mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 14:04:26 +08:00
again all sort of import related stuff, relative imports work now! fixes #2
This commit is contained in:
@@ -1509,7 +1509,7 @@ def goto(scopes, search_name=None, statement_path_offset=1):
|
|||||||
if isinstance(s, imports.ImportPath):
|
if isinstance(s, imports.ImportPath):
|
||||||
try:
|
try:
|
||||||
s = s.follow()[0]
|
s = s.follow()[0]
|
||||||
except imports.ModuleNotFound:
|
except IndexError:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if not isinstance(s, parsing.Module):
|
if not isinstance(s, parsing.Module):
|
||||||
|
|||||||
20
functions.py
20
functions.py
@@ -193,21 +193,14 @@ def _prepare_goto(position, source_path, module, goto_path,
|
|||||||
if isinstance(user_stmt, parsing.Import):
|
if isinstance(user_stmt, parsing.Import):
|
||||||
import_names = user_stmt.get_all_import_names()
|
import_names = user_stmt.get_all_import_names()
|
||||||
count = 0
|
count = 0
|
||||||
found_count = None
|
kill_count = -1
|
||||||
for i in import_names:
|
for i in import_names:
|
||||||
for name_part in i.names:
|
for name_part in i.names:
|
||||||
count += 1
|
count += 1
|
||||||
if name_part.start_pos <= position <= name_part.end_pos:
|
if position <= name_part.end_pos:
|
||||||
found_count = count
|
kill_count += 1
|
||||||
if found_count is None:
|
|
||||||
found_count = count
|
|
||||||
if is_like_search:
|
|
||||||
# is_like_search will decrease also one, so change this here.
|
|
||||||
found_count += 1
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
scopes = [imports.ImportPath(user_stmt, is_like_search,
|
scopes = [imports.ImportPath(user_stmt, is_like_search,
|
||||||
kill_count=(count - found_count), direct_resolve=True)]
|
kill_count=kill_count, direct_resolve=True)]
|
||||||
else:
|
else:
|
||||||
# just parse one statement, take it and evaluate it
|
# just parse one statement, take it and evaluate it
|
||||||
r = parsing.PyFuzzyParser(goto_path, source_path, no_docstr=True)
|
r = parsing.PyFuzzyParser(goto_path, source_path, no_docstr=True)
|
||||||
@@ -244,10 +237,7 @@ def get_definition(source, line, column, source_path):
|
|||||||
for s in scopes.copy():
|
for s in scopes.copy():
|
||||||
if isinstance(s, imports.ImportPath):
|
if isinstance(s, imports.ImportPath):
|
||||||
scopes.remove(s)
|
scopes.remove(s)
|
||||||
try:
|
scopes.update(resolve_import_paths(set(s.follow())))
|
||||||
scopes.update(resolve_import_paths(set(s.follow())))
|
|
||||||
except imports.ModuleNotFound:
|
|
||||||
pass
|
|
||||||
return scopes
|
return scopes
|
||||||
|
|
||||||
pos = (line, column)
|
pos = (line, column)
|
||||||
|
|||||||
33
imports.py
33
imports.py
@@ -21,8 +21,14 @@ class ImportPath(object):
|
|||||||
"""
|
"""
|
||||||
An ImportPath is the path of a `parsing.Import` object.
|
An ImportPath is the path of a `parsing.Import` object.
|
||||||
"""
|
"""
|
||||||
class GlobalNamespace(object):
|
class _GlobalNamespace(object):
|
||||||
pass
|
def get_defined_names(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_imports(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
GlobalNamespace = _GlobalNamespace()
|
||||||
|
|
||||||
def __init__(self, import_stmt, is_like_search=False, kill_count=0,
|
def __init__(self, import_stmt, is_like_search=False, kill_count=0,
|
||||||
direct_resolve=False):
|
direct_resolve=False):
|
||||||
@@ -45,7 +51,6 @@ class ImportPath(object):
|
|||||||
for i in range(kill_count + int(is_like_search)):
|
for i in range(kill_count + int(is_like_search)):
|
||||||
self.import_path.pop()
|
self.import_path.pop()
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (self.__class__.__name__, self.import_stmt)
|
return '<%s: %s>' % (self.__class__.__name__, self.import_stmt)
|
||||||
|
|
||||||
@@ -79,8 +84,13 @@ class ImportPath(object):
|
|||||||
names = []
|
names = []
|
||||||
for scope in self.follow():
|
for scope in self.follow():
|
||||||
if scope is ImportPath.GlobalNamespace:
|
if scope is ImportPath.GlobalNamespace:
|
||||||
names += self.get_module_names()
|
if self.import_stmt.relative_count == 0:
|
||||||
names += self.get_module_names([self.file_path])
|
names += self.get_module_names()
|
||||||
|
|
||||||
|
path = os.path.abspath(self.file_path)
|
||||||
|
for i in range(self.import_stmt.relative_count - 1):
|
||||||
|
path = os.path.dirname(path)
|
||||||
|
names += self.get_module_names([path])
|
||||||
else:
|
else:
|
||||||
if on_import_stmt and isinstance(scope, parsing.Module) \
|
if on_import_stmt and isinstance(scope, parsing.Module) \
|
||||||
and scope.path.endswith('__init__.py'):
|
and scope.path.endswith('__init__.py'):
|
||||||
@@ -117,7 +127,13 @@ class ImportPath(object):
|
|||||||
Returns the imported modules.
|
Returns the imported modules.
|
||||||
"""
|
"""
|
||||||
if self.import_path:
|
if self.import_path:
|
||||||
scope, rest = self._follow_file_system()
|
try:
|
||||||
|
scope, rest = self._follow_file_system()
|
||||||
|
except ModuleNotFound:
|
||||||
|
debug.warning('Module not found: ' + str(self.import_stmt))
|
||||||
|
return []
|
||||||
|
return [ImportPath.GlobalNamespace]
|
||||||
|
|
||||||
if len(rest) > 1 or rest and self.is_like_search:
|
if len(rest) > 1 or rest and self.is_like_search:
|
||||||
scopes = []
|
scopes = []
|
||||||
elif rest:
|
elif rest:
|
||||||
@@ -214,10 +230,7 @@ def strip_imports(scopes):
|
|||||||
if isinstance(s, parsing.Import):
|
if isinstance(s, parsing.Import):
|
||||||
# this is something like a statement following.
|
# this is something like a statement following.
|
||||||
evaluate.statement_path.append(s)
|
evaluate.statement_path.append(s)
|
||||||
try:
|
result += ImportPath(s).follow()
|
||||||
result += ImportPath(s).follow()
|
|
||||||
except ModuleNotFound:
|
|
||||||
debug.warning('Module not found: ' + str(s))
|
|
||||||
else:
|
else:
|
||||||
result.append(s)
|
result.append(s)
|
||||||
return result
|
return result
|
||||||
|
|||||||
34
parsing.py
34
parsing.py
@@ -515,7 +515,7 @@ class Import(Simple):
|
|||||||
:type defunct: bool
|
:type defunct: bool
|
||||||
"""
|
"""
|
||||||
def __init__(self, start_pos, end_pos, namespace, alias=None, \
|
def __init__(self, start_pos, end_pos, namespace, alias=None, \
|
||||||
from_ns=None, star=False, relative_count=None, defunct=False):
|
from_ns=None, star=False, relative_count=0, defunct=False):
|
||||||
super(Import, self).__init__(start_pos, end_pos)
|
super(Import, self).__init__(start_pos, end_pos)
|
||||||
|
|
||||||
self.namespace = namespace
|
self.namespace = namespace
|
||||||
@@ -1138,6 +1138,10 @@ class PyFuzzyParser(object):
|
|||||||
else:
|
else:
|
||||||
token_type, tok = pre_used_token
|
token_type, tok = pre_used_token
|
||||||
|
|
||||||
|
if token_type != tokenize.NAME and tok != '*':
|
||||||
|
# token maybe a name or star
|
||||||
|
return (None, token_type, tok)
|
||||||
|
|
||||||
append((tok, self.start_pos))
|
append((tok, self.start_pos))
|
||||||
first_pos = self.start_pos
|
first_pos = self.start_pos
|
||||||
while True:
|
while True:
|
||||||
@@ -1175,6 +1179,8 @@ class PyFuzzyParser(object):
|
|||||||
while True:
|
while True:
|
||||||
defunct = False
|
defunct = False
|
||||||
token_type, tok = self.next()
|
token_type, tok = self.next()
|
||||||
|
if token_type == tokenize.ENDMARKER:
|
||||||
|
break
|
||||||
if brackets and tok == '\n':
|
if brackets and tok == '\n':
|
||||||
self.next()
|
self.next()
|
||||||
if tok == '(': # python allows only one `(` in the statement.
|
if tok == '(': # python allows only one `(` in the statement.
|
||||||
@@ -1421,15 +1427,16 @@ class PyFuzzyParser(object):
|
|||||||
else:
|
else:
|
||||||
n, token_type, tok = self._parsedotname(self.current)
|
n, token_type, tok = self._parsedotname(self.current)
|
||||||
tok_list.pop() # removed last entry, because we add Name
|
tok_list.pop() # removed last entry, because we add Name
|
||||||
tok_list.append(n)
|
if n:
|
||||||
if tok == '(':
|
tok_list.append(n)
|
||||||
# it must be a function
|
if tok == '(':
|
||||||
used_funcs.append(n)
|
# it must be a function
|
||||||
else:
|
used_funcs.append(n)
|
||||||
used_vars.append(n)
|
else:
|
||||||
if string and re.match(r'[\w\d\'"]', string[-1]):
|
used_vars.append(n)
|
||||||
string += ' '
|
if string and re.match(r'[\w\d\'"]', string[-1]):
|
||||||
string += ".".join(n.names)
|
string += ' '
|
||||||
|
string += ".".join(n.names)
|
||||||
continue
|
continue
|
||||||
elif '=' in tok and not tok in ['>=', '<=', '==', '!=']:
|
elif '=' in tok and not tok in ['>=', '<=', '==', '!=']:
|
||||||
# there has been an assignement -> change vars
|
# there has been an assignement -> change vars
|
||||||
@@ -1474,7 +1481,7 @@ class PyFuzzyParser(object):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
debug.warning('return in non-function')
|
debug.warning('return in non-function')
|
||||||
|
|
||||||
if list_comp or tok in always_break:
|
if tok in always_break:
|
||||||
self.gen.push_back(self._current_full)
|
self.gen.push_back(self._current_full)
|
||||||
return stmt, tok
|
return stmt, tok
|
||||||
|
|
||||||
@@ -1584,9 +1591,11 @@ class PyFuzzyParser(object):
|
|||||||
debug.warning("from: syntax error@%s" %
|
debug.warning("from: syntax error@%s" %
|
||||||
self.start_pos[0])
|
self.start_pos[0])
|
||||||
defunct = True
|
defunct = True
|
||||||
|
if tok != 'import':
|
||||||
|
self.gen.push_back(self._current_full)
|
||||||
names = self._parseimportlist()
|
names = self._parseimportlist()
|
||||||
for name, alias, defunct2 in names:
|
for name, alias, defunct2 in names:
|
||||||
star = name.names[0] == '*'
|
star = name is not None and name.names[0] == '*'
|
||||||
if star:
|
if star:
|
||||||
name = None
|
name = None
|
||||||
i = Import(first_pos, self.end_pos, name, alias, mod,
|
i = Import(first_pos, self.end_pos, name, alias, mod,
|
||||||
@@ -1596,6 +1605,7 @@ class PyFuzzyParser(object):
|
|||||||
if not names:
|
if not names:
|
||||||
i = Import(first_pos, self.end_pos, mod, defunct=True,
|
i = Import(first_pos, self.end_pos, mod, defunct=True,
|
||||||
relative_count=relative_count)
|
relative_count=relative_count)
|
||||||
|
print i, repr(mod)
|
||||||
self._check_user_stmt(i)
|
self._check_user_stmt(i)
|
||||||
self.scope.add_import(i)
|
self.scope.add_import(i)
|
||||||
self.freshscope = False
|
self.freshscope = False
|
||||||
|
|||||||
@@ -172,6 +172,10 @@ mod1.
|
|||||||
#? str()
|
#? str()
|
||||||
imp_tree.a
|
imp_tree.a
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------
|
||||||
|
# special positions -> edge cases
|
||||||
|
# -----------------
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
#? 6 datetime
|
#? 6 datetime
|
||||||
@@ -187,3 +191,13 @@ from import_tree. import pkg
|
|||||||
|
|
||||||
#? 18 ['pkg']
|
#? 18 ['pkg']
|
||||||
from import_tree.p import pkg
|
from import_tree.p import pkg
|
||||||
|
|
||||||
|
#? 17 ['import_tree']
|
||||||
|
from .import_tree import
|
||||||
|
#? 10 ['run']
|
||||||
|
from ..run import
|
||||||
|
#? ['run']
|
||||||
|
from .. import run
|
||||||
|
|
||||||
|
#? []
|
||||||
|
from not_a_module import
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ class TestRegression(unittest.TestCase):
|
|||||||
assert self.get_def("import sys_blabla", (1, 8)) == []
|
assert self.get_def("import sys_blabla", (1, 8)) == []
|
||||||
assert len(self.get_def("import sys", (1, 8))) == 1
|
assert len(self.get_def("import sys", (1, 8))) == 1
|
||||||
|
|
||||||
|
def test_complete_on_empty_import(self):
|
||||||
|
# should just list the files in the directory
|
||||||
|
assert 10 < len(self.complete("from .", (1, 5))) < 30
|
||||||
|
assert 10 < len(self.complete("from . import", (1, 5))) < 30
|
||||||
|
assert 10 < len(self.complete("from . import classes", (1, 5))) < 30
|
||||||
|
|
||||||
def test_new(self):
|
def test_new(self):
|
||||||
""" This is just to try out things, removing or deleting it is ok. """
|
""" This is just to try out things, removing or deleting it is ok. """
|
||||||
s = ("def abc(): pass\n"
|
s = ("def abc(): pass\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user