from inspect import Parameter from jedi.cache import memoize_method from jedi import debug from jedi import parser_utils class _SignatureMixin: def to_string(self): def param_strings(): is_positional = False is_kw_only = False for n in self.get_param_names(resolve_stars=True): kind = n.get_kind() is_positional |= kind == Parameter.POSITIONAL_ONLY if is_positional and kind != Parameter.POSITIONAL_ONLY: yield '/' is_positional = False if kind == Parameter.VAR_POSITIONAL: is_kw_only = True elif kind == Parameter.KEYWORD_ONLY and not is_kw_only: yield '*' is_kw_only = True yield n.to_string() if is_positional: yield '/' s = self.name.string_name + '(' + ', '.join(param_strings()) + ')' annotation = self.annotation_string if annotation: s += ' -> ' + annotation return s class AbstractSignature(_SignatureMixin): def __init__(self, value, is_bound=False): self.value = value self.is_bound = is_bound @property def name(self): return self.value.name @property def annotation_string(self): return '' def get_param_names(self, resolve_stars=False): param_names = self._function_value.get_param_names() if self.is_bound: return param_names[1:] return param_names def bind(self, value): raise NotImplementedError def matches_signature(self, arguments): return True def __repr__(self): if self.value is self._function_value: return '<%s: %s>' % (self.__class__.__name__, self.value) return '<%s: %s, %s>' % (self.__class__.__name__, self.value, self._function_value) class TreeSignature(AbstractSignature): def __init__(self, value, function_value=None, is_bound=False): super().__init__(value, is_bound) self._function_value = function_value or value def bind(self, value): return TreeSignature(value, self._function_value, is_bound=True) @property def _annotation(self): # Classes don't need annotations, even if __init__ has one. They always # return themselves. if self.value.is_class(): return None return self._function_value.tree_node.annotation @property def annotation_string(self): a = self._annotation if a is None: return '' return a.get_code(include_prefix=False) @memoize_method def get_param_names(self, resolve_stars=False): params = self._function_value.get_param_names() if resolve_stars: from jedi.inference.star_args import process_params params = process_params(params) if self.is_bound: return params[1:] return params def matches_signature(self, arguments): from jedi.inference.param import get_executed_param_names_and_issues executed_param_names, issues = \ get_executed_param_names_and_issues(self._function_value, arguments) if issues: return False matches = all(executed_param_name.matches_signature() for executed_param_name in executed_param_names) if debug.enable_notice: tree_node = self._function_value.tree_node signature = parser_utils.get_signature(tree_node) if matches: debug.dbg("Overloading match: %s@%s (%s)", signature, tree_node.start_pos[0], arguments, color='BLUE') else: debug.dbg("Overloading no match: %s@%s (%s)", signature, tree_node.start_pos[0], arguments, color='BLUE') return matches class BuiltinSignature(AbstractSignature): def __init__(self, value, return_string, function_value=None, is_bound=False): super().__init__(value, is_bound) self._return_string = return_string self.__function_value = function_value @property def annotation_string(self): return self._return_string @property def _function_value(self): if self.__function_value is None: return self.value return self.__function_value def bind(self, value): return BuiltinSignature( value, self._return_string, function_value=self.value, is_bound=True ) class SignatureWrapper(_SignatureMixin): def __init__(self, wrapped_signature): self._wrapped_signature = wrapped_signature def __getattr__(self, name): return getattr(self._wrapped_signature, name)