forked from VimPlug/jedi
Merge branch 'dev'
This commit is contained in:
@@ -166,14 +166,6 @@ try:
|
||||
except NameError:
|
||||
unicode = str
|
||||
|
||||
if is_py3:
|
||||
u = lambda s: s
|
||||
else:
|
||||
u = lambda s: s.decode('utf-8')
|
||||
|
||||
u.__doc__ = """
|
||||
Decode a raw string into unicode object. Do nothing in Python 3.
|
||||
"""
|
||||
|
||||
# exec function
|
||||
if is_py3:
|
||||
|
||||
@@ -342,7 +342,7 @@ class Script(object):
|
||||
elif isinstance(node, tree.Import):
|
||||
import_names = set(node.get_defined_names())
|
||||
if node.is_nested():
|
||||
import_names |= set(path[-1] for path in node.paths())
|
||||
import_names |= set(path[-1] for path in node.get_paths())
|
||||
for n in import_names:
|
||||
imports.infer_import(context, n)
|
||||
elif node.type == 'expr_stmt':
|
||||
|
||||
@@ -15,7 +15,7 @@ from jedi.evaluate import representation as er
|
||||
from jedi.evaluate import instance
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate.filters import ParamName, TreeNameDefinition
|
||||
from jedi.evaluate.filters import ParamName
|
||||
from jedi.evaluate.imports import ImportName
|
||||
from jedi.api.keywords import KeywordName
|
||||
|
||||
@@ -538,7 +538,12 @@ class Definition(BaseDefinition):
|
||||
typ = 'def'
|
||||
return typ + ' ' + u(self._name.string_name)
|
||||
elif typ == 'param':
|
||||
return typ + ' ' + tree_name.get_definition().get_description()
|
||||
code = tree_name.get_definition().get_code(
|
||||
include_prefix=False,
|
||||
include_comma=False
|
||||
)
|
||||
return typ + ' ' + code
|
||||
|
||||
|
||||
definition = tree_name.get_definition()
|
||||
# Remove the prefix, because that's not what we want for get_code
|
||||
|
||||
@@ -76,12 +76,16 @@ class KeywordName(AbstractNameDefinition):
|
||||
api_type = 'keyword'
|
||||
|
||||
def __init__(self, evaluator, name):
|
||||
self.evaluator = evaluator
|
||||
self.string_name = name
|
||||
self.parent_context = evaluator.BUILTINS
|
||||
|
||||
def eval(self):
|
||||
return set()
|
||||
|
||||
def infer(self):
|
||||
return [Keyword(self.evaluator, self.string_name, (0, 0))]
|
||||
|
||||
|
||||
class Keyword(object):
|
||||
api_type = 'keyword'
|
||||
@@ -100,9 +104,8 @@ class Keyword(object):
|
||||
""" For a `parsing.Name` like comparision """
|
||||
return [self.name]
|
||||
|
||||
@property
|
||||
def docstr(self):
|
||||
return imitate_pydoc(self.name)
|
||||
def py__doc__(self, include_call_signature=False):
|
||||
return imitate_pydoc(self.name.string_name)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s: %s>' % (type(self).__name__, self.name)
|
||||
@@ -136,6 +139,6 @@ def imitate_pydoc(string):
|
||||
return ''
|
||||
|
||||
try:
|
||||
return pydoc_topics.topics[label] if pydoc_topics else ''
|
||||
return pydoc_topics.topics[label].strip() if pydoc_topics else ''
|
||||
except KeyError:
|
||||
return ''
|
||||
|
||||
@@ -194,7 +194,7 @@ class Evaluator(object):
|
||||
if_stmt = if_stmt.parent
|
||||
if if_stmt.type in ('if_stmt', 'for_stmt'):
|
||||
break
|
||||
if if_stmt.is_scope():
|
||||
if parser_utils.is_scope(if_stmt):
|
||||
if_stmt = None
|
||||
break
|
||||
predefined_if_name_dict = context.predefined_names.get(if_stmt)
|
||||
@@ -337,7 +337,7 @@ class Evaluator(object):
|
||||
# This is the first global lookup.
|
||||
stmt = atom.get_definition()
|
||||
if stmt.type == 'comp_for':
|
||||
stmt = tree.search_ancestor(stmt, ('expr_stmt', 'lambdef', 'funcdef', 'classdef'))
|
||||
stmt = tree.search_ancestor(stmt, 'expr_stmt', 'lambdef', 'funcdef', 'classdef')
|
||||
if stmt is None or stmt.type != 'expr_stmt':
|
||||
# We only need to adjust the start_pos for statements, because
|
||||
# there the name cannot be used.
|
||||
@@ -537,7 +537,7 @@ class Evaluator(object):
|
||||
while True:
|
||||
node = node.parent
|
||||
|
||||
if node.is_scope():
|
||||
if parser_utils.is_scope(node):
|
||||
return node
|
||||
elif node.type in ('argument', 'testlist_comp'):
|
||||
if node.children[1].type == 'comp_for':
|
||||
@@ -553,7 +553,7 @@ class Evaluator(object):
|
||||
return base_context
|
||||
|
||||
is_funcdef = scope_node.type in ('funcdef', 'lambdef')
|
||||
parent_scope = scope_node.get_parent_scope()
|
||||
parent_scope = parser_utils.get_parent_scope(scope_node)
|
||||
parent_context = from_scope_node(parent_scope, child_is_funcdef=is_funcdef)
|
||||
|
||||
if is_funcdef:
|
||||
@@ -586,7 +586,7 @@ class Evaluator(object):
|
||||
|
||||
base_node = base_context.tree_node
|
||||
|
||||
if node_is_context and node.is_scope():
|
||||
if node_is_context and parser_utils.is_scope(node):
|
||||
scope_node = node
|
||||
else:
|
||||
if node.parent.type in ('funcdef', 'classdef'):
|
||||
|
||||
@@ -222,9 +222,6 @@ class CompiledObject(Context):
|
||||
for result in self.evaluator.execute(bltn_obj, params):
|
||||
yield result
|
||||
|
||||
def is_scope(self):
|
||||
return True
|
||||
|
||||
def get_self_attributes(self):
|
||||
return [] # Instance compatibility
|
||||
|
||||
|
||||
@@ -116,8 +116,21 @@ def _load_module(evaluator, path, python_object):
|
||||
return module
|
||||
|
||||
|
||||
def source_findable(python_object):
|
||||
"""Check if inspect.getfile has a chance to find the source."""
|
||||
return (inspect.ismodule(python_object) or
|
||||
inspect.isclass(python_object) or
|
||||
inspect.ismethod(python_object) or
|
||||
inspect.isfunction(python_object) or
|
||||
inspect.istraceback(python_object) or
|
||||
inspect.isframe(python_object) or
|
||||
inspect.iscode(python_object))
|
||||
|
||||
|
||||
def find_syntax_node_name(evaluator, python_object):
|
||||
try:
|
||||
if not source_findable(python_object):
|
||||
raise TypeError # Prevents computation of `repr` within inspect.
|
||||
path = inspect.getsourcefile(python_object)
|
||||
except TypeError:
|
||||
# The type might not be known (e.g. class_with_dict.__weakref__)
|
||||
|
||||
@@ -24,6 +24,7 @@ from jedi.evaluate.cache import memoize_default
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate.param import TreeArguments, create_default_param
|
||||
from jedi.common import to_list, unite
|
||||
from jedi.parser_utils import get_parent_scope
|
||||
|
||||
|
||||
MAX_PARAM_SEARCHES = 20
|
||||
@@ -103,7 +104,7 @@ def _search_function_executions(evaluator, module_context, funcdef):
|
||||
func_string_name = funcdef.name.value
|
||||
compare_node = funcdef
|
||||
if func_string_name == '__init__':
|
||||
cls = funcdef.get_parent_scope()
|
||||
cls = get_parent_scope(funcdef)
|
||||
if isinstance(cls, tree.Class):
|
||||
func_string_name = cls.name.value
|
||||
compare_node = cls
|
||||
|
||||
@@ -7,6 +7,7 @@ from abc import abstractmethod
|
||||
from jedi.parser.tree import search_ancestor
|
||||
from jedi.evaluate import flow_analysis
|
||||
from jedi.common import to_list, unite
|
||||
from jedi.parser_utils import get_parent_scope
|
||||
|
||||
|
||||
class AbstractNameDefinition(object):
|
||||
@@ -189,7 +190,7 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
||||
if parent.type == 'trailer':
|
||||
return False
|
||||
base_node = parent if parent.type in ('classdef', 'funcdef') else name
|
||||
return base_node.get_parent_scope() == self._parser_scope
|
||||
return get_parent_scope(base_node) == self._parser_scope
|
||||
|
||||
def _check_flows(self, names):
|
||||
for name in sorted(names, key=lambda name: name.start_pos, reverse=True):
|
||||
|
||||
@@ -32,6 +32,7 @@ from jedi.evaluate import param
|
||||
from jedi.evaluate import helpers
|
||||
from jedi.evaluate.filters import get_global_filters
|
||||
from jedi.evaluate.context import ContextualizedName, ContextualizedNode
|
||||
from jedi.parser_utils import is_scope, get_parent_scope
|
||||
|
||||
|
||||
class NameFinder(object):
|
||||
@@ -106,7 +107,7 @@ class NameFinder(object):
|
||||
if self._context.predefined_names:
|
||||
# TODO is this ok? node might not always be a tree.Name
|
||||
node = self._name
|
||||
while node is not None and not node.is_scope():
|
||||
while node is not None and not is_scope(node):
|
||||
node = node.parent
|
||||
if node.type in ("if_stmt", "for_stmt", "comp_for"):
|
||||
try:
|
||||
@@ -160,7 +161,7 @@ class NameFinder(object):
|
||||
if base_node.type == 'comp_for':
|
||||
return types
|
||||
while True:
|
||||
flow_scope = flow_scope.get_parent_scope(include_flows=True)
|
||||
flow_scope = get_parent_scope(flow_scope, include_flows=True)
|
||||
n = _check_flow_information(self._name_context, flow_scope,
|
||||
self._name, self._position)
|
||||
if n is not None:
|
||||
@@ -298,7 +299,7 @@ def _check_flow_information(context, flow, search_name, pos):
|
||||
return None
|
||||
|
||||
result = None
|
||||
if flow.is_scope():
|
||||
if is_scope(flow):
|
||||
# Check for asserts.
|
||||
module_node = flow.get_root_node()
|
||||
try:
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from jedi.parser_utils import get_flow_branch_keyword
|
||||
from jedi.parser_utils import get_flow_branch_keyword, is_scope, get_parent_scope
|
||||
|
||||
|
||||
class Status(object):
|
||||
lookup_table = {}
|
||||
|
||||
@@ -32,14 +34,14 @@ UNSURE = Status(None, 'unsure')
|
||||
|
||||
def _get_flow_scopes(node):
|
||||
while True:
|
||||
node = node.get_parent_scope(include_flows=True)
|
||||
if node is None or node.is_scope():
|
||||
node = get_parent_scope(node, include_flows=True)
|
||||
if node is None or is_scope(node):
|
||||
return
|
||||
yield node
|
||||
|
||||
|
||||
def reachability_check(context, context_scope, node, origin_scope=None):
|
||||
first_flow_scope = node.get_parent_scope(include_flows=True)
|
||||
first_flow_scope = get_parent_scope(node, include_flows=True)
|
||||
if origin_scope is not None:
|
||||
origin_flow_scopes = list(_get_flow_scopes(origin_scope))
|
||||
node_flow_scopes = list(_get_flow_scopes(node))
|
||||
@@ -95,7 +97,7 @@ def _break_check(context, context_scope, flow_scope, node):
|
||||
return reachable
|
||||
|
||||
if context_scope != flow_scope and context_scope != flow_scope.parent:
|
||||
flow_scope = flow_scope.get_parent_scope(include_flows=True)
|
||||
flow_scope = get_parent_scope(flow_scope, include_flows=True)
|
||||
return reachable & _break_check(context, context_scope, flow_scope, node)
|
||||
else:
|
||||
return reachable
|
||||
|
||||
@@ -3,6 +3,7 @@ from itertools import chain
|
||||
from contextlib import contextmanager
|
||||
|
||||
from jedi.parser.python import tree
|
||||
from jedi.parser_utils import get_parent_scope
|
||||
|
||||
|
||||
def deep_ast_copy(obj):
|
||||
@@ -143,7 +144,7 @@ def get_module_names(module, all_scopes):
|
||||
# parent_scope. There's None as a parent, because nodes in the module
|
||||
# node have the parent module and not suite as all the others.
|
||||
# Therefore it's important to catch that case.
|
||||
names = [n for n in names if n.get_parent_scope().parent in (module, None)]
|
||||
names = [n for n in names if get_parent_scope(n).parent in (module, None)]
|
||||
return names
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ from jedi.evaluate.filters import AbstractNameDefinition
|
||||
@memoize_default(default=set())
|
||||
def infer_import(context, tree_name, is_goto=False):
|
||||
module_context = context.get_root_context()
|
||||
import_node = search_ancestor(tree_name, ('import_name', 'import_from'))
|
||||
import_node = search_ancestor(tree_name, 'import_name', 'import_from')
|
||||
import_path = import_node.get_path_for_name(tree_name)
|
||||
from_import_name = None
|
||||
evaluator = context.evaluator
|
||||
|
||||
@@ -11,6 +11,7 @@ from jedi.cache import memoize_method
|
||||
from jedi.evaluate import representation as er
|
||||
from jedi.evaluate.dynamic import search_params
|
||||
from jedi.evaluate import iterable
|
||||
from jedi.parser_utils import get_parent_scope
|
||||
|
||||
|
||||
class AbstractInstanceContext(Context):
|
||||
@@ -151,7 +152,7 @@ class AbstractInstanceContext(Context):
|
||||
def create_instance_context(self, class_context, node):
|
||||
if node.parent.type in ('funcdef', 'classdef'):
|
||||
node = node.parent
|
||||
scope = node.get_parent_scope()
|
||||
scope = get_parent_scope(node)
|
||||
if scope == class_context.tree_node:
|
||||
return class_context
|
||||
else:
|
||||
@@ -189,13 +190,18 @@ class CompiledInstance(AbstractInstanceContext):
|
||||
return compiled.CompiledContextName(self, self.class_context.name.string_name)
|
||||
|
||||
def create_instance_context(self, class_context, node):
|
||||
if node.get_parent_scope().type == 'classdef':
|
||||
if get_parent_scope(node).type == 'classdef':
|
||||
return class_context
|
||||
else:
|
||||
return super(CompiledInstance, self).create_instance_context(class_context, node)
|
||||
|
||||
|
||||
class TreeInstance(AbstractInstanceContext):
|
||||
def __init__(self, evaluator, parent_context, class_context, var_args):
|
||||
super(TreeInstance, self).__init__(evaluator, parent_context,
|
||||
class_context, var_args)
|
||||
self.tree_node = class_context.tree_node
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return filters.ContextName(self, self.class_context.name.tree_name)
|
||||
@@ -332,7 +338,7 @@ class InstanceClassFilter(filters.ParserTreeFilter):
|
||||
while node is not None:
|
||||
if node == self._parser_scope or node == self.context:
|
||||
return True
|
||||
node = node.get_parent_scope()
|
||||
node = get_parent_scope(node)
|
||||
return False
|
||||
|
||||
def _access_possible(self, name):
|
||||
|
||||
@@ -276,7 +276,7 @@ class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
||||
def py__class__(self):
|
||||
# This differentiation is only necessary for Python2. Python3 does not
|
||||
# use a different method class.
|
||||
if isinstance(self.tree_node.get_parent_scope(), tree.Class):
|
||||
if isinstance(parser_utils.get_parent_scope(self.tree_node), tree.Class):
|
||||
name = 'METHOD_CLASS'
|
||||
else:
|
||||
name = 'FUNCTION_CLASS'
|
||||
@@ -350,8 +350,8 @@ class FunctionExecutionContext(context.TreeContext):
|
||||
|
||||
@recursion.execution_recursion_decorator(default=iter([]))
|
||||
def get_yield_values(self):
|
||||
for_parents = [(y, tree.search_ancestor(y, ('for_stmt', 'funcdef',
|
||||
'while_stmt', 'if_stmt')))
|
||||
for_parents = [(y, tree.search_ancestor(y, 'for_stmt', 'funcdef',
|
||||
'while_stmt', 'if_stmt'))
|
||||
for y in self.tree_node.iter_yield_exprs()]
|
||||
|
||||
# Calculate if the yields are placed within the same for loop.
|
||||
@@ -476,7 +476,7 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
||||
modules = []
|
||||
for i in self.tree_node.iter_imports():
|
||||
if i.is_star_import():
|
||||
name = i.star_import_name()
|
||||
name = i.get_paths()[-1][-1]
|
||||
new = imports.infer_import(self, name)
|
||||
for module in new:
|
||||
if isinstance(module, ModuleContext):
|
||||
|
||||
@@ -74,9 +74,6 @@ def parse(code=None, path=None, grammar=None, error_recovery=True,
|
||||
if grammar is None:
|
||||
grammar = load_grammar()
|
||||
|
||||
if path is not None:
|
||||
path = os.path.expanduser(path)
|
||||
|
||||
if cache and not code and path is not None:
|
||||
# In this case we do actual caching. We just try to load it.
|
||||
module_node = load_module(grammar, path)
|
||||
|
||||
@@ -144,22 +144,9 @@ class Parser(BaseParser):
|
||||
elif symbol == 'suite' and len(nodes) > 1:
|
||||
# suites without an indent in them get discarded.
|
||||
break
|
||||
elif symbol == 'simple_stmt' and len(nodes) > 1:
|
||||
# simple_stmt can just be turned into a PythonNode, if
|
||||
# there are enough statements. Ignore the rest after that.
|
||||
break
|
||||
return index, symbol, nodes
|
||||
|
||||
index, symbol, nodes = current_suite(stack)
|
||||
if symbol == 'simple_stmt':
|
||||
index -= 2
|
||||
(_, _, (type_, suite_nodes)) = stack[index]
|
||||
symbol = grammar.number2symbol[type_]
|
||||
suite_nodes.append(tree.PythonNode(symbol, list(nodes)))
|
||||
# Remove
|
||||
nodes[:] = []
|
||||
nodes = suite_nodes
|
||||
stack[index]
|
||||
|
||||
# print('err', token.tok_name[typ], repr(value), start_pos, len(stack), index)
|
||||
if self._stack_removal(grammar, stack, arcs, index + 1, value, start_pos):
|
||||
|
||||
@@ -25,8 +25,6 @@ Any subclasses of :class:`Scope`, including :class:`Module` has an attribute
|
||||
[<ImportName: import os@1,0>]
|
||||
"""
|
||||
|
||||
from itertools import chain
|
||||
|
||||
from jedi._compatibility import utf8_repr, unicode
|
||||
from jedi.parser.tree import Node, BaseNode, Leaf, ErrorNode, ErrorLeaf, \
|
||||
search_ancestor
|
||||
@@ -61,18 +59,10 @@ class DocstringMixin(object):
|
||||
|
||||
|
||||
class PythonMixin(object):
|
||||
def get_parent_scope(self, include_flows=False):
|
||||
"""
|
||||
Returns the underlying scope.
|
||||
"""
|
||||
scope = self.parent
|
||||
while scope is not None:
|
||||
if include_flows and isinstance(scope, Flow):
|
||||
return scope
|
||||
if scope.is_scope():
|
||||
break
|
||||
scope = scope.parent
|
||||
return scope
|
||||
"""
|
||||
Some Python specific utitilies.
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
def get_definition(self):
|
||||
if self.type in ('newline', 'endmarker'):
|
||||
@@ -92,10 +82,6 @@ class PythonMixin(object):
|
||||
break
|
||||
return scope
|
||||
|
||||
def is_scope(self):
|
||||
# Default is not being a scope. Just inherit from Scope.
|
||||
return False
|
||||
|
||||
def get_name_of_position(self, position):
|
||||
for c in self.children:
|
||||
if isinstance(c, Leaf):
|
||||
@@ -269,9 +255,6 @@ class Scope(PythonBaseNode, DocstringMixin):
|
||||
|
||||
return scan(self.children)
|
||||
|
||||
def is_scope(self):
|
||||
return True
|
||||
|
||||
def get_suite(self):
|
||||
"""
|
||||
Returns the part that is executed by the function.
|
||||
@@ -311,7 +294,7 @@ class Module(Scope):
|
||||
# the future print statement).
|
||||
for imp in self.iter_imports():
|
||||
if imp.type == 'import_from' and imp.level == 0:
|
||||
for path in imp.paths():
|
||||
for path in imp.get_paths():
|
||||
names = [name.value for name in path]
|
||||
if len(names) == 2 and names[0] == '__future__':
|
||||
yield names[1]
|
||||
@@ -328,6 +311,10 @@ class Module(Scope):
|
||||
return False
|
||||
|
||||
def get_used_names(self):
|
||||
"""
|
||||
Returns all the `Name` leafs that exist in this module. Tihs includes
|
||||
both definitions and references of names.
|
||||
"""
|
||||
if self._used_names is None:
|
||||
# Don't directly use self._used_names to eliminate a lookup.
|
||||
dct = {}
|
||||
@@ -358,9 +345,15 @@ class ClassOrFunc(Scope):
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Returns the `Name` leaf that defines the function or class name.
|
||||
"""
|
||||
return self.children[1]
|
||||
|
||||
def get_decorators(self):
|
||||
"""
|
||||
:return list of Decorator:
|
||||
"""
|
||||
decorated = self.parent
|
||||
if decorated.type == 'decorated':
|
||||
if decorated.children[0].type == 'decorators':
|
||||
@@ -389,6 +382,10 @@ class Class(ClassOrFunc):
|
||||
super(Class, self).__init__(children)
|
||||
|
||||
def get_super_arglist(self):
|
||||
"""
|
||||
Returns the `arglist` node that defines the super classes. It returns
|
||||
None if there are no arguments.
|
||||
"""
|
||||
if self.children[2] != '(': # Has no parentheses
|
||||
return None
|
||||
else:
|
||||
@@ -452,14 +449,15 @@ class Function(ClassOrFunc):
|
||||
"""
|
||||
Used to store the parsed contents of a python function.
|
||||
|
||||
Children:
|
||||
0. <Keyword: def>
|
||||
1. <Name>
|
||||
2. parameter list (including open-paren and close-paren <Operator>s)
|
||||
3. or 5. <Operator: :>
|
||||
4. or 6. Node() representing function body
|
||||
3. -> (if annotation is also present)
|
||||
4. annotation (if present)
|
||||
Children::
|
||||
|
||||
0. <Keyword: def>
|
||||
1. <Name>
|
||||
2. parameter list (including open-paren and close-paren <Operator>s)
|
||||
3. or 5. <Operator: :>
|
||||
4. or 6. Node() representing function body
|
||||
3. -> (if annotation is also present)
|
||||
4. annotation (if present)
|
||||
"""
|
||||
type = 'funcdef'
|
||||
|
||||
@@ -514,20 +512,16 @@ class Function(ClassOrFunc):
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def _get_paramlist_code(self):
|
||||
return self.children[2].get_code()
|
||||
|
||||
|
||||
class Lambda(Function):
|
||||
"""
|
||||
Lambdas are basically trimmed functions, so give it the same interface.
|
||||
|
||||
Children:
|
||||
Children::
|
||||
|
||||
0. <Keyword: lambda>
|
||||
*. <Param x> for each argument x
|
||||
-2. <Operator: :>
|
||||
-1. Node() representing body
|
||||
0. <Keyword: lambda>
|
||||
*. <Param x> for each argument x
|
||||
-2. <Operator: :>
|
||||
-1. Node() representing body
|
||||
"""
|
||||
type = 'lambdef'
|
||||
__slots__ = ()
|
||||
@@ -545,9 +539,6 @@ class Lambda(Function):
|
||||
"""
|
||||
raise AttributeError("lambda is not named.")
|
||||
|
||||
def _get_paramlist_code(self):
|
||||
return '(' + ''.join(param.get_code() for param in self.params).strip() + ')'
|
||||
|
||||
def _get_param_nodes(self):
|
||||
return self.children[1:-2]
|
||||
|
||||
@@ -556,7 +547,6 @@ class Lambda(Function):
|
||||
"""
|
||||
Returns `None`, lambdas don't have annotations.
|
||||
"""
|
||||
# lambda functions do not support annotations
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
@@ -650,6 +640,10 @@ class WithStmt(Flow):
|
||||
__slots__ = ()
|
||||
|
||||
def get_defined_names(self):
|
||||
"""
|
||||
Returns the a list of `Name` that the with statement defines. The
|
||||
defined names are set after `as`.
|
||||
"""
|
||||
names = []
|
||||
for with_item in self.children[1:-2:2]:
|
||||
# Check with items for 'as' names.
|
||||
@@ -669,13 +663,18 @@ class Import(PythonBaseNode):
|
||||
__slots__ = ()
|
||||
|
||||
def get_path_for_name(self, name):
|
||||
"""
|
||||
The path is the list of names that leads to the searched name.
|
||||
|
||||
:return list of Name:
|
||||
"""
|
||||
try:
|
||||
# The name may be an alias. If it is, just map it back to the name.
|
||||
name = self.aliases()[name]
|
||||
name = self._aliases()[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for path in self.paths():
|
||||
for path in self.get_paths():
|
||||
if name in path:
|
||||
return path[:path.index(name) + 1]
|
||||
raise ValueError('Name should be defined in the import itself')
|
||||
@@ -692,9 +691,14 @@ class ImportFrom(Import):
|
||||
__slots__ = ()
|
||||
|
||||
def get_defined_names(self):
|
||||
"""
|
||||
Returns the a list of `Name` that the import defines. The
|
||||
defined names are set after `import` or in case an alias - `as` - is
|
||||
present that name is returned.
|
||||
"""
|
||||
return [alias or name for name, alias in self._as_name_tuples()]
|
||||
|
||||
def aliases(self):
|
||||
def _aliases(self):
|
||||
"""Mapping from alias to its corresponding name."""
|
||||
return dict((alias, name) for name, alias in self._as_name_tuples()
|
||||
if alias is not None)
|
||||
@@ -738,16 +742,12 @@ class ImportFrom(Import):
|
||||
else:
|
||||
yield as_name.children[::2] # yields x, y -> ``x as y``
|
||||
|
||||
def star_import_name(self):
|
||||
"""
|
||||
The last name defined in a star import.
|
||||
"""
|
||||
return self.paths()[-1][-1]
|
||||
|
||||
def paths(self):
|
||||
def get_paths(self):
|
||||
"""
|
||||
The import paths defined in an import statement. Typically an array
|
||||
like this: ``[<Name: datetime>, <Name: date>]``.
|
||||
|
||||
:return list of list of Name:
|
||||
"""
|
||||
dotted = self.get_from_names()
|
||||
|
||||
@@ -762,6 +762,11 @@ class ImportName(Import):
|
||||
__slots__ = ()
|
||||
|
||||
def get_defined_names(self):
|
||||
"""
|
||||
Returns the a list of `Name` that the import defines. The defined names
|
||||
is always the first name after `import` or in case an alias - `as` - is
|
||||
present that name is returned.
|
||||
"""
|
||||
return [alias or path[0] for path, alias in self._dotted_as_names()]
|
||||
|
||||
@property
|
||||
@@ -769,7 +774,7 @@ class ImportName(Import):
|
||||
"""The level parameter of ``__import__``."""
|
||||
return 0 # Obviously 0 for imports without from.
|
||||
|
||||
def paths(self):
|
||||
def get_paths(self):
|
||||
return [path for path, alias in self._dotted_as_names()]
|
||||
|
||||
def _dotted_as_names(self):
|
||||
@@ -799,10 +804,13 @@ class ImportName(Import):
|
||||
|
||||
import foo.bar
|
||||
"""
|
||||
return [1 for path, alias in self._dotted_as_names()
|
||||
if alias is None and len(path) > 1]
|
||||
return bool([1 for path, alias in self._dotted_as_names()
|
||||
if alias is None and len(path) > 1])
|
||||
|
||||
def aliases(self):
|
||||
def _aliases(self):
|
||||
"""
|
||||
:return list of Name: Returns all the alias
|
||||
"""
|
||||
return dict((alias, path[-1]) for path, alias in self._dotted_as_names()
|
||||
if alias is not None)
|
||||
|
||||
@@ -880,14 +888,18 @@ class ExprStmt(PythonBaseNode, DocstringMixin):
|
||||
__slots__ = ()
|
||||
|
||||
def get_defined_names(self):
|
||||
"""
|
||||
Returns a list of `Name` defined before the `=` sign.
|
||||
"""
|
||||
names = []
|
||||
if self.children[1].type == 'annassign':
|
||||
names = _defined_names(self.children[0])
|
||||
return list(chain.from_iterable(
|
||||
_defined_names(self.children[i])
|
||||
return [
|
||||
name
|
||||
for i in range(0, len(self.children) - 2, 2)
|
||||
if '=' in self.children[i + 1].value)
|
||||
) + names
|
||||
if '=' in self.children[i + 1].value
|
||||
for name in _defined_names(self.children[i])
|
||||
] + names
|
||||
|
||||
def get_rhs(self):
|
||||
"""Returns the right-hand-side of the equals."""
|
||||
@@ -925,6 +937,10 @@ class Param(PythonBaseNode):
|
||||
|
||||
@property
|
||||
def star_count(self):
|
||||
"""
|
||||
Is `0` in case of `foo`, `1` in case of `*foo` or `2` in case of
|
||||
`**foo`.
|
||||
"""
|
||||
first = self.children[0]
|
||||
if first in ('*', '**'):
|
||||
return len(first.value)
|
||||
@@ -932,6 +948,10 @@ class Param(PythonBaseNode):
|
||||
|
||||
@property
|
||||
def default(self):
|
||||
"""
|
||||
The default is the test node that appears after the `=`. Is `None` in
|
||||
case no default is present.
|
||||
"""
|
||||
try:
|
||||
return self.children[int(self.children[0] in ('*', '**')) + 2]
|
||||
except IndexError:
|
||||
@@ -939,6 +959,10 @@ class Param(PythonBaseNode):
|
||||
|
||||
@property
|
||||
def annotation(self):
|
||||
"""
|
||||
The default is the test node that appears after `->`. Is `None` in case
|
||||
no annotation is present.
|
||||
"""
|
||||
tfpdef = self._tfpdef()
|
||||
if tfpdef.type == 'tfpdef':
|
||||
assert tfpdef.children[1] == ":"
|
||||
@@ -957,6 +981,9 @@ class Param(PythonBaseNode):
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
The `Name` leaf of the param.
|
||||
"""
|
||||
if self._tfpdef().type == 'tfpdef':
|
||||
return self._tfpdef().children[0]
|
||||
else:
|
||||
@@ -965,7 +992,7 @@ class Param(PythonBaseNode):
|
||||
@property
|
||||
def position_index(self):
|
||||
"""
|
||||
Returns the positional index of a paramter.
|
||||
Property for the positional index of a paramter.
|
||||
"""
|
||||
index = self.parent.children.index(self)
|
||||
try:
|
||||
@@ -979,16 +1006,28 @@ class Param(PythonBaseNode):
|
||||
|
||||
def get_parent_function(self):
|
||||
"""
|
||||
Returns the function/lambda a paramter is defined in.
|
||||
Returns the function/lambda of a parameter.
|
||||
"""
|
||||
return search_ancestor(self, ('funcdef', 'lambdef'))
|
||||
return search_ancestor(self, 'funcdef', 'lambdef')
|
||||
|
||||
def get_code(self, normalized=False, include_prefix=True, include_comma=True):
|
||||
"""
|
||||
Like all the other get_code functions, but includes the param
|
||||
`include_comma`.
|
||||
|
||||
:param include_comma bool: If enabled includes the comma in the string output.
|
||||
"""
|
||||
if include_comma:
|
||||
return super(Param, self).get_code(normalized, include_prefix)
|
||||
|
||||
def get_description(self):
|
||||
# TODO Remove?
|
||||
children = self.children
|
||||
if children[-1] == ',':
|
||||
children = children[:-1]
|
||||
return self._get_code_for_children(children, False, False)
|
||||
return self._get_code_for_children(
|
||||
children,
|
||||
normalized=False,
|
||||
include_prefix=include_prefix
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
default = '' if self.default is None else '=%s' % self.default.get_code()
|
||||
@@ -999,8 +1038,8 @@ class CompFor(PythonBaseNode):
|
||||
type = 'comp_for'
|
||||
__slots__ = ()
|
||||
|
||||
def is_scope(self):
|
||||
return True
|
||||
|
||||
def get_defined_names(self):
|
||||
"""
|
||||
Returns the a list of `Name` that the comprehension defines.
|
||||
"""
|
||||
return _defined_names(self.children[1])
|
||||
|
||||
@@ -2,21 +2,18 @@ from abc import abstractmethod, abstractproperty
|
||||
from jedi._compatibility import utf8_repr, encoding, is_py3
|
||||
|
||||
|
||||
def search_ancestor(node, node_type_or_types):
|
||||
def search_ancestor(node, *node_types):
|
||||
"""
|
||||
Recursively looks at the parents of a node and checks if the type names
|
||||
match.
|
||||
|
||||
:param node: The node that is looked at.
|
||||
:param node_type_or_types: A tuple or a string of type names that are
|
||||
:param node_types: A tuple or a string of type names that are
|
||||
searched for.
|
||||
"""
|
||||
if not isinstance(node_type_or_types, (list, tuple)):
|
||||
node_type_or_types = (node_type_or_types,)
|
||||
|
||||
while True:
|
||||
node = node.parent
|
||||
if node is None or node.type in node_type_or_types:
|
||||
if node is None or node.type in node_types:
|
||||
return node
|
||||
|
||||
|
||||
|
||||
@@ -154,7 +154,12 @@ def get_call_signature(funcdef, width=72, call_string=None):
|
||||
call_string = '<lambda>'
|
||||
else:
|
||||
call_string = funcdef.name.value
|
||||
code = call_string + funcdef._get_paramlist_code()
|
||||
if funcdef.type == 'lambdef':
|
||||
p = '(' + ''.join(param.get_code() for param in funcdef.params).strip() + ')'
|
||||
else:
|
||||
p = funcdef.children[2].get_code()
|
||||
code = call_string + p
|
||||
|
||||
return '\n'.join(textwrap.wrap(code, width))
|
||||
|
||||
|
||||
@@ -217,3 +222,21 @@ def get_following_comment_same_line(node):
|
||||
comment = comment[:comment.index("\n")]
|
||||
return comment
|
||||
|
||||
|
||||
def is_scope(node):
|
||||
return node.type in ('file_input', 'classdef', 'funcdef', 'lambdef', 'comp_for')
|
||||
|
||||
|
||||
def get_parent_scope(node, include_flows=False):
|
||||
"""
|
||||
Returns the underlying scope.
|
||||
"""
|
||||
scope = node.parent
|
||||
while scope is not None:
|
||||
if include_flows and isinstance(scope, tree.Flow):
|
||||
return scope
|
||||
if is_scope(scope):
|
||||
break
|
||||
scope = scope.parent
|
||||
return scope
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ else:
|
||||
'jedi')
|
||||
cache_directory = os.path.expanduser(_cache_directory)
|
||||
"""
|
||||
The path where all the caches can be found.
|
||||
The path where the cache is stored.
|
||||
|
||||
On Linux, this defaults to ``~/.cache/jedi/``, on OS X to
|
||||
``~/Library/Caches/Jedi/`` and on Windows to ``%APPDATA%\\Jedi\\Jedi\\``.
|
||||
|
||||
Reference in New Issue
Block a user