Big refactoring: BaseDefinition._definnition changes to BaseDefinition._name, because it's a NamePart now.

This also includes changes to tests and some simplifications like deleting the old name logic of Definition.
This commit is contained in:
Dave Halter
2014-09-11 01:02:20 +02:00
parent 58526e2302
commit 9f16555f47
4 changed files with 50 additions and 96 deletions

View File

@@ -160,15 +160,15 @@ class Script(object):
# add named params # add named params
for call_sig in self.call_signatures(): for call_sig in self.call_signatures():
# Allow protected access, because it's a public API. # Allow protected access, because it's a public API.
module = call_sig._definition.get_parent_until() module = call_sig._name.get_parent_until()
# Compiled modules typically don't allow keyword arguments. # Compiled modules typically don't allow keyword arguments.
if not isinstance(module, compiled.CompiledObject): if not isinstance(module, compiled.CompiledObject):
for p in call_sig.params: for p in call_sig.params:
# Allow access on _definition here, because it's a # Allow access on _definition here, because it's a
# public API and we don't want to make the internal # public API and we don't want to make the internal
# Name object public. # Name object public.
if p._definition.get_definition().stars == 0: # no *args/**kwargs if p._name.get_definition().stars == 0: # no *args/**kwargs
completions.append((p._definition.parent, p)) completions.append((p._name.parent, p))
if not path and not isinstance(user_stmt, pr.Import): if not path and not isinstance(user_stmt, pr.Import):
# add keywords # add keywords

View File

@@ -63,23 +63,34 @@ class BaseDefinition(object):
'_sre.SRE_Pattern': 're.RegexObject', '_sre.SRE_Pattern': 're.RegexObject',
}.items()) }.items())
def __init__(self, evaluator, definition, start_pos): def __init__(self, evaluator, name, start_pos):
self._evaluator = evaluator self._evaluator = evaluator
self._start_pos = start_pos self._start_pos = start_pos
self._definition = definition self._name = name
""" """
An instance of :class:`jedi.parsing_representation.Base` subclass. An instance of :class:`jedi.parsing_representation.Base` subclass.
""" """
self.is_keyword = isinstance(definition, keywords.Keyword) self.is_keyword = isinstance(name, keywords.Keyword)
# generate a path to the definition # generate a path to the definition
self._module = definition.get_parent_until() self._module = name.get_parent_until()
if self.in_builtin_module(): if self.in_builtin_module():
self.module_path = None self.module_path = None
else: else:
self.module_path = self._module.path self.module_path = self._module.path
"""Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``""" """Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``"""
@property
def name(self):
"""
Name of variable/function/class/module.
For example, for ``x = None`` it returns ``'x'``.
:rtype: str or None
"""
return unicode(self._name)
@property @property
def start_pos(self): def start_pos(self):
""" """
@@ -142,7 +153,7 @@ class BaseDefinition(object):
""" """
# generate the type # generate the type
stripped = self._definition stripped = self._name
if isinstance(stripped, er.InstanceElement): if isinstance(stripped, er.InstanceElement):
stripped = stripped.var stripped = stripped.var
if isinstance(stripped, (pr.Name, pr.NamePart)): if isinstance(stripped, (pr.Name, pr.NamePart)):
@@ -165,8 +176,8 @@ class BaseDefinition(object):
if x: if x:
path.insert(0, x) path.insert(0, x)
if not isinstance(self._definition, keywords.Keyword): if not isinstance(self._name, keywords.Keyword):
par = self._definition.get_definition() par = self._name.get_definition()
while par is not None: while par is not None:
if isinstance(par, pr.Import): if isinstance(par, pr.Import):
insert_nonnone(par.namespace) insert_nonnone(par.namespace)
@@ -246,7 +257,7 @@ class BaseDefinition(object):
Document for function f. Document for function f.
""" """
definition = self._definition definition = self._name
if isinstance(definition, pr.NamePart): if isinstance(definition, pr.NamePart):
definition = definition.parent.parent definition = definition.parent.parent
if raw: if raw:
@@ -277,7 +288,7 @@ class BaseDefinition(object):
@property @property
def description(self): def description(self):
"""A textual description of the object.""" """A textual description of the object."""
return unicode(self._definition) return unicode(self._name)
@property @property
def full_name(self): def full_name(self):
@@ -326,15 +337,15 @@ class BaseDefinition(object):
if element is name_part: if element is name_part:
return call_path[:i + 1] return call_path[:i + 1]
if not isinstance(self._definition, pr.NamePart): if not isinstance(self._name, pr.NamePart):
raise TypeError('Definition is not a NamePart.') raise TypeError('Definition is not a NamePart.')
if self.type not in ('statement', 'import'): if self.type not in ('statement', 'import'):
# Functions, classes and modules are already fixed definitions, we # Functions, classes and modules are already fixed definitions, we
# cannot follow them anymore. # cannot follow them anymore.
return [self] return [self]
stmt_or_imp = self._definition.get_parent_until((pr.Statement, pr.Import)) stmt_or_imp = self._name.get_parent_until((pr.Statement, pr.Import))
call_path = call_path_for_name_part(stmt_or_imp, self._definition) call_path = call_path_for_name_part(stmt_or_imp, self._name)
names = self._evaluator.goto(stmt_or_imp, call_path) names = self._evaluator.goto(stmt_or_imp, call_path)
return [Definition(self._evaluator, n) for n in names] return [Definition(self._evaluator, n) for n in names]
@@ -343,7 +354,7 @@ class BaseDefinition(object):
""" """
Follow both statements and imports, as far as possible. Follow both statements and imports, as far as possible.
""" """
stripped = self._definition stripped = self._name
if isinstance(stripped, (pr.Name, pr.NamePart)): if isinstance(stripped, (pr.Name, pr.NamePart)):
stripped = stripped.get_definition() stripped = stripped.get_definition()
@@ -388,10 +399,10 @@ class BaseDefinition(object):
return [_Param(self._evaluator, p.get_name().names[-1]) for p in params] return [_Param(self._evaluator, p.get_name().names[-1]) for p in params]
def parent(self): def parent(self):
if isinstance(self._definition, compiled.CompiledObject): if isinstance(self._name, compiled.CompiledObject):
non_flow = self._definition.parent non_flow = self._name.parent
else: else:
scope = self._definition.get_definition().get_parent_scope() scope = self._name.get_definition().get_parent_scope()
non_flow = scope.get_parent_until(pr.Flow, reverse=True) non_flow = scope.get_parent_until(pr.Flow, reverse=True)
return Definition(self._evaluator, non_flow.name.names[-1]) return Definition(self._evaluator, non_flow.name.names[-1])
@@ -407,7 +418,6 @@ class Completion(BaseDefinition):
def __init__(self, evaluator, name, needs_dot, like_name_length, base): def __init__(self, evaluator, name, needs_dot, like_name_length, base):
super(Completion, self).__init__(evaluator, name, name.start_pos) super(Completion, self).__init__(evaluator, name, name.start_pos)
self._name = name
self._needs_dot = needs_dot self._needs_dot = needs_dot
self._like_name_length = like_name_length self._like_name_length = like_name_length
self._base = base self._base = base
@@ -446,18 +456,6 @@ class Completion(BaseDefinition):
""" """
return self._complete(True) return self._complete(True)
@property
def name(self):
"""
Similar to :attr:`complete`, but return the whole word, for
example::
isinstan
would return `isinstance`.
"""
return unicode(self._name)
@property @property
def name_with_symbols(self): def name_with_symbols(self):
""" """
@@ -488,7 +486,7 @@ class Completion(BaseDefinition):
return '' return ''
t = self.type t = self.type
if t == 'statement' or t == 'import': if t == 'statement' or t == 'import':
desc = self._definition.get_definition().get_code(False) desc = self._name.get_definition().get_code(False)
else: else:
desc = '.'.join(unicode(p) for p in self._path()) desc = '.'.join(unicode(p) for p in self._path())
@@ -506,7 +504,7 @@ class Completion(BaseDefinition):
the ``foo.docstring(fast=False)`` on every object, because it the ``foo.docstring(fast=False)`` on every object, because it
parses all libraries starting with ``a``. parses all libraries starting with ``a``.
""" """
definition = self._definition.get_definition() definition = self._name.get_definition()
if isinstance(definition, pr.Import): if isinstance(definition, pr.Import):
i = imports.ImportWrapper(self._evaluator, definition) i = imports.ImportWrapper(self._evaluator, definition)
if len(i.import_path) > 1 or not fast: if len(i.import_path) > 1 or not fast:
@@ -526,7 +524,7 @@ class Completion(BaseDefinition):
The type of the completion objects. Follows imports. For a further The type of the completion objects. Follows imports. For a further
description, look at :attr:`jedi.api.classes.BaseDefinition.type`. description, look at :attr:`jedi.api.classes.BaseDefinition.type`.
""" """
definition = self._definition.get_definition() definition = self._name.get_definition()
if isinstance(definition, pr.Import): if isinstance(definition, pr.Import):
i = imports.ImportWrapper(self._evaluator, definition) i = imports.ImportWrapper(self._evaluator, definition)
if len(i.import_path) <= 1: if len(i.import_path) <= 1:
@@ -544,7 +542,7 @@ class Completion(BaseDefinition):
def _follow_statements_imports(self): def _follow_statements_imports(self):
# imports completion is very complicated and needs to be treated # imports completion is very complicated and needs to be treated
# separately in Completion. # separately in Completion.
definition = self._definition.get_definition() definition = self._name.get_definition()
if definition.isinstance(pr.Import) and definition.alias is None: if definition.isinstance(pr.Import) and definition.alias is None:
i = imports.ImportWrapper(self._evaluator, definition, True) i = imports.ImportWrapper(self._evaluator, definition, True)
import_path = i.import_path + (unicode(self._name),) import_path = i.import_path + (unicode(self._name),)
@@ -577,50 +575,6 @@ class Definition(use_metaclass(CachedMetaClass, BaseDefinition)):
def __init__(self, evaluator, definition): def __init__(self, evaluator, definition):
super(Definition, self).__init__(evaluator, definition, definition.start_pos) super(Definition, self).__init__(evaluator, definition, definition.start_pos)
@property
@underscore_memoization
def name(self):
"""
Name of variable/function/class/module.
For example, for ``x = None`` it returns ``'x'``.
:rtype: str or None
"""
d = self._definition
if isinstance(d, er.InstanceElement):
d = d.var
if isinstance(d, (compiled.CompiledObject, compiled.CompiledName)):
name = d.name
elif isinstance(d, pr.Name):
name = d.names[-1]
elif isinstance(d, iterable.Array):
name = d.type
elif isinstance(d, (pr.Class, er.Class, er.Instance,
er.Function, pr.Function)):
name = d.name
elif isinstance(d, pr.Module):
name = self.module_name
elif isinstance(d, pr.Import):
try:
name = d.get_defined_names()[0].names[-1]
except (AttributeError, IndexError):
return None
elif isinstance(d, pr.Param):
name = d.get_name()
elif isinstance(d, pr.ExprStmt):
try:
expression_list = d.assignment_details[0][0]
name = expression_list[0].name.names[-1]
except IndexError:
return None
elif isinstance(d, iterable.Generator):
return None
elif isinstance(d, pr.NamePart):
name = d
return unicode(name)
@property @property
def description(self): def description(self):
""" """
@@ -649,7 +603,7 @@ class Definition(use_metaclass(CachedMetaClass, BaseDefinition)):
'class C' 'class C'
""" """
d = self._definition d = self._name
if isinstance(d, er.InstanceElement): if isinstance(d, er.InstanceElement):
d = d.var d = d.var
if isinstance(d, (pr.Name, pr.NamePart)): if isinstance(d, (pr.Name, pr.NamePart)):
@@ -710,17 +664,17 @@ class Definition(use_metaclass(CachedMetaClass, BaseDefinition)):
Returns True, if defined as a name in a statement, function or class. Returns True, if defined as a name in a statement, function or class.
Returns False, if it's a reference to such a definition. Returns False, if it's a reference to such a definition.
""" """
if isinstance(self._definition, compiled.CompiledName): if isinstance(self._name, compiled.CompiledName):
return True return True
if not isinstance(self._definition, pr.NamePart): if not isinstance(self._name, pr.NamePart):
# Currently only handle NameParts. Once we have a proper API, this # Currently only handle NameParts. Once we have a proper API, this
# will be the standard anyway. # will be the standard anyway.
raise NotImplementedError raise NotImplementedError
_def = self._definition.get_parent_until((pr.ExprStmt, _def = self._name.get_parent_until((pr.ExprStmt,
pr.Import, pr.Function, pr.Class, pr.Module)) pr.Import, pr.Function, pr.Class, pr.Module))
if isinstance(_def, pr.ExprStmt): if isinstance(_def, pr.ExprStmt):
exp_list = _def.expression_list() exp_list = _def.expression_list()
return not exp_list or self._definition.start_pos < exp_list[0].start_pos return not exp_list or self._name.start_pos < exp_list[0].start_pos
else: else:
return True return True
@@ -743,8 +697,8 @@ class CallSignature(Definition):
It knows what functions you are currently in. e.g. `isinstance(` would It knows what functions you are currently in. e.g. `isinstance(` would
return the `isinstance` function. without `(` it would return nothing. return the `isinstance` function. without `(` it would return nothing.
""" """
def __init__(self, evaluator, executable, call, index, key_name): def __init__(self, evaluator, executable_name, call, index, key_name):
super(CallSignature, self).__init__(evaluator, executable) super(CallSignature, self).__init__(evaluator, executable_name)
self._index = index self._index = index
self._key_name = key_name self._key_name = key_name
self._call = call self._call = call
@@ -759,7 +713,7 @@ class CallSignature(Definition):
for i, param in enumerate(self.params): for i, param in enumerate(self.params):
if self._key_name == param.name: if self._key_name == param.name:
return i return i
if self.params and self.params[-1]._definition.get_definition().stars == 2: if self.params and self.params[-1]._name.get_definition().stars == 2:
return i return i
else: else:
return None return None
@@ -768,7 +722,7 @@ class CallSignature(Definition):
for i, param in enumerate(self.params): for i, param in enumerate(self.params):
# *args case # *args case
if param._definition.get_definition().stars == 1: if param._name.get_definition().stars == 1:
return i return i
return None return None
return self._index return self._index
@@ -794,7 +748,7 @@ class CallSignature(Definition):
The name (e.g. 'isinstance') as a string. The name (e.g. 'isinstance') as a string.
""" """
warnings.warn("Use name instead.", DeprecationWarning) warnings.warn("Use name instead.", DeprecationWarning)
return unicode(self._definition.name) return unicode(self.name)
@property @property
def module(self): def module(self):
@@ -806,7 +760,7 @@ class CallSignature(Definition):
return self._executable.get_parent_until() return self._executable.get_parent_until()
def __repr__(self): def __repr__(self):
return '<%s: %s index %s>' % (type(self).__name__, self._definition, return '<%s: %s index %s>' % (type(self).__name__, self._name,
self.index) self.index)
@@ -832,11 +786,11 @@ class _Help(object):
the future. the future.
""" """
def __init__(self, definition): def __init__(self, definition):
self._definition = definition self._name = definition
def full(self): def full(self):
try: try:
return self._definition.doc return self._name.doc
except AttributeError: except AttributeError:
return self.raw() return self.raw()
@@ -847,6 +801,6 @@ class _Help(object):
See :attr:`doc` for example. See :attr:`doc` for example.
""" """
try: try:
return self._definition.raw_doc return self._name.raw_doc
except AttributeError: except AttributeError:
return '' return ''

View File

@@ -5,7 +5,7 @@ from jedi import Script
def get_definition_and_evaluator(source): def get_definition_and_evaluator(source):
d = Script(dedent(source)).goto_definitions()[0] d = Script(dedent(source)).goto_definitions()[0]
return d._definition.parent.parent, d._evaluator return d._name.parent.parent, d._evaluator
def test_function_execution(): def test_function_execution():

View File

@@ -26,4 +26,4 @@ asdfasdf""" + "h"
def test_tokenizer_with_string_literal_backslash(): def test_tokenizer_with_string_literal_backslash():
import jedi import jedi
c = jedi.Script("statement = u'foo\\\n'; statement").goto_definitions() c = jedi.Script("statement = u'foo\\\n'; statement").goto_definitions()
assert c[0]._definition.parent.parent.obj == 'foo' assert c[0]._name.parent.parent.obj == 'foo'