Implement Import.is_nested method.

This commit is contained in:
Dave Halter
2014-12-11 16:17:07 +01:00
parent 6406bfb3c2
commit 6818d3affa
4 changed files with 35 additions and 28 deletions

View File

@@ -610,11 +610,11 @@ class Script(object):
def _analysis(self):
#statements = set(chain(*self._parser.module().used_names.values()))
stmts, imps = analysis.get_module_statements(self._parser.module())
stmts, imp_names = analysis.get_module_statements(self._parser.module())
# Sort the statements so that the results are reproducible.
for i in imps:
iw = imports.ImportWrapper(self._evaluator, i,
nested_resolve=True).follow()
for n in imp_names:
iw = imports.ImportWrapper(self._evaluator, n).follow()
i = n.get_definition()
if i.is_nested() and any(not isinstance(i, pr.Module) for i in iw):
analysis.add(self._evaluator, 'import-error', i.namespace_names[-1])
for stmt in sorted(stmts, key=lambda obj: obj.start_pos):

View File

@@ -212,9 +212,10 @@ def get_module_statements(module):
return new
stmts = set()
imports = set()
import_names = set()
for scope in module.walk():
imports |= set(scope.imports)
for imp in set(scope.imports):
import_names |= set(imp.get_defined_names())
stmts |= add_stmts(scope.statements)
stmts |= add_stmts(r for r in scope.returns if r is not None)
@@ -224,4 +225,4 @@ def get_module_statements(module):
pass
else:
stmts |= add_stmts(decorators)
return stmts, imports
return stmts, import_names

View File

@@ -32,9 +32,9 @@ from jedi.evaluate.cache import memoize_default, NO_DEFAULT
class ModuleNotFound(Exception):
def __init__(self, name_part):
def __init__(self, name):
super(ModuleNotFound, self).__init__()
self.name_part = name_part
self.name = name
def completion_names(evaluator, imp, pos):
@@ -101,16 +101,16 @@ class ImportWrapper(pr.Base):
try:
module, rest = importer.follow_file_system()
except ModuleNotFound as e:
analysis.add(self._evaluator, 'import-error', e.name_part)
analysis.add(self._evaluator, 'import-error', e.name)
return []
if module is None:
return []
if self._import.is_nested() and not self.nested_resolve:
scopes = [NestedImportModule(module, self._import)]
else:
scopes = [module]
#if self._import.is_nested() and not self.nested_resolve:
# scopes = [NestedImportModule(module, self._import)]
#else:
scopes = [module]
#star_imports = remove_star_imports(self._evaluator, module)
#if star_imports:
@@ -127,7 +127,11 @@ class ImportWrapper(pr.Base):
self._evaluator.find_types(s, rest[0], is_goto=True)
for s in scopes))
else:
scopes = importer.follow_rest(scopes[0], rest)
print(self._import, scopes, rest)
if self._import.type == 'import_from':
scopes = importer.follow_rest(scopes[0], rest)
else:
scopes = []
debug.dbg('after import: %s', scopes)
if not scopes:
analysis.add(self._evaluator, 'import-error', importer.import_path[-1])
@@ -135,6 +139,7 @@ class ImportWrapper(pr.Base):
self._evaluator.recursion_detector.pop_stmt()
return scopes
class ImportWrapper2(pr.Base):
"""
An ImportWrapper is the path of a `pr.Import` object.
@@ -284,7 +289,7 @@ class ImportWrapper2(pr.Base):
try:
module, rest = self._importer.follow_file_system()
except ModuleNotFound as e:
analysis.add(self._evaluator, 'import-error', e.name_part)
analysis.add(self._evaluator, 'import-error', e.name)
return []
if module is None:
@@ -346,7 +351,7 @@ class NestedImportModule(pr.Module):
# This is not an existing Import statement. Therefore, set position to
# 0 (0 is not a valid line number).
zero = (0, 0)
names = [unicode(name_part) for name_part in i.namespace_names[1:]]
names = [unicode(name) for name in i.namespace_names[1:]]
name = helpers.FakeName(names, self._nested_import)
new = pr.Import(i._sub_module, zero, zero, name)
new.parent = self._module
@@ -435,7 +440,7 @@ class _Importer(object):
@property
def str_import_path(self):
"""Returns the import path as pure strings instead of `Name`."""
return tuple(str(name_part) for name_part in self.import_path)
return tuple(str(name) for name in self.import_path)
def get_relative_path(self):
path = self.file_path

View File

@@ -992,16 +992,7 @@ class Import(Simple):
raise ValueError('Name should be defined in the import itself')
def is_nested(self):
"""
This checks for the special case of nested imports, without aliases and
from statement::
import foo.bar
"""
return False
# TODO use this check differently?
return not self.alias and not self.from_names \
and len(self.namespace_names) > 1
return False # By default, sub classes may overwrite this behavior
def is_star_import(self):
return self.children[-1] == '*'
@@ -1102,6 +1093,16 @@ class ImportName(Import):
# dotted_names
yield as_name.children[::2], alias
def is_nested(self):
"""
This checks for the special case of nested imports, without aliases and
from statement::
import foo.bar
"""
return [1 for path, alias in self._dotted_as_names()
if alias is None and len(path) > 1]
def aliases(self):
return dict((alias, path[-1]) for path, alias in self._dotted_as_names()
if alias is not None)