]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/star_args.py
Actualizado el Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / inference / star_args.py
CommitLineData
53e6db90
DC
1"""
2This module is responsible for inferring *args and **kwargs for signatures.
3
4This means for example in this case::
5
6 def foo(a, b, c): ...
7
8 def bar(*args):
9 return foo(1, *args)
10
11The signature here for bar should be `bar(b, c)` instead of bar(*args).
12"""
13from inspect import Parameter
14
15from parso import tree
16
17from jedi.inference.utils import to_list
18from jedi.inference.names import ParamNameWrapper
19from jedi.inference.helpers import is_big_annoying_library
20
21
22def _iter_nodes_for_param(param_name):
23 from parso.python.tree import search_ancestor
24 from jedi.inference.arguments import TreeArguments
25
26 execution_context = param_name.parent_context
27 # Walk up the parso tree to get the FunctionNode we want. We use the parso
28 # tree rather than going via the execution context so that we're agnostic of
29 # the specific scope we're evaluating within (i.e: module or function,
30 # etc.).
31 function_node = tree.search_ancestor(param_name.tree_name, 'funcdef', 'lambdef')
32 module_node = function_node.get_root_node()
33 start = function_node.children[-1].start_pos
34 end = function_node.children[-1].end_pos
35 for name in module_node.get_used_names().get(param_name.string_name):
36 if start <= name.start_pos < end:
37 # Is used in the function
38 argument = name.parent
39 if argument.type == 'argument' \
40 and argument.children[0] == '*' * param_name.star_count:
41 trailer = search_ancestor(argument, 'trailer')
42 if trailer is not None: # Make sure we're in a function
43 context = execution_context.create_context(trailer)
44 if _goes_to_param_name(param_name, context, name):
45 values = _to_callables(context, trailer)
46
47 args = TreeArguments.create_cached(
48 execution_context.inference_state,
49 context=context,
50 argument_node=trailer.children[1],
51 trailer=trailer,
52 )
53 for c in values:
54 yield c, args
55
56
57def _goes_to_param_name(param_name, context, potential_name):
58 if potential_name.type != 'name':
59 return False
60 from jedi.inference.names import TreeNameDefinition
61 found = TreeNameDefinition(context, potential_name).goto()
62 return any(param_name.parent_context == p.parent_context
63 and param_name.start_pos == p.start_pos
64 for p in found)
65
66
67def _to_callables(context, trailer):
68 from jedi.inference.syntax_tree import infer_trailer
69
70 atom_expr = trailer.parent
71 index = atom_expr.children[0] == 'await'
72 # Infer atom first
73 values = context.infer_node(atom_expr.children[index])
74 for trailer2 in atom_expr.children[index + 1:]:
75 if trailer == trailer2:
76 break
77 values = infer_trailer(context, values, trailer2)
78 return values
79
80
81def _remove_given_params(arguments, param_names):
82 count = 0
83 used_keys = set()
84 for key, _ in arguments.unpack():
85 if key is None:
86 count += 1
87 else:
88 used_keys.add(key)
89
90 for p in param_names:
91 if count and p.maybe_positional_argument():
92 count -= 1
93 continue
94 if p.string_name in used_keys and p.maybe_keyword_argument():
95 continue
96 yield p
97
98
99@to_list
100def process_params(param_names, star_count=3): # default means both * and **
101 if param_names:
102 if is_big_annoying_library(param_names[0].parent_context):
103 # At first this feature can look innocent, but it does a lot of
104 # type inference in some cases, so we just ditch it.
105 yield from param_names
106 return
107
108 used_names = set()
109 arg_callables = []
110 kwarg_callables = []
111
112 kw_only_names = []
113 kwarg_names = []
114 arg_names = []
115 original_arg_name = None
116 original_kwarg_name = None
117 for p in param_names:
118 kind = p.get_kind()
119 if kind == Parameter.VAR_POSITIONAL:
120 if star_count & 1:
121 arg_callables = _iter_nodes_for_param(p)
122 original_arg_name = p
123 elif p.get_kind() == Parameter.VAR_KEYWORD:
124 if star_count & 2:
125 kwarg_callables = list(_iter_nodes_for_param(p))
126 original_kwarg_name = p
127 elif kind == Parameter.KEYWORD_ONLY:
128 if star_count & 2:
129 kw_only_names.append(p)
130 elif kind == Parameter.POSITIONAL_ONLY:
131 if star_count & 1:
132 yield p
133 else:
134 if star_count == 1:
135 yield ParamNameFixedKind(p, Parameter.POSITIONAL_ONLY)
136 elif star_count == 2:
137 kw_only_names.append(ParamNameFixedKind(p, Parameter.KEYWORD_ONLY))
138 else:
139 used_names.add(p.string_name)
140 yield p
141
142 # First process *args
143 longest_param_names = ()
144 found_arg_signature = False
145 found_kwarg_signature = False
146 for func_and_argument in arg_callables:
147 func, arguments = func_and_argument
148 new_star_count = star_count
149 if func_and_argument in kwarg_callables:
150 kwarg_callables.remove(func_and_argument)
151 else:
152 new_star_count = 1
153
154 for signature in func.get_signatures():
155 found_arg_signature = True
156 if new_star_count == 3:
157 found_kwarg_signature = True
158 args_for_this_func = []
159 for p in process_params(
160 list(_remove_given_params(
161 arguments,
162 signature.get_param_names(resolve_stars=False)
163 )), new_star_count):
164 if p.get_kind() == Parameter.VAR_KEYWORD:
165 kwarg_names.append(p)
166 elif p.get_kind() == Parameter.VAR_POSITIONAL:
167 arg_names.append(p)
168 elif p.get_kind() == Parameter.KEYWORD_ONLY:
169 kw_only_names.append(p)
170 else:
171 args_for_this_func.append(p)
172 if len(args_for_this_func) > len(longest_param_names):
173 longest_param_names = args_for_this_func
174
175 for p in longest_param_names:
176 if star_count == 1 and p.get_kind() != Parameter.VAR_POSITIONAL:
177 yield ParamNameFixedKind(p, Parameter.POSITIONAL_ONLY)
178 else:
179 if p.get_kind() == Parameter.POSITIONAL_OR_KEYWORD:
180 used_names.add(p.string_name)
181 yield p
182
183 if not found_arg_signature and original_arg_name is not None:
184 yield original_arg_name
185 elif arg_names:
186 yield arg_names[0]
187
188 # Then process **kwargs
189 for func, arguments in kwarg_callables:
190 for signature in func.get_signatures():
191 found_kwarg_signature = True
192 for p in process_params(
193 list(_remove_given_params(
194 arguments,
195 signature.get_param_names(resolve_stars=False)
196 )), star_count=2):
197 if p.get_kind() == Parameter.VAR_KEYWORD:
198 kwarg_names.append(p)
199 elif p.get_kind() == Parameter.KEYWORD_ONLY:
200 kw_only_names.append(p)
201
202 for p in kw_only_names:
203 if p.string_name in used_names:
204 continue
205 yield p
206 used_names.add(p.string_name)
207
208 if not found_kwarg_signature and original_kwarg_name is not None:
209 yield original_kwarg_name
210 elif kwarg_names:
211 yield kwarg_names[0]
212
213
214class ParamNameFixedKind(ParamNameWrapper):
215 def __init__(self, param_name, new_kind):
216 super().__init__(param_name)
217 self._new_kind = new_kind
218
219 def get_kind(self):
220 return self._new_kind