diff --git a/jedi/api/project.py b/jedi/api/project.py index 615f5039..20572a87 100644 --- a/jedi/api/project.py +++ b/jedi/api/project.py @@ -10,7 +10,7 @@ from jedi.api.exceptions import WrongVersion from jedi.api.completion import search_in_module from jedi.api.helpers import split_search_string, get_module_names from jedi._compatibility import force_unicode -from jedi.inference.imports import load_module_from_path +from jedi.inference.imports import load_module_from_path, load_namespace_from_path from jedi.inference.sys_path import discover_buildout_paths from jedi.inference.cache import inference_state_as_method_param_cache from jedi.inference.references import recurse_find_python_folders_and_files, search_in_file_ios @@ -196,11 +196,11 @@ class Project(object): try: m = load_module_from_path(inference_state, f).as_context() except FileNotFoundError: - f = folder_io.get_file_io('__init__.py') + f = folder_io.get_file_io('__init__.pyi') try: m = load_module_from_path(inference_state, f).as_context() except FileNotFoundError: - m = namespace + m = load_namespace_from_path(inference_state, folder_io).as_context() else: continue else: diff --git a/jedi/inference/context.py b/jedi/inference/context.py index e9236c1f..b4e9d9bf 100644 --- a/jedi/inference/context.py +++ b/jedi/inference/context.py @@ -353,6 +353,10 @@ class NamespaceContext(TreeContextMixin, ValueContext): def get_value(self): return self._value + @property + def string_names(self): + return self._value.string_names + def py__file__(self): return self._value.py__file__() diff --git a/jedi/inference/imports.py b/jedi/inference/imports.py index a43e19aa..8e4ae7c3 100644 --- a/jedi/inference/imports.py +++ b/jedi/inference/imports.py @@ -500,6 +500,15 @@ def load_module_from_path(inference_state, file_io, base_names=None): return module +def load_namespace_from_path(inference_state, folder_io): + import_names, is_package = sys_path.transform_path_to_dotted( + inference_state.get_sys_path(), + folder_io.path + ) + from jedi.inference.value.namespace import ImplicitNamespaceValue + return ImplicitNamespaceValue(inference_state, import_names, [folder_io.path]) + + def follow_error_node_imports_if_possible(context, name): error_node = tree.search_ancestor(name, 'error_node') if error_node is not None: diff --git a/test/test_api/test_project.py b/test/test_api/test_project.py index 41dd4dfe..52efefa2 100644 --- a/test/test_api/test_project.py +++ b/test/test_api/test_project.py @@ -73,6 +73,26 @@ def test_load_save_project(tmpdir): ('test_api.test_project.test_search', ['test_api.test_project.test_search'], {}), ('test_api.test_project.test_sear', ['test_api.test_project.test_search'], dict(complete=True)), + + # With namespace + ('implicit_namespace_package.ns1.pkg', + ['test_inference.implicit_namespace_package.ns1.pkg', + 'examples.implicit_namespace_package.ns1.pkg'], {}), + ('implicit_namespace_package.ns1.pkg.ns1_file', + ['test_inference.implicit_namespace_package.ns1.pkg.ns1_file', + 'examples.implicit_namespace_package.ns1.pkg.ns1_file'], {}), + ('examples.implicit_namespace_package.ns1.pkg.ns1_file', + ['examples.implicit_namespace_package.ns1.pkg.ns1_file'], {}), + ('implicit_namespace_package.ns1.pkg.', + ['test_inference.implicit_namespace_package.ns1.pkg.ns1_file', + 'examples.implicit_namespace_package.ns1.pkg.ns1_file'], + dict(complete=True)), + ('implicit_namespace_package.', + ['test_inference.implicit_namespace_package.ns1', + 'test_inference.implicit_namespace_package.ns2', + 'examples.implicit_namespace_package.ns1', + 'examples.implicit_namespace_package.ns2'], + dict(complete=True)), ] ) @pytest.mark.skipif(sys.version_info < (3, 6), reason="Ignore Python 2, because EOL")