Skip to content

Commit

Permalink
Finally make it possible to use auto_import_modules for packages
Browse files Browse the repository at this point in the history
This means that you can now write 'from gi.repository import Gtk' and Gtk completions work.

It also means that other libraries could be used like that for speed or other reasons.

Fixes #531
  • Loading branch information
davidhalter committed Jul 2, 2018
1 parent 5b7984c commit f4aad8b
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 6 deletions.
5 changes: 4 additions & 1 deletion jedi/evaluate/compiled/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def load_module(evaluator, path=None, name=None, sys_path=None):
__import__(dotted_path)
except ImportError:
# If a module is "corrupt" or not really a Python module or whatever.
debug.warning('Module %s not importable in path %s.', dotted_path, path)
print_to_stderr('Module %s not importable in path %s.' % (dotted_path, path))
return None
except Exception:
# Since __import__ pretty much makes code execution possible, just
Expand Down Expand Up @@ -262,6 +262,9 @@ def py__class__(self):
def py__bases__(self):
return [self._create_access_path(base) for base in self._obj.__bases__]

def py__path__(self):
return self._obj.__path__

@_force_unicode_decorator
def get_repr(self):
builtins = 'builtins', '__builtin__'
Expand Down
4 changes: 4 additions & 0 deletions jedi/evaluate/compiled/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ def py__bases__(self):
for access in self.access_handle.py__bases__()
)

@CheckAttribute
def py__path__(self):
return self.access_handle.py__path__()

def py__bool__(self):
return self.access_handle.py__bool__()

Expand Down
14 changes: 11 additions & 3 deletions jedi/evaluate/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ def sys_path_with_modifications(self):
def follow(self):
if not self.import_path:
return NO_CONTEXTS

return self._do_import(self.import_path, self.sys_path_with_modifications())

def _do_import(self, import_path, sys_path):
Expand All @@ -300,6 +301,14 @@ def _do_import(self, import_path, sys_path):
# Old style
return self._do_import(('flaskext',) + import_path[2:], sys_path)

if import_parts[0] in settings.auto_import_modules:
module = compiled.load_module(
self._evaluator,
name='.'.join(import_parts),
sys_path=sys_path,
)
return ContextSet(module)

module_name = '.'.join(import_parts)
try:
return ContextSet(self._evaluator.module_cache.get(module_name))
Expand Down Expand Up @@ -464,7 +473,7 @@ def completion_names(self, evaluator, only_modules=False):


def _load_module(evaluator, path=None, code=None, sys_path=None,
module_name=None, safe_module_name=False):
module_name=None, safe_module_name=False, auto_import=False):
try:
return evaluator.module_cache.get(module_name)
except KeyError:
Expand All @@ -485,9 +494,8 @@ def _load_module(evaluator, path=None, code=None, sys_path=None,
if sys_path is None:
sys_path = evaluator.get_sys_path()

dotted_path = path and dotted_from_fs_path(path, sys_path)
if path is not None and path.endswith(('.py', '.zip', '.egg')) \
and dotted_path not in settings.auto_import_modules:
and not auto_import:

module_node = evaluator.parse(
code=code, path=path, cache=True, diff_cache=True,
Expand Down
3 changes: 2 additions & 1 deletion jedi/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@
"""

auto_import_modules = [
'hashlib', # setattr
'hashlib', # hashlib is mostly using setattr, which jedi doesn't understand
'gi', # This third-party repository (GTK stuff) doesn't really work with jedi
]
"""
Modules that are not analyzed but imported, although they contain Python code.
Expand Down
13 changes: 12 additions & 1 deletion test/test_settings.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import pytest

from jedi import settings
from jedi.evaluate.compiled import CompiledContextName


def test_base_auto_import_modules(monkeypatch, Script):
@pytest.fixture()
def auto_import_json(monkeypatch):
monkeypatch.setattr(settings, 'auto_import_modules', ['json'])


def test_base_auto_import_modules(auto_import_json, Script):
loads, = Script('import json; json.loads').goto_definitions()
assert isinstance(loads._name, CompiledContextName)


def test_auto_import_modules_imports(auto_import_json, Script):
main, = Script('from json import tool; tool.main').goto_definitions()
assert isinstance(main._name, CompiledContextName)

0 comments on commit f4aad8b

Please sign in to comment.