34
34
35
35
36
36
@dataclass
37
- class _ParsedParamAnnotation :
37
+ class _ParsedParam :
38
+ name : Union [str , int ] = field (init = True )
38
39
orig_types : set [type ] = field (default_factory = set )
39
40
encoded_types : set [str ] = field (default_factory = set )
40
41
none_allowed : bool = False
@@ -54,7 +55,7 @@ class _ParsedReturnAnnotation:
54
55
@dataclass
55
56
class _ParsedSignature :
56
57
fn : Callable = None
57
- params : List [_ParsedParamAnnotation ] = field (default_factory = list )
58
+ params : List [_ParsedParam ] = field (default_factory = list )
58
59
ret_annotation : _ParsedReturnAnnotation = None
59
60
60
61
@property
@@ -93,22 +94,22 @@ def _encode_param_type(t: type) -> str:
93
94
return tc
94
95
95
96
96
- def _parse_param_annotation ( annotation : Any ) -> _ParsedParamAnnotation :
97
+ def _parse_param ( name : str , annotation : Any ) -> _ParsedParam :
97
98
""" Parse a parameter annotation in a function's signature """
98
- p_annotation = _ParsedParamAnnotation ( )
99
+ p_param = _ParsedParam ( name )
99
100
100
101
if annotation is inspect ._empty :
101
- p_annotation .encoded_types .add ("O" )
102
- p_annotation .none_allowed = True
102
+ p_param .encoded_types .add ("O" )
103
+ p_param .none_allowed = True
103
104
elif isinstance (annotation , _GenericAlias ) and annotation .__origin__ == Union :
104
105
for t in annotation .__args__ :
105
- _parse_type_no_nested (annotation , p_annotation , t )
106
+ _parse_type_no_nested (annotation , p_param , t )
106
107
else :
107
- _parse_type_no_nested (annotation , p_annotation , annotation )
108
- return p_annotation
108
+ _parse_type_no_nested (annotation , p_param , annotation )
109
+ return p_param
109
110
110
111
111
- def _parse_type_no_nested (annotation : Any , p_annotation : _ParsedParamAnnotation , t : Union [type , str ]) -> None :
112
+ def _parse_type_no_nested (annotation : Any , p_param : _ParsedParam , t : Union [type , str ]) -> None :
112
113
""" Parse a specific type (top level or nested in a top-level Union annotation) without handling nested types
113
114
(e.g. a nested Union). The result is stored in the given _ParsedAnnotation object.
114
115
"""
@@ -117,25 +118,25 @@ def _parse_type_no_nested(annotation: Any, p_annotation: _ParsedParamAnnotation,
117
118
# annotation is already a type, and we can remove this line.
118
119
t = eval (t ) if isinstance (t , str ) else t
119
120
120
- p_annotation .orig_types .add (t )
121
+ p_param .orig_types .add (t )
121
122
tc = _encode_param_type (t )
122
123
if "[" in tc :
123
- p_annotation .has_array = True
124
+ p_param .has_array = True
124
125
if tc in {"N" , "O" }:
125
- p_annotation .none_allowed = True
126
+ p_param .none_allowed = True
126
127
if tc in _NUMPY_INT_TYPE_CODES :
127
- if p_annotation .int_char and p_annotation .int_char != tc :
128
+ if p_param .int_char and p_param .int_char != tc :
128
129
raise DHError (message = f"multiple integer types in annotation: { annotation } , "
129
- f"types: { p_annotation .int_char } , { tc } . this is not supported because it is not "
130
+ f"types: { p_param .int_char } , { tc } . this is not supported because it is not "
130
131
f"clear which Deephaven null value to use when checking for nulls in the argument" )
131
- p_annotation .int_char = tc
132
+ p_param .int_char = tc
132
133
if tc in _NUMPY_FLOATING_TYPE_CODES :
133
- if p_annotation .floating_char and p_annotation .floating_char != tc :
134
+ if p_param .floating_char and p_param .floating_char != tc :
134
135
raise DHError (message = f"multiple floating types in annotation: { annotation } , "
135
- f"types: { p_annotation .floating_char } , { tc } . this is not supported because it is not "
136
+ f"types: { p_param .floating_char } , { tc } . this is not supported because it is not "
136
137
f"clear which Deephaven null value to use when checking for nulls in the argument" )
137
- p_annotation .floating_char = tc
138
- p_annotation .encoded_types .add (tc )
138
+ p_param .floating_char = tc
139
+ p_param .encoded_types .add (tc )
139
140
140
141
141
142
def _parse_return_annotation (annotation : Any ) -> _ParsedReturnAnnotation :
@@ -182,8 +183,8 @@ def _parse_numba_signature(fn: Union[numba.np.ufunc.gufunc.GUFunc, numba.np.ufun
182
183
p_sig .ret_annotation .encoded_type = rt_char
183
184
184
185
if isinstance (fn , numba .np .ufunc .dufunc .DUFunc ):
185
- for p in params :
186
- pa = _ParsedParamAnnotation ( )
186
+ for i , p in enumerate ( params ) :
187
+ pa = _ParsedParam ( i + 1 )
187
188
pa .encoded_types .add (p )
188
189
if p in _NUMPY_INT_TYPE_CODES :
189
190
pa .int_char = p
@@ -198,8 +199,8 @@ def _parse_numba_signature(fn: Union[numba.np.ufunc.gufunc.GUFunc, numba.np.ufun
198
199
input_decl = re .sub ("[()]" , "" , input_decl ).split ("," )
199
200
output_decl = re .sub ("[()]" , "" , output_decl )
200
201
201
- for p , d in zip (params , input_decl ):
202
- pa = _ParsedParamAnnotation ( )
202
+ for i , ( p , d ) in enumerate ( zip (params , input_decl ) ):
203
+ pa = _ParsedParam ( i + 1 )
203
204
if d :
204
205
pa .encoded_types .add ("[" + p )
205
206
pa .has_array = True
@@ -225,9 +226,10 @@ def _parse_np_ufunc_signature(fn: numpy.ufunc) -> _ParsedSignature:
225
226
# them in the future (https://github.com/deephaven/deephaven-core/issues/4762)
226
227
p_sig = _ParsedSignature (fn )
227
228
if fn .nin > 0 :
228
- pa = _ParsedParamAnnotation ()
229
- pa .encoded_types .add ("O" )
230
- p_sig .params = [pa ] * fn .nin
229
+ for i in range (fn .nin ):
230
+ pa = _ParsedParam (i + 1 )
231
+ pa .encoded_types .add ("O" )
232
+ p_sig .params .append (pa )
231
233
p_sig .ret_annotation = _ParsedReturnAnnotation ()
232
234
p_sig .ret_annotation .encoded_type = "O"
233
235
return p_sig
@@ -249,7 +251,7 @@ def _parse_signature(fn: Callable) -> _ParsedSignature:
249
251
else :
250
252
sig = inspect .signature (fn )
251
253
for n , p in sig .parameters .items ():
252
- p_sig .params .append (_parse_param_annotation ( p .annotation ))
254
+ p_sig .params .append (_parse_param ( n , p .annotation ))
253
255
254
256
p_sig .ret_annotation = _parse_return_annotation (sig .return_annotation )
255
257
return p_sig
@@ -263,11 +265,11 @@ def _is_from_np_type(param_types: set[type], np_type_char: str) -> bool:
263
265
return False
264
266
265
267
266
- def _convert_arg (param : _ParsedParamAnnotation , arg : Any ) -> Any :
268
+ def _convert_arg (param : _ParsedParam , arg : Any ) -> Any :
267
269
""" Convert a single argument to the type specified by the annotation """
268
270
if arg is None :
269
271
if not param .none_allowed :
270
- raise TypeError (f"Argument { arg } is not compatible with annotation { param .orig_types } " )
272
+ raise TypeError (f"Argument { param . name !r } : { arg } is not compatible with annotation { param .orig_types } " )
271
273
else :
272
274
return None
273
275
@@ -277,12 +279,17 @@ def _convert_arg(param: _ParsedParamAnnotation, arg: Any) -> Any:
277
279
# if it matches one of the encoded types, convert it
278
280
if encoded_type in param .encoded_types :
279
281
dtype = dtypes .from_np_dtype (np_dtype )
280
- return _j_array_to_numpy_array (dtype , arg , conv_null = True , type_promotion = False )
282
+ try :
283
+ return _j_array_to_numpy_array (dtype , arg , conv_null = True , type_promotion = False )
284
+ except Exception as e :
285
+ raise TypeError (f"Argument { param .name !r} : { arg } is not compatible with annotation"
286
+ f" { param .encoded_types } "
287
+ f"\n { str (e )} " ) from e
281
288
# if the annotation is missing, or it is a generic object type, return the arg
282
289
elif "O" in param .encoded_types :
283
290
return arg
284
291
else :
285
- raise TypeError (f"Argument { arg } is not compatible with annotation { param .encoded_types } " )
292
+ raise TypeError (f"Argument { param . name !r } : { arg } is not compatible with annotation { param .encoded_types } " )
286
293
else : # if the arg is not a Java array
287
294
specific_types = param .encoded_types - {"N" , "O" } # remove NoneType and object type
288
295
if specific_types :
@@ -300,7 +307,8 @@ def _convert_arg(param: _ParsedParamAnnotation, arg: Any) -> Any:
300
307
if param .none_allowed :
301
308
return None
302
309
else :
303
- raise DHError (f"Argument { arg } is not compatible with annotation { param .orig_types } " )
310
+ raise DHError (f"Argument { param .name !r} : { arg } is not compatible with annotation"
311
+ f" { param .orig_types } " )
304
312
else :
305
313
# return a numpy integer instance only if the annotation is a numpy type
306
314
if _is_from_np_type (param .orig_types , param .int_char ):
@@ -332,7 +340,8 @@ def _convert_arg(param: _ParsedParamAnnotation, arg: Any) -> Any:
332
340
if "O" in param .encoded_types :
333
341
return arg
334
342
else :
335
- raise TypeError (f"Argument { arg } is not compatible with annotation { param .orig_types } " )
343
+ raise TypeError (f"Argument { param .name !r} : { arg } is not compatible with annotation"
344
+ f" { param .orig_types } " )
336
345
else : # if no annotation or generic object, return arg
337
346
return arg
338
347
0 commit comments