@@ -316,7 +316,6 @@ def get_local_defns(
316316 ],
317317]:
318318 from typemap .typing import GenericCallable , Overloaded
319- from ._eval_operators import _function_type , _function_type_from_sig
320319
321320 annos : dict [str , Any ] = {}
322321 dct : dict [str , Any ] = {}
@@ -357,8 +356,6 @@ def get_local_defns(
357356 definition_cls = boxed .canonical_cls
358357
359358 def _make_lambda (fn , o , sa , tp , recv_cls , def_cls ):
360- from ._eval_operators import _function_type_from_sig
361-
362359 def lam (* vs ):
363360 args = dict (sa )
364361 args .update (
@@ -416,6 +413,110 @@ def lam(*vs):
416413 return annos , dct
417414
418415
416+ def _function_type_from_sig (sig , func_type , * , receiver_type ):
417+ from typemap .typing import Param
418+
419+ empty = inspect .Parameter .empty
420+
421+ def _ann (x ):
422+ return typing .Any if x is empty else None if x is type (None ) else x
423+
424+ specified_receiver = receiver_type
425+
426+ params = []
427+ for i , p in enumerate (sig .parameters .values ()):
428+ ann = p .annotation
429+ # Special handling for first argument on methods.
430+ if i == 0 and receiver_type and func_type is not staticmethod :
431+ if ann is empty :
432+ ann = receiver_type
433+ else :
434+ if (
435+ func_type is classmethod
436+ and typing .get_origin (ann ) is type
437+ and (receiver_args := typing .get_args (ann ))
438+ ):
439+ # The annotation for cls in a classmethod should be type[C]
440+ specified_receiver = receiver_args [0 ]
441+ else :
442+ specified_receiver = ann
443+
444+ quals = []
445+ if p .kind == inspect .Parameter .VAR_POSITIONAL :
446+ quals .append ("*" )
447+ if p .kind == inspect .Parameter .VAR_KEYWORD :
448+ quals .append ("**" )
449+ if p .kind == inspect .Parameter .KEYWORD_ONLY :
450+ quals .append ("keyword" )
451+ if p .kind == inspect .Parameter .POSITIONAL_ONLY :
452+ quals .append ("positional" )
453+ if p .default is not empty :
454+ quals .append ("default" )
455+ params .append (
456+ Param [
457+ typing .Literal [p .name ],
458+ _ann (ann ),
459+ typing .Literal [* quals ] if quals else typing .Never ,
460+ ]
461+ )
462+
463+ ret = _ann (sig .return_annotation )
464+
465+ # TODO: Is doing the tuple for staticmethod/classmethod legit?
466+ # Putting a list in makes it unhashable...
467+ f : typing .Any # type: ignore[annotation-unchecked]
468+ if func_type is staticmethod :
469+ f = staticmethod [tuple [* params ], ret ]
470+ elif func_type is classmethod :
471+ f = classmethod [specified_receiver , tuple [* params [1 :]], ret ]
472+ else :
473+ f = typing .Callable [params , ret ]
474+
475+ return f
476+
477+
478+ def _function_type (
479+ func , * , receiver_type
480+ ) -> type [typing .Callable | classmethod | staticmethod | GenericCallable ]:
481+ from typemap .typing import GenericCallable
482+
483+ root = inspect .unwrap (func )
484+ sig = inspect .signature (root )
485+ f = _function_type_from_sig (sig , type (func ), receiver_type = receiver_type )
486+
487+ if root .__type_params__ :
488+ # Must store a lambda that performs type variable substitution
489+ type_params = root .__type_params__
490+ callable_lambda = _create_generic_callable_lambda (f , type_params )
491+ f = GenericCallable [tuple [* type_params ], callable_lambda ] # type: ignore[misc,valid-type]
492+ return f
493+
494+
495+ def _create_generic_callable_lambda (
496+ f : typing .Callable | classmethod | staticmethod ,
497+ type_params : tuple [typing .TypeVar , ...],
498+ ):
499+ if typing .get_origin (f ) in (staticmethod , classmethod ):
500+ return lambda * vs : substitute (
501+ f , dict (zip (type_params , vs , strict = True ))
502+ )
503+
504+ else :
505+ # Callable params are stored as a list
506+ params , ret = typing .get_args (f )
507+
508+ return lambda * vs : typing .Callable [
509+ [
510+ substitute (
511+ p ,
512+ dict (zip (type_params , vs , strict = True )),
513+ )
514+ for p in params
515+ ],
516+ substitute (ret , dict (zip (type_params , vs , strict = True ))),
517+ ]
518+
519+
419520def flatten_class_new_proto (cls : type ) -> type :
420521 # This is a hacky version of flatten_class that works by using
421522 # NewProtocol on Members!
0 commit comments