2525)
2626from ._optionals import get_annotated_base_type , is_annotated , is_pydantic_model , parse_docs
2727from ._postponed_annotations import evaluate_postponed_annotations
28- from ._stubs_resolver import get_stub_types
28+ from ._stubs_resolver import get_arg_type , get_stub_types , get_stubs_resolver
2929from ._util import (
3030 ClassFromFunctionBase ,
3131 get_import_path ,
@@ -500,7 +500,10 @@ def get_component_and_parent(
500500 method_or_property = method_or_property .__name__
501501 parent = component = None
502502 if method_or_property :
503- attr = inspect .getattr_static (get_generic_origin (function_or_class ), method_or_property )
503+ try :
504+ attr = inspect .getattr_static (get_generic_origin (function_or_class ), method_or_property )
505+ except AttributeError as ex :
506+ raise AttributeError (f"Attribute '{ method_or_property } ' not found in { function_or_class } " ) from ex
504507 if is_staticmethod (attr ):
505508 component = getattr (function_or_class , method_or_property )
506509 return component , parent , method_or_property
@@ -880,26 +883,6 @@ def get_parameters(self) -> ParamList:
880883 return params
881884
882885
883- def get_parameters_by_assumptions (
884- function_or_class : Union [Callable , Type ],
885- method_name : Optional [str ] = None ,
886- logger : Union [bool , str , dict , logging .Logger ] = True ,
887- ) -> ParamList :
888- component , parent , method_name = get_component_and_parent (function_or_class , method_name )
889- params , args_idx , kwargs_idx , _ , stubs = get_signature_parameters_and_indexes (component , parent , logger )
890-
891- if parent and (args_idx >= 0 or kwargs_idx >= 0 ):
892- with mro_context (parent ):
893- subparams = get_mro_parameters (method_name , get_parameters_by_assumptions , logger )
894- if subparams :
895- args , kwargs = split_args_and_kwargs (subparams )
896- params = replace_args_and_kwargs (params , args , kwargs )
897-
898- params = replace_args_and_kwargs (params , [], [])
899- add_stub_types (stubs , params , component )
900- return params
901-
902-
903886def get_field_data_pydantic1_model (field , name , doc_params ):
904887 default = field .default
905888 if field .required :
@@ -997,6 +980,7 @@ def get_parameters_from_pydantic_or_attrs(
997980
998981 if method_or_property or not (pydantic_support or attrs_support ):
999982 return None
983+
1000984 function_or_class = get_unaliased_type (function_or_class )
1001985 fields_iterator = get_field_data = None
1002986 if pydantic_support :
@@ -1039,6 +1023,71 @@ def get_parameters_from_pydantic_or_attrs(
10391023 )
10401024 )
10411025 evaluate_postponed_annotations (params , function_or_class , None , logger )
1026+
1027+ return params
1028+
1029+
1030+ def get_parameters_from_ast (
1031+ function_or_class : Union [Callable , Type ],
1032+ method_or_property : Optional [str ],
1033+ logger : logging .Logger ,
1034+ ) -> Optional [ParamList ]:
1035+ visitor = ParametersVisitor (function_or_class , method_or_property , logger = logger )
1036+ return visitor .get_parameters ()
1037+
1038+
1039+ def get_parameters_from_stubs (
1040+ function_or_class : Union [Callable , Type ],
1041+ method_or_property : Optional [str ],
1042+ logger : logging .Logger ,
1043+ ) -> Optional [ParamList ]:
1044+ component , parent , _ = get_component_and_parent (function_or_class , method_or_property )
1045+ params = None
1046+ resolver = get_stubs_resolver ()
1047+ stub_import = resolver .get_component_imported_info (component , parent )
1048+ if stub_import :
1049+ origin = get_parameter_origins (component , parent )
1050+ aliases = resolver .get_aliases (stub_import )
1051+ arg_asts = stub_import .info .ast .args .args + stub_import .info .ast .args .kwonlyargs
1052+ params = []
1053+ for num , arg_ast in enumerate (arg_asts ):
1054+ if parent and num == 0 :
1055+ continue
1056+ try :
1057+ annotation = get_arg_type (arg_ast .annotation , aliases )
1058+ except Exception :
1059+ annotation = inspect ._empty
1060+ params .append (
1061+ ParamData (
1062+ name = arg_ast .arg ,
1063+ annotation = annotation ,
1064+ default = UnknownDefault ("stubs-resolver" ),
1065+ kind = inspect ._ParameterKind .KEYWORD_ONLY ,
1066+ component = component ,
1067+ parent = parent ,
1068+ origin = origin ,
1069+ )
1070+ )
1071+ return params
1072+
1073+
1074+ def get_parameters_by_assumptions (
1075+ function_or_class : Union [Callable , Type ],
1076+ method_name : Optional [str ],
1077+ logger : logging .Logger ,
1078+ ) -> ParamList :
1079+ component , parent , method_name = get_component_and_parent (function_or_class , method_name )
1080+ params , args_idx , kwargs_idx , _ , stubs = get_signature_parameters_and_indexes (component , parent , logger )
1081+
1082+ if parent and (args_idx >= 0 or kwargs_idx >= 0 ):
1083+ with mro_context (parent ):
1084+ subparams = get_mro_parameters (method_name , get_parameters_by_assumptions , logger )
1085+ if subparams :
1086+ args , kwargs = split_args_and_kwargs (subparams )
1087+ params = replace_args_and_kwargs (params , args , kwargs )
1088+
1089+ params = replace_args_and_kwargs (params , [], [])
1090+ add_stub_types (stubs , params , component )
10421091 return params
10431092
10441093
@@ -1047,7 +1096,7 @@ def get_signature_parameters(
10471096 method_or_property : Optional [str ] = None ,
10481097 logger : Union [bool , str , dict , logging .Logger ] = True ,
10491098) -> ParamList :
1050- """Get parameters by inspecting ASTs or by inheritance assumptions if source not available .
1099+ """Get parameters by inspecting ASTs, stubs or by inheritance assumptions.
10511100
10521101 In contrast to inspect.signature, it follows the use of *args and **kwargs
10531102 attempting to find all accepted named parameters.
@@ -1060,22 +1109,26 @@ def get_signature_parameters(
10601109 the parameters for ``__init__``.
10611110 logger: Useful for debugging. Only logs at ``DEBUG`` level.
10621111 """
1112+ get_component_and_parent (function_or_class , method_or_property ) # verify input
10631113 logger = parse_logger (logger , "get_signature_parameters" )
1064- try :
1065- params = get_parameters_from_pydantic_or_attrs (function_or_class , method_or_property , logger )
1114+ params = None
1115+ for get_parameters in [
1116+ get_parameters_from_pydantic_or_attrs ,
1117+ get_parameters_from_ast ,
1118+ get_parameters_from_stubs ,
1119+ get_parameters_by_assumptions ,
1120+ ]:
1121+ try :
1122+ params = get_parameters (function_or_class , method_or_property , logger )
1123+ except Exception as ex :
1124+ logger .debug (
1125+ "%s failed: function_or_class=%s, method_or_property=%s: %s" ,
1126+ get_parameters .__name__ ,
1127+ function_or_class ,
1128+ method_or_property ,
1129+ ex ,
1130+ exc_info = ex ,
1131+ )
10661132 if params is not None :
1067- return params
1068- visitor = ParametersVisitor (function_or_class , method_or_property , logger = logger )
1069- return visitor .get_parameters ()
1070- except Exception as ex :
1071- cause = "Source not available"
1072- exc_info = None
1073- if not isinstance (ex , SourceNotAvailable ):
1074- cause = "Problems with AST resolving"
1075- exc_info = ex
1076- logger .debug (
1077- f"{ cause } , falling back to parameters by assumptions: function_or_class={ function_or_class } "
1078- f"method_or_property={ method_or_property } : { ex } " ,
1079- exc_info = exc_info ,
1080- )
1081- return get_parameters_by_assumptions (function_or_class , method_or_property , logger )
1133+ break
1134+ return params or []
0 commit comments