From 993567ca56f378a9edf77162ec2ab6b9462e7b06 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 26 Mar 2019 18:42:37 +0100 Subject: [PATCH] Remove submodule dict issues from namespace packages --- jedi/evaluate/context/module.py | 61 +++++++++++----------- jedi/evaluate/context/namespace.py | 22 +------- test/test_evaluate/test_imports.py | 14 +++++ test/test_evaluate/zipped_imports/pkg.zip | Bin 811 -> 1057 bytes 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/jedi/evaluate/context/module.py b/jedi/evaluate/context/module.py index eb4195da..e1b30a5a 100644 --- a/jedi/evaluate/context/module.py +++ b/jedi/evaluate/context/module.py @@ -37,7 +37,37 @@ class ModuleName(ContextNameMixin, AbstractNameDefinition): return self._name -class ModuleMixin(object): +class SubModuleDictMixin(object): + @evaluator_method_cache() + def _sub_modules_dict(self): + """ + Lists modules in the directory of this module (if this module is a + package). + """ + from jedi.evaluate.imports import SubModuleName + + names = {} + try: + method = self.py__path__ + except AttributeError: + pass + else: + for path in method(): + mods = iter_modules([path]) + for module_loader, name, is_pkg in mods: + # It's obviously a relative import to the current module. + names[name] = SubModuleName(self, name) + + # TODO add something like this in the future, its cleaner than the + # import hacks. + # ``os.path`` is a hardcoded exception, because it's a + # ``sys.modules`` modification. + # if str(self.name) == 'os': + # names.append(Name('path', parent_context=self)) + + return names + +class ModuleMixin(SubModuleDictMixin): def get_filters(self, search_global=False, until_position=None, origin_scope=None): yield MergedFilter( ParserTreeFilter( @@ -77,35 +107,6 @@ class ModuleMixin(object): # Remove PEP 3149 names return re.sub(r'\.[a-z]+-\d{2}[mud]{0,3}$', '', r.group(1)) - @evaluator_method_cache() - def _sub_modules_dict(self): - """ - Lists modules in the directory of this module (if this module is a - package). - """ - from jedi.evaluate.imports import SubModuleName - - names = {} - try: - method = self.py__path__ - except AttributeError: - pass - else: - for path in method(): - mods = iter_modules([path]) - for module_loader, name, is_pkg in mods: - # It's obviously a relative import to the current module. - names[name] = SubModuleName(self, name) - - # TODO add something like this in the future, its cleaner than the - # import hacks. - # ``os.path`` is a hardcoded exception, because it's a - # ``sys.modules`` modification. - # if str(self.name) == 'os': - # names.append(Name('path', parent_context=self)) - - return names - @evaluator_method_cache() def _module_attributes_dict(self): names = ['__file__', '__package__', '__doc__', '__name__'] diff --git a/jedi/evaluate/context/namespace.py b/jedi/evaluate/context/namespace.py index cf705f64..2616f83b 100644 --- a/jedi/evaluate/context/namespace.py +++ b/jedi/evaluate/context/namespace.py @@ -1,10 +1,7 @@ -import os -from itertools import chain - from jedi.evaluate.cache import evaluator_method_cache -from jedi.evaluate import imports from jedi.evaluate.filters import DictFilter, AbstractNameDefinition, ContextNameMixin from jedi.evaluate.base_context import Context +from jedi.evaluate.context.module import SubModuleDictMixin class ImplicitNSName(ContextNameMixin, AbstractNameDefinition): @@ -17,7 +14,7 @@ class ImplicitNSName(ContextNameMixin, AbstractNameDefinition): self.string_name = string_name -class ImplicitNamespaceContext(Context): +class ImplicitNamespaceContext(Context, SubModuleDictMixin): """ Provides support for implicit namespace packages """ @@ -56,20 +53,5 @@ class ImplicitNamespaceContext(Context): def py__name__(self): return self._fullname - @evaluator_method_cache() - def _sub_modules_dict(self): - names = {} - - file_names = chain.from_iterable(os.listdir(path) for path in self._paths) - mods = [ - file_name.rpartition('.')[0] if '.' in file_name else file_name - for file_name in file_names - if file_name != '__pycache__' - ] - - for name in mods: - names[name] = imports.SubModuleName(self, name) - return names - def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self._fullname) diff --git a/test/test_evaluate/test_imports.py b/test/test_evaluate/test_imports.py index 8f42d4e7..8721bcce 100644 --- a/test/test_evaluate/test_imports.py +++ b/test/test_evaluate/test_imports.py @@ -59,11 +59,25 @@ def test_find_module_package_zipped(Script, evaluator, environment): @pytest.mark.parametrize( 'code, file, package, path', [ ('import pkg', '__init__.py', 'pkg', 'pkg'), + #('import pkg', '__init__.py', 'pkg', 'pkg'), + ('from pkg import module', 'module.py', 'pkg', None), + #('from pkg.module', 'module.py', 'pkg', None), + ('from pkg import nested', os.path.join('nested', '__init__.py'), 'pkg.nested', os.path.join('pkg', 'nested')), + #('from pkg.nested', os.path.join('nested', '__init__.py'), + # 'pkg.nested', os.path.join('pkg', 'nested')), + ('from pkg.nested import nested_module', os.path.join('nested', 'nested_module.py'), 'pkg.nested', None), + #('from pkg.nested.nested_module', + # os.path.join('nested', 'nested_module.py'), 'pkg.nested', None), + + ('from pkg.namespace import namespace_module', + os.path.join('namespace', 'namespace_module.py'), 'pkg.namespace', None), + #('from pkg.namespace.namespace_module', + # os.path.join('namespace', 'namespace_module.py'), 'pkg.namespace', None), ] ) diff --git a/test/test_evaluate/zipped_imports/pkg.zip b/test/test_evaluate/zipped_imports/pkg.zip index 41366b12d1533a77eddc7610a6d31a0981491e54..0344f746975f4f6ceb1fca740e58d8baafd45406 100644 GIT binary patch delta 287 zcmZ3@wvb~3BV%HwPn91765s=}3$oMo^AdAYiwhEyQ}qM9nOV4)K}wR*)GA`Ah3ksX z%}*)KN!2T;-1t3(u^yW(AQKrF1RDN2eh1R%b}};AGvl@utd&8bVN0VjBf4HJZkX)P wq{WoPIJuh1oT-~}vJIouV0BM9i{{R30 delta 54 zcmZ3;v6^iIBje;iW|7SejBX%?9MgA($%V}3j0%%iGCMPdOn%F(#>d9M#?ZmYz|afC G3=9C6Z48kB