1from inspect import Parameter
2from typing import Any
3
4from jedi.cache import memoize_method
5from jedi import debug
6from jedi import parser_utils
7
8
9class _SignatureMixin:
10 get_param_names: Any
11 name: Any
12 annotation_string: Any
13
14 def to_string(self):
15 def param_strings():
16 is_positional = False
17 is_kw_only = False
18 for n in self.get_param_names(resolve_stars=True):
19 kind = n.get_kind()
20 is_positional |= kind == Parameter.POSITIONAL_ONLY
21 if is_positional and kind != Parameter.POSITIONAL_ONLY:
22 yield '/'
23 is_positional = False
24
25 if kind == Parameter.VAR_POSITIONAL:
26 is_kw_only = True
27 elif kind == Parameter.KEYWORD_ONLY and not is_kw_only:
28 yield '*'
29 is_kw_only = True
30
31 yield n.to_string()
32
33 if is_positional:
34 yield '/'
35
36 s = self.name.string_name + '(' + ', '.join(param_strings()) + ')'
37 annotation = self.annotation_string
38 if annotation:
39 s += ' -> ' + annotation
40 return s
41
42
43class AbstractSignature(_SignatureMixin):
44 _function_value: Any
45
46 def __init__(self, value, is_bound=False):
47 self.value = value
48 self.is_bound = is_bound
49
50 @property
51 def name(self):
52 return self.value.name
53
54 @property
55 def annotation_string(self):
56 return ''
57
58 def get_param_names(self, resolve_stars=False):
59 param_names = self._function_value.get_param_names()
60 if self.is_bound:
61 return param_names[1:]
62 return param_names
63
64 def bind(self, value):
65 raise NotImplementedError
66
67 def matches_signature(self, arguments):
68 return True
69
70 def __repr__(self):
71 if self.value is self._function_value:
72 return '<%s: %s>' % (self.__class__.__name__, self.value)
73 return '<%s: %s, %s>' % (self.__class__.__name__, self.value, self._function_value)
74
75
76class TreeSignature(AbstractSignature):
77 def __init__(self, value, function_value=None, is_bound=False):
78 super().__init__(value, is_bound)
79 self._function_value = function_value or value
80
81 def bind(self, value):
82 return TreeSignature(value, self._function_value, is_bound=True)
83
84 @property
85 def _annotation(self):
86 # Classes don't need annotations, even if __init__ has one. They always
87 # return themselves.
88 if self.value.is_class():
89 return None
90 return self._function_value.tree_node.annotation
91
92 @property
93 def annotation_string(self):
94 a = self._annotation
95 if a is None:
96 return ''
97 return a.get_code(include_prefix=False)
98
99 @memoize_method
100 def get_param_names(self, resolve_stars=False):
101 params = self._function_value.get_param_names()
102 if resolve_stars:
103 from jedi.inference.star_args import process_params
104 params = process_params(params)
105 if self.is_bound:
106 return params[1:]
107 return params
108
109 def matches_signature(self, arguments):
110 from jedi.inference.param import get_executed_param_names_and_issues
111 executed_param_names, issues = \
112 get_executed_param_names_and_issues(self._function_value, arguments)
113 if issues:
114 return False
115
116 matches = all(executed_param_name.matches_signature()
117 for executed_param_name in executed_param_names)
118 if debug.enable_notice:
119 tree_node = self._function_value.tree_node
120 signature = parser_utils.get_signature(tree_node)
121 if matches:
122 debug.dbg("Overloading match: %s@%s (%s)",
123 signature, tree_node.start_pos[0], arguments, color='BLUE')
124 else:
125 debug.dbg("Overloading no match: %s@%s (%s)",
126 signature, tree_node.start_pos[0], arguments, color='BLUE')
127 return matches
128
129
130class BuiltinSignature(AbstractSignature):
131 def __init__(self, value, return_string, function_value=None, is_bound=False):
132 super().__init__(value, is_bound)
133 self._return_string = return_string
134 self.__function_value = function_value
135
136 @property
137 def annotation_string(self):
138 return self._return_string
139
140 @property
141 def _function_value(self):
142 if self.__function_value is None:
143 return self.value
144 return self.__function_value
145
146 def bind(self, value):
147 return BuiltinSignature(
148 value, self._return_string,
149 function_value=self.value,
150 is_bound=True
151 )
152
153
154class SignatureWrapper(_SignatureMixin):
155 def __init__(self, wrapped_signature):
156 self._wrapped_signature = wrapped_signature
157
158 def __getattr__(self, name):
159 return getattr(self._wrapped_signature, name)