2 from pathlib
import Path
3 from typing
import Optional
5 from jedi
.inference
.cache
import inference_state_method_cache
6 from jedi
.inference
.names
import AbstractNameDefinition
, ModuleName
7 from jedi
.inference
.filters
import GlobalNameFilter
, ParserTreeFilter
, DictFilter
, MergedFilter
8 from jedi
.inference
import compiled
9 from jedi
.inference
.base_value
import TreeValue
10 from jedi
.inference
.names
import SubModuleName
11 from jedi
.inference
.helpers
import values_from_qualified_names
12 from jedi
.inference
.compiled
import create_simple_object
13 from jedi
.inference
.base_value
import ValueSet
14 from jedi
.inference
.context
import ModuleContext
17 class _ModuleAttributeName(AbstractNameDefinition
):
19 For module attributes like __file__, __str__ and so on.
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
29 if self
._string
_value
is not None:
30 s
= self
._string
_value
32 create_simple_object(self
.parent_context
.inference_state
, s
)
34 return compiled
.get_string_value_set(self
.parent_context
.inference_state
)
37 class SubModuleDictMixin
:
38 @inference_state_method_cache()
39 def sub_modules_dict(self
):
41 Lists modules in the directory of this module (if this module is a
46 mods
= self
.inference_state
.compiled_subprocess
.iter_module_names(
50 # It's obviously a relative import to the current module.
51 names
[name
] = SubModuleName(self
.as_context(), name
)
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.
58 class ModuleMixin(SubModuleDictMixin
):
59 _module_name_class
= ModuleName
61 def get_filters(self
, origin_scope
=None):
64 parent_context
=self
.as_context(),
65 origin_scope
=origin_scope
67 GlobalNameFilter(self
.as_context()),
69 yield DictFilter(self
.sub_modules_dict())
70 yield DictFilter(self
._module
_attributes
_dict
())
71 yield from self
.iter_star_filters()
73 def py__class__(self
):
74 c
, = values_from_qualified_names(self
.inference_state
, 'types', 'ModuleType')
83 @property # type: ignore[misc]
84 @inference_state_method_cache()
86 return self
._module
_name
_class
(self
, self
.string_names
[-1])
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__()
95 dct
['__file__'] = _ModuleAttributeName(self
, '__file__', str(path
))
98 def iter_star_filters(self
):
99 for star_module
in self
.star_imports():
100 f
= next(star_module
.get_filters(), None)
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
112 module_context
= self
.as_context()
113 for i
in self
.tree_node
.iter_imports():
114 if i
.is_star_import():
116 self
.inference_state
,
117 import_path
=i
.get_paths()[-1],
118 module_context
=module_context
,
123 if isinstance(module
, ModuleValue
):
124 modules
+= module
.star_imports()
128 def get_qualified_names(self
):
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.
137 class ModuleValue(ModuleMixin
, TreeValue
):
140 def __init__(self
, inference_state
, module_node
, code_lines
, file_io
=None,
141 string_names
=None, is_package
=False):
145 tree_node
=module_node
147 self
.file_io
= file_io
149 self
._path
: Optional
[Path
] = None
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
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.
162 return super().is_stub()
164 def py__name__(self
):
165 if self
.string_names
is None:
167 return '.'.join(self
.string_names
)
169 def py__file__(self
) -> Optional
[Path
]:
171 In contrast to Python's __file__ can be None.
173 if self
._path
is None:
176 return self
._path
.absolute()
178 def is_package(self
):
179 return self
._is
_package
181 def py__package__(self
):
182 if self
.string_names
is None:
186 return self
.string_names
187 return self
.string_names
[:-1]
189 def py__path__(self
):
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.
195 if not self
._is
_package
:
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.
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
):
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
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)]
222 def _as_context(self
):
223 return ModuleContext(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],