1+ import asyncio
12import functools
23
34from typing import Callable , Optional
45
6+ import aiohttp
7+
58from urllib3 .exceptions import HTTPError
69
710from polyaxon import settings
1114from polyaxon .logger import logger
1215
1316
17+ def _check_global_or_inline_config (args , config_key ) -> Optional [bool ]:
18+ self_arg = args [0 ] if args else None
19+ config_value = getattr (self_arg , f"_{ config_key } " , None )
20+ return get_global_or_inline_config (
21+ config_key = config_key ,
22+ config_value = config_value ,
23+ client = getattr (self_arg , "_client" , None ),
24+ )
25+
26+
27+ def _should_skip_client_call (
28+ args ,
29+ check_no_op : bool ,
30+ check_offline : bool ,
31+ ) -> bool :
32+ if check_no_op and _check_global_or_inline_config (args , "no_op" ):
33+ logger .debug ("Using NO_OP mode" )
34+ return True
35+ if check_offline and _check_global_or_inline_config (args , "is_offline" ):
36+ logger .debug ("Using IS_OFFLINE mode" )
37+ return True
38+ return False
39+
40+
41+ def _warn_missing_loggers (
42+ self_arg ,
43+ f : Callable ,
44+ can_log_events : bool ,
45+ can_log_outputs : bool ,
46+ ):
47+ if can_log_events and (
48+ not hasattr (self_arg , "_event_logger" )
49+ or self_arg ._event_logger is None # pylint:disable=protected-access
50+ ):
51+ logger .warning (
52+ "You should set an event logger before calling: {}" .format (f .__name__ )
53+ )
54+
55+ if can_log_outputs and (
56+ not hasattr (self_arg , "_outputs_path" )
57+ or self_arg ._outputs_path is None # pylint:disable=protected-access
58+ ):
59+ logger .warning (
60+ "You should set an an outputs path before calling: {}" .format (f .__name__ )
61+ )
62+
63+
64+ def _prepare_client_call (
65+ args ,
66+ f : Callable ,
67+ check_no_op : bool ,
68+ check_offline : bool ,
69+ can_log_events : bool ,
70+ can_log_outputs : bool ,
71+ ):
72+ if _should_skip_client_call (args , check_no_op , check_offline ):
73+ return True , False
74+
75+ manual_exceptions_handling = False
76+ if args :
77+ self_arg = args [0 ]
78+ manual_exceptions_handling = getattr (
79+ self_arg , "_manual_exceptions_handling" , False
80+ )
81+ _warn_missing_loggers (
82+ self_arg = self_arg ,
83+ f = f ,
84+ can_log_events = can_log_events ,
85+ can_log_outputs = can_log_outputs ,
86+ )
87+
88+ return False , manual_exceptions_handling
89+
90+
91+ def _get_client_error_message (f : Callable ) -> str :
92+ return (
93+ "\n API Client failed at the function `%(name)s` in file "
94+ "`%(filename)s` line number `%(line)s`."
95+ "\n Client config:\n %(config)s\n "
96+ % {
97+ "name" : f .__name__ ,
98+ "filename" : f .__code__ .co_filename ,
99+ "line" : f .__code__ .co_firstlineno + 1 ,
100+ "config" : settings .CLIENT_CONFIG .to_dict (),
101+ }
102+ )
103+
104+
105+ def _handle_client_exception (
106+ f : Callable ,
107+ e : Exception ,
108+ manual_exceptions_handling : bool ,
109+ ):
110+ handle_client_error (
111+ e = None if manual_exceptions_handling else e ,
112+ message = _get_client_error_message (f ),
113+ )
114+
115+
14116def client_handler (
15117 check_no_op : bool = True ,
16118 check_offline : bool = False ,
@@ -41,68 +143,27 @@ def my_func(arg1, arg2):
41143 return ...
42144 """
43145
44- def _check_global_or_inline_config (args , config_key ) -> Optional [bool ]:
45- self_arg = args [0 ] if args else None
46- config_value = getattr (self_arg , f"_{ config_key } " , None )
47- return get_global_or_inline_config (
48- config_key = config_key ,
49- config_value = config_value ,
50- client = getattr (self_arg , "_client" , None ),
51- )
52-
53146 def client_handler_wrapper (f : Callable ) -> Callable :
54147 @functools .wraps (f )
55148 def wrapper (* args , ** kwargs ):
56- if check_no_op and _check_global_or_inline_config (args , "no_op" ):
57- logger .debug ("Using NO_OP mode" )
149+ skip_call , manual_exceptions_handling = _prepare_client_call (
150+ args = args ,
151+ f = f ,
152+ check_no_op = check_no_op ,
153+ check_offline = check_offline ,
154+ can_log_events = can_log_events ,
155+ can_log_outputs = can_log_outputs ,
156+ )
157+ if skip_call :
58158 return None
59- if check_offline and _check_global_or_inline_config (args , "is_offline" ):
60- logger .debug ("Using IS_OFFLINE mode" )
61- return None
62- manual_exceptions_handling = False
63- if args :
64- self_arg = args [0 ]
65-
66- manual_exceptions_handling = getattr (
67- self_arg , "_manual_exceptions_handling" , False
68- )
69-
70- if can_log_events and (
71- not hasattr (self_arg , "_event_logger" )
72- or self_arg ._event_logger is None # pylint:disable=protected-access
73- ):
74- logger .warning (
75- "You should set an event logger before calling: {}" .format (
76- f .__name__
77- )
78- )
79-
80- if can_log_outputs and (
81- not hasattr (self_arg , "_outputs_path" )
82- or self_arg ._outputs_path is None # pylint:disable=protected-access
83- ):
84- logger .warning (
85- "You should set an an outputs path before calling: {}" .format (
86- f .__name__
87- )
88- )
89159
90160 try :
91161 return f (* args , ** kwargs )
92162 except (ApiException , HTTPError ) as e :
93- message = (
94- "\n API Client failed at the function `%(name)s` in file "
95- "`%(filename)s` line number `%(line)s`."
96- "\n Client config:\n %(config)s\n "
97- % {
98- "name" : f .__name__ ,
99- "filename" : f .__code__ .co_filename ,
100- "line" : f .__code__ .co_firstlineno + 1 ,
101- "config" : settings .CLIENT_CONFIG .to_dict (),
102- }
103- )
104- handle_client_error (
105- e = None if manual_exceptions_handling else e , message = message
163+ _handle_client_exception (
164+ f = f ,
165+ e = e ,
166+ manual_exceptions_handling = manual_exceptions_handling ,
106167 )
107168 raise e
108169
@@ -111,6 +172,41 @@ def wrapper(*args, **kwargs):
111172 return client_handler_wrapper
112173
113174
175+ def async_client_handler (
176+ check_no_op : bool = True ,
177+ check_offline : bool = False ,
178+ can_log_events : bool = False ,
179+ can_log_outputs : bool = False ,
180+ ) -> Callable :
181+ def async_client_handler_wrapper (f : Callable ) -> Callable :
182+ @functools .wraps (f )
183+ async def wrapper (* args , ** kwargs ):
184+ skip_call , manual_exceptions_handling = _prepare_client_call (
185+ args = args ,
186+ f = f ,
187+ check_no_op = check_no_op ,
188+ check_offline = check_offline ,
189+ can_log_events = can_log_events ,
190+ can_log_outputs = can_log_outputs ,
191+ )
192+ if skip_call :
193+ return None
194+
195+ try :
196+ return await f (* args , ** kwargs )
197+ except (ApiException , aiohttp .ClientError , asyncio .TimeoutError ) as e :
198+ _handle_client_exception (
199+ f = f ,
200+ e = e ,
201+ manual_exceptions_handling = manual_exceptions_handling ,
202+ )
203+ raise e
204+
205+ return wrapper
206+
207+ return async_client_handler_wrapper
208+
209+
114210def get_global_or_inline_config (
115211 config_key : str ,
116212 config_value : Optional [bool ] = None ,
0 commit comments