@@ -340,7 +340,6 @@ def get_local_defns(
340340 ],
341341]:
342342 from typemap .typing import GenericCallable , Overloaded
343- from ._eval_operators import _function_type , _function_type_from_sig
344343
345344 annos : dict [str , Any ] = {}
346345 dct : dict [str , Any ] = {}
@@ -381,8 +380,6 @@ def get_local_defns(
381380 definition_cls = boxed .canonical_cls
382381
383382 def _make_lambda (fn , o , sa , tp , recv_cls , def_cls ):
384- from ._eval_operators import _function_type_from_sig
385-
386383 def lam (* vs ):
387384 args = dict (sa )
388385 args .update (
@@ -440,6 +437,110 @@ def lam(*vs):
440437 return annos , dct
441438
442439
440+ def _function_type_from_sig (sig , func_type , * , receiver_type ):
441+ from typemap .typing import Param
442+
443+ empty = inspect .Parameter .empty
444+
445+ def _ann (x ):
446+ return typing .Any if x is empty else None if x is type (None ) else x
447+
448+ specified_receiver = receiver_type
449+
450+ params = []
451+ for i , p in enumerate (sig .parameters .values ()):
452+ ann = p .annotation
453+ # Special handling for first argument on methods.
454+ if i == 0 and receiver_type and func_type is not staticmethod :
455+ if ann is empty :
456+ ann = receiver_type
457+ else :
458+ if (
459+ func_type is classmethod
460+ and typing .get_origin (ann ) is type
461+ and (receiver_args := typing .get_args (ann ))
462+ ):
463+ # The annotation for cls in a classmethod should be type[C]
464+ specified_receiver = receiver_args [0 ]
465+ else :
466+ specified_receiver = ann
467+
468+ quals = []
469+ if p .kind == inspect .Parameter .VAR_POSITIONAL :
470+ quals .append ("*" )
471+ if p .kind == inspect .Parameter .VAR_KEYWORD :
472+ quals .append ("**" )
473+ if p .kind == inspect .Parameter .KEYWORD_ONLY :
474+ quals .append ("keyword" )
475+ if p .kind == inspect .Parameter .POSITIONAL_ONLY :
476+ quals .append ("positional" )
477+ if p .default is not empty :
478+ quals .append ("default" )
479+ params .append (
480+ Param [
481+ typing .Literal [p .name ],
482+ _ann (ann ),
483+ typing .Literal [* quals ] if quals else typing .Never ,
484+ ]
485+ )
486+
487+ ret = _ann (sig .return_annotation )
488+
489+ # TODO: Is doing the tuple for staticmethod/classmethod legit?
490+ # Putting a list in makes it unhashable...
491+ f : typing .Any # type: ignore[annotation-unchecked]
492+ if func_type is staticmethod :
493+ f = staticmethod [tuple [* params ], ret ]
494+ elif func_type is classmethod :
495+ f = classmethod [specified_receiver , tuple [* params [1 :]], ret ]
496+ else :
497+ f = typing .Callable [params , ret ]
498+
499+ return f
500+
501+
502+ def _function_type (
503+ func , * , receiver_type
504+ ) -> type [typing .Callable | classmethod | staticmethod | GenericCallable ]:
505+ from typemap .typing import GenericCallable
506+
507+ root = inspect .unwrap (func )
508+ sig = inspect .signature (root )
509+ f = _function_type_from_sig (sig , type (func ), receiver_type = receiver_type )
510+
511+ if root .__type_params__ :
512+ # Must store a lambda that performs type variable substitution
513+ type_params = root .__type_params__
514+ callable_lambda = _create_generic_callable_lambda (f , type_params )
515+ f = GenericCallable [tuple [* type_params ], callable_lambda ] # type: ignore[misc,valid-type]
516+ return f
517+
518+
519+ def _create_generic_callable_lambda (
520+ f : typing .Callable | classmethod | staticmethod ,
521+ type_params : tuple [typing .TypeVar , ...],
522+ ):
523+ if typing .get_origin (f ) in (staticmethod , classmethod ):
524+ return lambda * vs : substitute (
525+ f , dict (zip (type_params , vs , strict = True ))
526+ )
527+
528+ else :
529+ # Callable params are stored as a list
530+ params , ret = typing .get_args (f )
531+
532+ return lambda * vs : typing .Callable [
533+ [
534+ substitute (
535+ p ,
536+ dict (zip (type_params , vs , strict = True )),
537+ )
538+ for p in params
539+ ],
540+ substitute (ret , dict (zip (type_params , vs , strict = True ))),
541+ ]
542+
543+
443544def flatten_class_new_proto (cls : type ) -> type :
444545 # This is a hacky version of flatten_class that works by using
445546 # NewProtocol on Members!
0 commit comments