]> crepu.dev Git - config.git/blob - djavu-asus/emacs/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/param.py
Reorganización de directorios
[config.git] / djavu-asus / emacs / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / inference / param.py
1 from collections import defaultdict
2 from inspect import Parameter
3
4 from jedi import debug
5 from jedi.inference.utils import PushBackIterator
6 from jedi.inference import analysis
7 from jedi.inference.lazy_value import LazyKnownValue, \
8 LazyTreeValue, LazyUnknownValue
9 from jedi.inference.value import iterable
10 from jedi.inference.names import ParamName
11
12
13 def _add_argument_issue(error_name, lazy_value, message):
14 if isinstance(lazy_value, LazyTreeValue):
15 node = lazy_value.data
16 if node.parent.type == 'argument':
17 node = node.parent
18 return analysis.add(lazy_value.context, error_name, node, message)
19
20
21 class ExecutedParamName(ParamName):
22 def __init__(self, function_value, arguments, param_node, lazy_value, is_default=False):
23 super().__init__(function_value, param_node.name, arguments=arguments)
24 self._lazy_value = lazy_value
25 self._is_default = is_default
26
27 def infer(self):
28 return self._lazy_value.infer()
29
30 def matches_signature(self):
31 if self._is_default:
32 return True
33 argument_values = self.infer().py__class__()
34 if self.get_kind() in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD):
35 return True
36 annotations = self.infer_annotation(execute_annotation=False)
37 if not annotations:
38 # If we cannot infer annotations - or there aren't any - pretend
39 # that the signature matches.
40 return True
41 matches = any(c1.is_sub_class_of(c2)
42 for c1 in argument_values
43 for c2 in annotations.gather_annotation_classes())
44 debug.dbg("param compare %s: %s <=> %s",
45 matches, argument_values, annotations, color='BLUE')
46 return matches
47
48 def __repr__(self):
49 return '<%s: %s>' % (self.__class__.__name__, self.string_name)
50
51
52 def get_executed_param_names_and_issues(function_value, arguments):
53 """
54 Return a tuple of:
55 - a list of `ExecutedParamName`s corresponding to the arguments of the
56 function execution `function_value`, containing the inferred value of
57 those arguments (whether explicit or default)
58 - a list of the issues encountered while building that list
59
60 For example, given:
61 ```
62 def foo(a, b, c=None, d='d'): ...
63
64 foo(42, c='c')
65 ```
66
67 Then for the execution of `foo`, this will return a tuple containing:
68 - a list with entries for each parameter a, b, c & d; the entries for a,
69 c, & d will have their values (42, 'c' and 'd' respectively) included.
70 - a list with a single entry about the lack of a value for `b`
71 """
72 def too_many_args(argument):
73 m = _error_argument_count(funcdef, len(unpacked_va))
74 # Just report an error for the first param that is not needed (like
75 # cPython).
76 if arguments.get_calling_nodes():
77 # There might not be a valid calling node so check for that first.
78 issues.append(
79 _add_argument_issue(
80 'type-error-too-many-arguments',
81 argument,
82 message=m
83 )
84 )
85 else:
86 issues.append(None)
87 debug.warning('non-public warning: %s', m)
88
89 issues = [] # List[Optional[analysis issue]]
90 result_params = []
91 param_dict = {}
92 funcdef = function_value.tree_node
93 # Default params are part of the value where the function was defined.
94 # This means that they might have access on class variables that the
95 # function itself doesn't have.
96 default_param_context = function_value.get_default_param_context()
97
98 for param in funcdef.get_params():
99 param_dict[param.name.value] = param
100 unpacked_va = list(arguments.unpack(funcdef))
101 var_arg_iterator = PushBackIterator(iter(unpacked_va))
102
103 non_matching_keys = defaultdict(lambda: [])
104 keys_used = {}
105 keys_only = False
106 had_multiple_value_error = False
107 for param in funcdef.get_params():
108 # The value and key can both be null. There, the defaults apply.
109 # args / kwargs will just be empty arrays / dicts, respectively.
110 # Wrong value count is just ignored. If you try to test cases that are
111 # not allowed in Python, Jedi will maybe not show any completions.
112 is_default = False
113 key, argument = next(var_arg_iterator, (None, None))
114 while key is not None:
115 keys_only = True
116 try:
117 key_param = param_dict[key]
118 except KeyError:
119 non_matching_keys[key] = argument
120 else:
121 if key in keys_used:
122 had_multiple_value_error = True
123 m = ("TypeError: %s() got multiple values for keyword argument '%s'."
124 % (funcdef.name, key))
125 for contextualized_node in arguments.get_calling_nodes():
126 issues.append(
127 analysis.add(contextualized_node.context,
128 'type-error-multiple-values',
129 contextualized_node.node, message=m)
130 )
131 else:
132 keys_used[key] = ExecutedParamName(
133 function_value, arguments, key_param, argument)
134 key, argument = next(var_arg_iterator, (None, None))
135
136 try:
137 result_params.append(keys_used[param.name.value])
138 continue
139 except KeyError:
140 pass
141
142 if param.star_count == 1:
143 # *args param
144 lazy_value_list = []
145 if argument is not None:
146 lazy_value_list.append(argument)
147 for key, argument in var_arg_iterator:
148 # Iterate until a key argument is found.
149 if key:
150 var_arg_iterator.push_back((key, argument))
151 break
152 lazy_value_list.append(argument)
153 seq = iterable.FakeTuple(function_value.inference_state, lazy_value_list)
154 result_arg = LazyKnownValue(seq)
155 elif param.star_count == 2:
156 if argument is not None:
157 too_many_args(argument)
158 # **kwargs param
159 dct = iterable.FakeDict(function_value.inference_state, dict(non_matching_keys))
160 result_arg = LazyKnownValue(dct)
161 non_matching_keys = {}
162 else:
163 # normal param
164 if argument is None:
165 # No value: Return an empty container
166 if param.default is None:
167 result_arg = LazyUnknownValue()
168 if not keys_only:
169 for contextualized_node in arguments.get_calling_nodes():
170 m = _error_argument_count(funcdef, len(unpacked_va))
171 issues.append(
172 analysis.add(
173 contextualized_node.context,
174 'type-error-too-few-arguments',
175 contextualized_node.node,
176 message=m,
177 )
178 )
179 else:
180 result_arg = LazyTreeValue(default_param_context, param.default)
181 is_default = True
182 else:
183 result_arg = argument
184
185 result_params.append(ExecutedParamName(
186 function_value, arguments, param, result_arg, is_default=is_default
187 ))
188 if not isinstance(result_arg, LazyUnknownValue):
189 keys_used[param.name.value] = result_params[-1]
190
191 if keys_only:
192 # All arguments should be handed over to the next function. It's not
193 # about the values inside, it's about the names. Jedi needs to now that
194 # there's nothing to find for certain names.
195 for k in set(param_dict) - set(keys_used):
196 param = param_dict[k]
197
198 if not (non_matching_keys or had_multiple_value_error
199 or param.star_count or param.default):
200 # add a warning only if there's not another one.
201 for contextualized_node in arguments.get_calling_nodes():
202 m = _error_argument_count(funcdef, len(unpacked_va))
203 issues.append(
204 analysis.add(contextualized_node.context,
205 'type-error-too-few-arguments',
206 contextualized_node.node, message=m)
207 )
208
209 for key, lazy_value in non_matching_keys.items():
210 m = "TypeError: %s() got an unexpected keyword argument '%s'." \
211 % (funcdef.name, key)
212 issues.append(
213 _add_argument_issue(
214 'type-error-keyword-argument',
215 lazy_value,
216 message=m
217 )
218 )
219
220 remaining_arguments = list(var_arg_iterator)
221 if remaining_arguments:
222 first_key, lazy_value = remaining_arguments[0]
223 too_many_args(lazy_value)
224 return result_params, issues
225
226
227 def get_executed_param_names(function_value, arguments):
228 """
229 Return a list of `ExecutedParamName`s corresponding to the arguments of the
230 function execution `function_value`, containing the inferred value of those
231 arguments (whether explicit or default). Any issues building this list (for
232 example required arguments which are missing in the invocation) are ignored.
233
234 For example, given:
235 ```
236 def foo(a, b, c=None, d='d'): ...
237
238 foo(42, c='c')
239 ```
240
241 Then for the execution of `foo`, this will return a list containing entries
242 for each parameter a, b, c & d; the entries for a, c, & d will have their
243 values (42, 'c' and 'd' respectively) included.
244 """
245 return get_executed_param_names_and_issues(function_value, arguments)[0]
246
247
248 def _error_argument_count(funcdef, actual_count):
249 params = funcdef.get_params()
250 default_arguments = sum(1 for p in params if p.default or p.star_count)
251
252 if default_arguments == 0:
253 before = 'exactly '
254 else:
255 before = 'from %s to ' % (len(params) - default_arguments)
256 return ('TypeError: %s() takes %s%s arguments (%s given).'
257 % (funcdef.name, before, len(params), actual_count))