move usages to its own api module usages

This commit is contained in:
Dave Halter
2014-01-26 23:04:38 +01:00
parent 8193f0c2b6
commit f6b1e5635e
3 changed files with 114 additions and 108 deletions

View File

@@ -24,6 +24,7 @@ from jedi import cache
from jedi.api import keywords from jedi.api import keywords
from jedi.api import classes from jedi.api import classes
from jedi.api import interpreter from jedi.api import interpreter
from jedi.api import usages
from jedi.evaluate import Evaluator, filter_private_variable from jedi.evaluate import Evaluator, filter_private_variable
from jedi.evaluate import representation as er from jedi.evaluate import representation as er
from jedi.evaluate import compiled from jedi.evaluate import compiled
@@ -451,21 +452,21 @@ class Script(object):
if unicode(v.names[-1]) == search_name] if unicode(v.names[-1]) == search_name]
if not isinstance(user_stmt, pr.Import): if not isinstance(user_stmt, pr.Import):
# import case is looked at with add_import_name option # import case is looked at with add_import_name option
definitions = usages_add_import_modules(self._evaluator, definitions, search_name) definitions = usages.usages_add_import_modules(self._evaluator, definitions, search_name)
module = set([d.get_parent_until() for d in definitions]) module = set([d.get_parent_until() for d in definitions])
module.add(self._parser.module()) module.add(self._parser.module())
names = usages(self._evaluator, definitions, search_name, module) names = usages.usages(self._evaluator, definitions, search_name, module)
for d in set(definitions): for d in set(definitions):
if isinstance(d, pr.Module): if isinstance(d, pr.Module):
names.append(classes.Usage(self._evaluator, d, d)) names.append(usages.Usage(self._evaluator, d, d))
elif isinstance(d, er.Instance): elif isinstance(d, er.Instance):
# Instances can be ignored, because they are being created by # Instances can be ignored, because they are being created by
# ``__getattr__``. # ``__getattr__``.
pass pass
else: else:
names.append(classes.Usage(self._evaluator, d.names[-1], d)) names.append(usages.Usage(self._evaluator, d.names[-1], d))
settings.dynamic_flow_information = temp settings.dynamic_flow_information = temp
return self._sorted_defs(set(names)) return self._sorted_defs(set(names))
@@ -667,88 +668,3 @@ def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
debug.enable_warning = warnings debug.enable_warning = warnings
debug.enable_notice = notices debug.enable_notice = notices
debug.enable_speed = speed debug.enable_speed = speed
# TODO move to a better place.
def usages(evaluator, definitions, search_name, mods):
def compare_array(definitions):
""" `definitions` are being compared by module/start_pos, because
sometimes the id's of the objects change (e.g. executions).
"""
result = []
for d in definitions:
module = d.get_parent_until()
result.append((module, d.start_pos))
return result
def check_call(call):
result = []
follow = [] # There might be multiple search_name's in one call_path
call_path = list(call.generate_call_path())
for i, name in enumerate(call_path):
# name is `pr.NamePart`.
if name == search_name:
follow.append(call_path[:i + 1])
for f in follow:
follow_res, search = evaluator.goto(call.parent, f)
# names can change (getattr stuff), therefore filter names that
# don't match `search_name`.
# TODO add something like that in the future - for now usages are
# completely broken anyway.
#follow_res = [r for r in follow_res if str(r) == search]
#print search.start_pos,search_name.start_pos
#print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res]
follow_res = usages_add_import_modules(evaluator, follow_res, search)
compare_follow_res = compare_array(follow_res)
# compare to see if they match
if any(r in compare_definitions for r in compare_follow_res):
scope = call.parent
result.append(classes.Usage(evaluator, search, scope))
return result
if not definitions:
return set()
compare_definitions = compare_array(definitions)
mods |= set([d.get_parent_until() for d in definitions])
names = []
for m in imports.get_modules_containing_name(mods, search_name):
try:
stmts = m.used_names[search_name]
except KeyError:
continue
for stmt in stmts:
if isinstance(stmt, pr.Import):
count = 0
imps = []
for i in stmt.get_all_import_names():
for name_part in i.names:
count += 1
if name_part == search_name:
imps.append((count, name_part))
for used_count, name_part in imps:
i = imports.ImportPath(evaluator, stmt, kill_count=count - used_count,
direct_resolve=True)
f = i.follow(is_goto=True)
if set(f) & set(definitions):
names.append(classes.Usage(evaluator, name_part, stmt))
else:
for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True):
names += check_call(call)
return names
def usages_add_import_modules(evaluator, definitions, search_name):
""" Adds the modules of the imports """
new = set()
for d in definitions:
if isinstance(d.parent, pr.Import):
s = imports.ImportPath(evaluator, d.parent, direct_resolve=True)
with common.ignored(IndexError):
new.add(s.follow(is_goto=True)[0])
return set(definitions) | new

View File

@@ -557,25 +557,6 @@ def defined_names(evaluator, scope):
return [Definition(evaluator, d) for d in sorted(names, key=lambda s: s.start_pos)] return [Definition(evaluator, d) for d in sorted(names, key=lambda s: s.start_pos)]
class Usage(BaseDefinition):
"""TODO: document this"""
def __init__(self, evaluator, name_part, scope):
super(Usage, self).__init__(evaluator, scope, name_part.start_pos)
self.text = unicode(name_part)
self.end_pos = name_part.end_pos
@property
def description(self):
return "%s@%s,%s" % (self.text, self.line, self.column)
def __eq__(self, other):
return self._start_pos == other._start_pos \
and self.module_path == other.module_path
def __hash__(self):
return hash((self._start_pos, self.module_path))
class CallDef(object): class CallDef(object):
""" """
`CallDef` objects is the return value of `Script.function_definition`. `CallDef` objects is the return value of `Script.function_definition`.

109
jedi/api/usages.py Normal file
View File

@@ -0,0 +1,109 @@
from jedi._compatibility import unicode
from jedi import common
from jedi.api import classes
from jedi.parser import representation as pr
from jedi.evaluate import imports
from jedi.evaluate import helpers
class Usage(classes.BaseDefinition):
"""TODO: document this"""
def __init__(self, evaluator, name_part, scope):
super(Usage, self).__init__(evaluator, scope, name_part.start_pos)
self.text = unicode(name_part)
self.end_pos = name_part.end_pos
@property
def description(self):
return "%s@%s,%s" % (self.text, self.line, self.column)
def __eq__(self, other):
return self._start_pos == other._start_pos \
and self.module_path == other.module_path
def __hash__(self):
return hash((self._start_pos, self.module_path))
def usages(evaluator, definitions, search_name, mods):
def compare_array(definitions):
""" `definitions` are being compared by module/start_pos, because
sometimes the id's of the objects change (e.g. executions).
"""
result = []
for d in definitions:
module = d.get_parent_until()
result.append((module, d.start_pos))
return result
def check_call(call):
result = []
follow = [] # There might be multiple search_name's in one call_path
call_path = list(call.generate_call_path())
for i, name in enumerate(call_path):
# name is `pr.NamePart`.
if name == search_name:
follow.append(call_path[:i + 1])
for f in follow:
follow_res, search = evaluator.goto(call.parent, f)
# names can change (getattr stuff), therefore filter names that
# don't match `search_name`.
# TODO add something like that in the future - for now usages are
# completely broken anyway.
#follow_res = [r for r in follow_res if str(r) == search]
#print search.start_pos,search_name.start_pos
#print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res]
follow_res = usages_add_import_modules(evaluator, follow_res, search)
compare_follow_res = compare_array(follow_res)
# compare to see if they match
if any(r in compare_definitions for r in compare_follow_res):
scope = call.parent
result.append(Usage(evaluator, search, scope))
return result
if not definitions:
return set()
compare_definitions = compare_array(definitions)
mods |= set([d.get_parent_until() for d in definitions])
names = []
for m in imports.get_modules_containing_name(mods, search_name):
try:
stmts = m.used_names[search_name]
except KeyError:
continue
for stmt in stmts:
if isinstance(stmt, pr.Import):
count = 0
imps = []
for i in stmt.get_all_import_names():
for name_part in i.names:
count += 1
if name_part == search_name:
imps.append((count, name_part))
for used_count, name_part in imps:
i = imports.ImportPath(evaluator, stmt, kill_count=count - used_count,
direct_resolve=True)
f = i.follow(is_goto=True)
if set(f) & set(definitions):
names.append(Usage(evaluator, name_part, stmt))
else:
for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True):
names += check_call(call)
return names
def usages_add_import_modules(evaluator, definitions, search_name):
""" Adds the modules of the imports """
new = set()
for d in definitions:
if isinstance(d.parent, pr.Import):
s = imports.ImportPath(evaluator, d.parent, direct_resolve=True)
with common.ignored(IndexError):
new.add(s.follow(is_goto=True)[0])
return set(definitions) | new