]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/value/module.py
ActualizaciĆ³n de Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / inference / value / module.py
CommitLineData
53e6db90
DC
1import os
2from pathlib import Path
3from typing import Optional
4
5from jedi.inference.cache import inference_state_method_cache
6from jedi.inference.names import AbstractNameDefinition, ModuleName
7from jedi.inference.filters import GlobalNameFilter, ParserTreeFilter, DictFilter, MergedFilter
8from jedi.inference import compiled
9from jedi.inference.base_value import TreeValue
10from jedi.inference.names import SubModuleName
11from jedi.inference.helpers import values_from_qualified_names
12from jedi.inference.compiled import create_simple_object
13from jedi.inference.base_value import ValueSet
14from jedi.inference.context import ModuleContext
15
16
17class _ModuleAttributeName(AbstractNameDefinition):
18 """
19 For module attributes like __file__, __str__ and so on.
20 """
21 api_type = 'instance'
22
23 def __init__(self, parent_module, string_name, string_value=None):
24 self.parent_context = parent_module
25 self.string_name = string_name
26 self._string_value = string_value
27
28 def infer(self):
29 if self._string_value is not None:
30 s = self._string_value
31 return ValueSet([
32 create_simple_object(self.parent_context.inference_state, s)
33 ])
34 return compiled.get_string_value_set(self.parent_context.inference_state)
35
36
37class SubModuleDictMixin:
38 @inference_state_method_cache()
39 def sub_modules_dict(self):
40 """
41 Lists modules in the directory of this module (if this module is a
42 package).
43 """
44 names = {}
45 if self.is_package():
46 mods = self.inference_state.compiled_subprocess.iter_module_names(
47 self.py__path__()
48 )
49 for name in mods:
50 # It's obviously a relative import to the current module.
51 names[name] = SubModuleName(self.as_context(), name)
52
53 # In the case of an import like `from x.` we don't need to
54 # add all the variables, this is only about submodules.
55 return names
56
57
58class ModuleMixin(SubModuleDictMixin):
59 _module_name_class = ModuleName
60
61 def get_filters(self, origin_scope=None):
62 yield MergedFilter(
63 ParserTreeFilter(
64 parent_context=self.as_context(),
65 origin_scope=origin_scope
66 ),
67 GlobalNameFilter(self.as_context()),
68 )
69 yield DictFilter(self.sub_modules_dict())
70 yield DictFilter(self._module_attributes_dict())
71 yield from self.iter_star_filters()
72
73 def py__class__(self):
74 c, = values_from_qualified_names(self.inference_state, 'types', 'ModuleType')
75 return c
76
77 def is_module(self):
78 return True
79
80 def is_stub(self):
81 return False
82
83 @property # type: ignore[misc]
84 @inference_state_method_cache()
85 def name(self):
86 return self._module_name_class(self, self.string_names[-1])
87
88 @inference_state_method_cache()
89 def _module_attributes_dict(self):
90 names = ['__package__', '__doc__', '__name__']
91 # All the additional module attributes are strings.
92 dct = dict((n, _ModuleAttributeName(self, n)) for n in names)
93 path = self.py__file__()
94 if path is not None:
95 dct['__file__'] = _ModuleAttributeName(self, '__file__', str(path))
96 return dct
97
98 def iter_star_filters(self):
99 for star_module in self.star_imports():
100 f = next(star_module.get_filters(), None)
101 assert f is not None
102 yield f
103
104 # I'm not sure if the star import cache is really that effective anymore
105 # with all the other really fast import caches. Recheck. Also we would need
106 # to push the star imports into InferenceState.module_cache, if we reenable this.
107 @inference_state_method_cache([])
108 def star_imports(self):
109 from jedi.inference.imports import Importer
110
111 modules = []
112 module_context = self.as_context()
113 for i in self.tree_node.iter_imports():
114 if i.is_star_import():
115 new = Importer(
116 self.inference_state,
117 import_path=i.get_paths()[-1],
118 module_context=module_context,
119 level=i.level
120 ).follow()
121
122 for module in new:
123 if isinstance(module, ModuleValue):
124 modules += module.star_imports()
125 modules += new
126 return modules
127
128 def get_qualified_names(self):
129 """
130 A module doesn't have a qualified name, but it's important to note that
131 it's reachable and not `None`. With this information we can add
132 qualified names on top for all value children.
133 """
134 return ()
135
136
137class ModuleValue(ModuleMixin, TreeValue):
138 api_type = 'module'
139
140 def __init__(self, inference_state, module_node, code_lines, file_io=None,
141 string_names=None, is_package=False):
142 super().__init__(
143 inference_state,
144 parent_context=None,
145 tree_node=module_node
146 )
147 self.file_io = file_io
148 if file_io is None:
149 self._path: Optional[Path] = None
150 else:
151 self._path = file_io.path
152 self.string_names = string_names # Optional[Tuple[str, ...]]
153 self.code_lines = code_lines
154 self._is_package = is_package
155
156 def is_stub(self):
157 if self._path is not None and self._path.suffix == '.pyi':
158 # Currently this is the way how we identify stubs when e.g. goto is
159 # used in them. This could be changed if stubs would be identified
160 # sooner and used as StubModuleValue.
161 return True
162 return super().is_stub()
163
164 def py__name__(self):
165 if self.string_names is None:
166 return None
167 return '.'.join(self.string_names)
168
169 def py__file__(self) -> Optional[Path]:
170 """
171 In contrast to Python's __file__ can be None.
172 """
173 if self._path is None:
174 return None
175
176 return self._path.absolute()
177
178 def is_package(self):
179 return self._is_package
180
181 def py__package__(self):
182 if self.string_names is None:
183 return []
184
185 if self._is_package:
186 return self.string_names
187 return self.string_names[:-1]
188
189 def py__path__(self):
190 """
191 In case of a package, this returns Python's __path__ attribute, which
192 is a list of paths (strings).
193 Returns None if the module is not a package.
194 """
195 if not self._is_package:
196 return None
197
198 # A namespace package is typically auto generated and ~10 lines long.
199 first_few_lines = ''.join(self.code_lines[:50])
200 # these are strings that need to be used for namespace packages,
201 # the first one is ``pkgutil``, the second ``pkg_resources``.
202 options = ('declare_namespace(__name__)', 'extend_path(__path__')
203 if options[0] in first_few_lines or options[1] in first_few_lines:
204 # It is a namespace, now try to find the rest of the
205 # modules on sys_path or whatever the search_path is.
206 paths = set()
207 for s in self.inference_state.get_sys_path():
208 other = os.path.join(s, self.name.string_name)
209 if os.path.isdir(other):
210 paths.add(other)
211 if paths:
212 return list(paths)
213 # Nested namespace packages will not be supported. Nobody ever
214 # asked for it and in Python 3 they are there without using all the
215 # crap above.
216
217 # Default to the of this file.
218 file = self.py__file__()
219 assert file is not None # Shouldn't be a package in the first place.
220 return [os.path.dirname(file)]
221
222 def _as_context(self):
223 return ModuleContext(self)
224
225 def __repr__(self):
226 return "<%s: %s@%s-%s is_stub=%s>" % (
227 self.__class__.__name__, self.py__name__(),
228 self.tree_node.start_pos[0], self.tree_node.end_pos[0],
229 self.is_stub()
230 )