diff --git a/jedi/api/classes.py b/jedi/api/classes.py index e5c789ea..79756a78 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -142,7 +142,7 @@ class BaseDefinition(object): stripped = stripped.parent if isinstance(stripped, pr.Name): stripped = stripped.parent - return type(stripped).__name__.lower() + return type(stripped).__name__.lower().replace('wrapper', '') def _path(self): """The module path.""" diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 7d6a13e9..02784444 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -206,6 +206,8 @@ class NameFinder(object): typ = er.Class(evaluator, typ) elif isinstance(typ, pr.Function): typ = er.Function(evaluator, typ) + elif isinstance(typ, pr.Module): + typ = er.ModuleWrapper(evaluator, typ) if typ.isinstance(er.Function) and resolve_decorator: typ = typ.get_decorated_func() types.append(typ) diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 2f868d85..568c6c27 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -473,7 +473,13 @@ def follow_imports(evaluator, scopes): result = [] for s in scopes: if isinstance(s, pr.Import): - result += ImportWrapper(evaluator, s).follow() + for r in ImportWrapper(evaluator, s).follow(): + if isinstance(r, pr.Module) and not isinstance(r, + StarImportModule): + # TODO This check is strange and feels wrong somehow. Change it. + from jedi.evaluate import representation as er + r = er.ModuleWrapper(evaluator, r) + result.append(r) else: result.append(s) return result diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index c9b886d4..fc87b17a 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -521,3 +521,23 @@ class FunctionExecution(Executable): def __repr__(self): return "<%s of %s>" % (type(self).__name__, self.base) + + +class ModuleWrapper(pr.Module): + def __init__(self, evaluator, module): + self._evaluator = evaluator + self._module = module + + @memoize_default() + def get_defined_names(self): + names = ['__file__', '__package__', '__doc__', '__name__', '__version__'] + # All the additional module attributes are strings. + parent = Instance(self._evaluator, compiled.create(self._evaluator, str)) + module_attributes = [helpers.FakeName(n, parent) for n in names] + return self._module.get_defined_names() + module_attributes + + def __getattr__(self, name): + return getattr(self._module, name) + + def __repr__(self): + return "<%s: %s>" % (type(self).__name__, self._module) diff --git a/test/completion/imports.py b/test/completion/imports.py index cd5193a9..79072c4b 100644 --- a/test/completion/imports.py +++ b/test/completion/imports.py @@ -46,8 +46,8 @@ def scope_nested(): #? ['sqrt'] import_tree.pkg.sqrt - #? ['a', 'pkg'] - import_tree. + #? ['pkg'] + import_tree.p #? float() import_tree.pkg.mod1.a @@ -317,3 +317,12 @@ else: a = not_existing_import #? a + +# ----------------- +# magic methods +# ----------------- + +def magic_method(): + import keyword + #? ['__file__'] + keyword.__file__