]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/compiled/mixed.py
Archivo de configuraciĆ³n de la terminal
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / inference / compiled / mixed.py
CommitLineData
53e6db90
DC
1"""
2Used only for REPL Completion.
3"""
4
5import inspect
6from pathlib import Path
7
8from jedi.parser_utils import get_cached_code_lines
9
10from jedi import settings
11from jedi.cache import memoize_method
12from jedi.inference import compiled
13from jedi.file_io import FileIO
14from jedi.inference.names import NameWrapper
15from jedi.inference.base_value import ValueSet, ValueWrapper, NO_VALUES
16from jedi.inference.value import ModuleValue
17from jedi.inference.cache import inference_state_function_cache, \
18 inference_state_method_cache
19from jedi.inference.compiled.access import ALLOWED_GETITEM_TYPES, get_api_type
20from jedi.inference.gradual.conversion import to_stub
21from jedi.inference.context import CompiledContext, CompiledModuleContext, \
22 TreeContextMixin
23
24_sentinel = object()
25
26
27class MixedObject(ValueWrapper):
28 """
29 A ``MixedObject`` is used in two ways:
30
31 1. It uses the default logic of ``parser.python.tree`` objects,
32 2. except for getattr calls and signatures. The names dicts are generated
33 in a fashion like ``CompiledValue``.
34
35 This combined logic makes it possible to provide more powerful REPL
36 completion. It allows side effects that are not noticable with the default
37 parser structure to still be completable.
38
39 The biggest difference from CompiledValue to MixedObject is that we are
40 generally dealing with Python code and not with C code. This will generate
41 fewer special cases, because we in Python you don't have the same freedoms
42 to modify the runtime.
43 """
44 def __init__(self, compiled_value, tree_value):
45 super().__init__(tree_value)
46 self.compiled_value = compiled_value
47 self.access_handle = compiled_value.access_handle
48
49 def get_filters(self, *args, **kwargs):
50 yield MixedObjectFilter(
51 self.inference_state, self.compiled_value, self._wrapped_value)
52
53 def get_signatures(self):
54 # Prefer `inspect.signature` over somehow analyzing Python code. It
55 # should be very precise, especially for stuff like `partial`.
56 return self.compiled_value.get_signatures()
57
58 @inference_state_method_cache(default=NO_VALUES)
59 def py__call__(self, arguments):
60 # Fallback to the wrapped value if to stub returns no values.
61 values = to_stub(self._wrapped_value)
62 if not values:
63 values = self._wrapped_value
64 return values.py__call__(arguments)
65
66 def get_safe_value(self, default=_sentinel):
67 if default is _sentinel:
68 return self.compiled_value.get_safe_value()
69 else:
70 return self.compiled_value.get_safe_value(default)
71
72 @property
73 def array_type(self):
74 return self.compiled_value.array_type
75
76 def get_key_values(self):
77 return self.compiled_value.get_key_values()
78
79 def py__simple_getitem__(self, index):
80 python_object = self.compiled_value.access_handle.access._obj
81 if type(python_object) in ALLOWED_GETITEM_TYPES:
82 return self.compiled_value.py__simple_getitem__(index)
83 return self._wrapped_value.py__simple_getitem__(index)
84
85 def negate(self):
86 return self.compiled_value.negate()
87
88 def _as_context(self):
89 if self.parent_context is None:
90 return MixedModuleContext(self)
91 return MixedContext(self)
92
93 def __repr__(self):
94 return '<%s: %s; %s>' % (
95 type(self).__name__,
96 self.access_handle.get_repr(),
97 self._wrapped_value,
98 )
99
100
101class MixedContext(CompiledContext, TreeContextMixin):
102 @property
103 def compiled_value(self):
104 return self._value.compiled_value
105
106
107class MixedModuleContext(CompiledModuleContext, MixedContext):
108 pass
109
110
111class MixedName(NameWrapper):
112 """
113 The ``CompiledName._compiled_value`` is our MixedObject.
114 """
115 def __init__(self, wrapped_name, parent_tree_value):
116 super().__init__(wrapped_name)
117 self._parent_tree_value = parent_tree_value
118
119 @property
120 def start_pos(self):
121 values = list(self.infer())
122 if not values:
123 # This means a start_pos that doesn't exist (compiled objects).
124 return 0, 0
125 return values[0].name.start_pos
126
127 @memoize_method
128 def infer(self):
129 compiled_value = self._wrapped_name.infer_compiled_value()
130 tree_value = self._parent_tree_value
131 if tree_value.is_instance() or tree_value.is_class():
132 tree_values = tree_value.py__getattribute__(self.string_name)
133 if compiled_value.is_function():
134 return ValueSet({MixedObject(compiled_value, v) for v in tree_values})
135
136 module_context = tree_value.get_root_context()
137 return _create(self._inference_state, compiled_value, module_context)
138
139
140class MixedObjectFilter(compiled.CompiledValueFilter):
141 def __init__(self, inference_state, compiled_value, tree_value):
142 super().__init__(inference_state, compiled_value)
143 self._tree_value = tree_value
144
145 def _create_name(self, *args, **kwargs):
146 return MixedName(
147 super()._create_name(*args, **kwargs),
148 self._tree_value,
149 )
150
151
152@inference_state_function_cache()
153def _load_module(inference_state, path):
154 return inference_state.parse(
155 path=path,
156 cache=True,
157 diff_cache=settings.fast_parser,
158 cache_path=settings.cache_directory
159 ).get_root_node()
160
161
162def _get_object_to_check(python_object):
163 """Check if inspect.getfile has a chance to find the source."""
164 try:
165 python_object = inspect.unwrap(python_object)
166 except ValueError:
167 # Can return a ValueError when it wraps around
168 pass
169
170 if (inspect.ismodule(python_object)
171 or inspect.isclass(python_object)
172 or inspect.ismethod(python_object)
173 or inspect.isfunction(python_object)
174 or inspect.istraceback(python_object)
175 or inspect.isframe(python_object)
176 or inspect.iscode(python_object)):
177 return python_object
178
179 try:
180 return python_object.__class__
181 except AttributeError:
182 raise TypeError # Prevents computation of `repr` within inspect.
183
184
185def _find_syntax_node_name(inference_state, python_object):
186 original_object = python_object
187 try:
188 python_object = _get_object_to_check(python_object)
189 path = inspect.getsourcefile(python_object)
190 except (OSError, TypeError):
191 # The type might not be known (e.g. class_with_dict.__weakref__)
192 return None
193 path = None if path is None else Path(path)
194 try:
195 if path is None or not path.exists():
196 # The path might not exist or be e.g. <stdin>.
197 return None
198 except OSError:
199 # Might raise an OSError on Windows:
200 #
201 # [WinError 123] The filename, directory name, or volume label
202 # syntax is incorrect: '<string>'
203 return None
204
205 file_io = FileIO(path)
206 module_node = _load_module(inference_state, path)
207
208 if inspect.ismodule(python_object):
209 # We don't need to check names for modules, because there's not really
210 # a way to write a module in a module in Python (and also __name__ can
211 # be something like ``email.utils``).
212 code_lines = get_cached_code_lines(inference_state.grammar, path)
213 return module_node, module_node, file_io, code_lines
214
215 try:
216 name_str = python_object.__name__
217 except AttributeError:
218 # Stuff like python_function.__code__.
219 return None
220
221 if name_str == '<lambda>':
222 return None # It's too hard to find lambdas.
223
224 # Doesn't always work (e.g. os.stat_result)
225 names = module_node.get_used_names().get(name_str, [])
226 # Only functions and classes are relevant. If a name e.g. points to an
227 # import, it's probably a builtin (like collections.deque) and needs to be
228 # ignored.
229 names = [
230 n for n in names
231 if n.parent.type in ('funcdef', 'classdef') and n.parent.name == n
232 ]
233 if not names:
234 return None
235
236 try:
237 code = python_object.__code__
238 # By using the line number of a code object we make the lookup in a
239 # file pretty easy. There's still a possibility of people defining
240 # stuff like ``a = 3; foo(a); a = 4`` on the same line, but if people
241 # do so we just don't care.
242 line_nr = code.co_firstlineno
243 except AttributeError:
244 pass
245 else:
246 line_names = [name for name in names if name.start_pos[0] == line_nr]
247 # There's a chance that the object is not available anymore, because
248 # the code has changed in the background.
249 if line_names:
250 names = line_names
251
252 code_lines = get_cached_code_lines(inference_state.grammar, path)
253 # It's really hard to actually get the right definition, here as a last
254 # resort we just return the last one. This chance might lead to odd
255 # completions at some points but will lead to mostly correct type
256 # inference, because people tend to define a public name in a module only
257 # once.
258 tree_node = names[-1].parent
259 if tree_node.type == 'funcdef' and get_api_type(original_object) == 'instance':
260 # If an instance is given and we're landing on a function (e.g.
261 # partial in 3.5), something is completely wrong and we should not
262 # return that.
263 return None
264 return module_node, tree_node, file_io, code_lines
265
266
267@inference_state_function_cache()
268def _create(inference_state, compiled_value, module_context):
269 # TODO accessing this is bad, but it probably doesn't matter that much,
270 # because we're working with interpreters only here.
271 python_object = compiled_value.access_handle.access._obj
272 result = _find_syntax_node_name(inference_state, python_object)
273 if result is None:
274 # TODO Care about generics from stuff like `[1]` and don't return like this.
275 if type(python_object) in (dict, list, tuple):
276 return ValueSet({compiled_value})
277
278 tree_values = to_stub(compiled_value)
279 if not tree_values:
280 return ValueSet({compiled_value})
281 else:
282 module_node, tree_node, file_io, code_lines = result
283
284 if module_context is None or module_context.tree_node != module_node:
285 root_compiled_value = compiled_value.get_root_context().get_value()
286 # TODO this __name__ might be wrong.
287 name = root_compiled_value.py__name__()
288 string_names = tuple(name.split('.'))
289 module_value = ModuleValue(
290 inference_state, module_node,
291 file_io=file_io,
292 string_names=string_names,
293 code_lines=code_lines,
294 is_package=root_compiled_value.is_package(),
295 )
296 if name is not None:
297 inference_state.module_cache.add(string_names, ValueSet([module_value]))
298 module_context = module_value.as_context()
299
300 tree_values = ValueSet({module_context.create_value(tree_node)})
301 if tree_node.type == 'classdef':
302 if not compiled_value.is_class():
303 # Is an instance, not a class.
304 tree_values = tree_values.execute_with_values()
305
306 return ValueSet(
307 MixedObject(compiled_value, tree_value=tree_value)
308 for tree_value in tree_values
309 )