mirror of
https://github.com/davidhalter/jedi.git
synced 2026-01-15 00:16:44 +08:00
Annotations can contain forward references even if they are not a string anymore
Since Python 3.7 this behavior can be imported with from future import __annotations
This commit is contained in:
@@ -216,5 +216,5 @@ class ModuleContext(TreeContext):
|
||||
return "<%s: %s@%s-%s is_stub=%s>" % (
|
||||
self.__class__.__name__, self._string_name,
|
||||
self.tree_node.start_pos[0], self.tree_node.end_pos[0],
|
||||
self._path.endswith('.pyi')
|
||||
self._path is not None and self._path.endswith('.pyi')
|
||||
)
|
||||
|
||||
@@ -110,7 +110,7 @@ class NameFinder(object):
|
||||
ancestor = search_ancestor(origin_scope, 'funcdef', 'classdef')
|
||||
if ancestor is not None:
|
||||
colon = ancestor.children[-2]
|
||||
if position < colon.start_pos:
|
||||
if position is not None and position < colon.start_pos:
|
||||
if lambdef is None or position < lambdef.children[-2].start_pos:
|
||||
position = ancestor.start_pos
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ def _evaluate_annotation_string(context, string, index=None):
|
||||
context_set = context.eval_node(node)
|
||||
if index is not None:
|
||||
context_set = context_set.filter(
|
||||
lambda context: context.array_type == u'tuple'
|
||||
lambda context: context.array_type == u'tuple' # noqa
|
||||
and len(list(context.py__iter__())) >= index
|
||||
).py__getitem__(index)
|
||||
return context_set.execute_evaluated()
|
||||
|
||||
@@ -196,9 +196,17 @@ def eval_atom(context, atom):
|
||||
) or atom
|
||||
if stmt.type == 'lambdef':
|
||||
stmt = atom
|
||||
position = stmt.start_pos
|
||||
if _is_annotation_name(atom):
|
||||
# Since Python 3.7 (with from __future__ import annotations),
|
||||
# annotations are essentially strings and can reference objects
|
||||
# that are defined further down in code. Therefore just set the
|
||||
# position to None, so the finder will not try to stop at a certain
|
||||
# position in the module.
|
||||
position = None
|
||||
return context.py__getattribute__(
|
||||
name_or_str=atom,
|
||||
position=stmt.start_pos,
|
||||
position=position,
|
||||
search_global=True
|
||||
)
|
||||
elif atom.type == 'keyword':
|
||||
@@ -410,6 +418,22 @@ def _eval_comparison(evaluator, context, left_contexts, operator, right_contexts
|
||||
)
|
||||
|
||||
|
||||
def _is_annotation_name(name):
|
||||
ancestor = tree.search_ancestor(name, 'param', 'funcdef', 'expr_stmt')
|
||||
if ancestor is None:
|
||||
return False
|
||||
|
||||
if ancestor.type in ('param', 'funcdef'):
|
||||
annotation = ancestor.annotation
|
||||
if annotation is not None:
|
||||
return annotation.start_pos <= name.start_pos < annotation.end_pos
|
||||
elif ancestor.type == 'expr_stmt':
|
||||
c = ancestor.children
|
||||
if len(c) > 1 and c[1].type == 'annassign':
|
||||
return c[1].start_pos <= name.start_pos < c[1].end_pos
|
||||
return True
|
||||
|
||||
|
||||
def _is_tuple(context):
|
||||
return isinstance(context, iterable.Sequence) and context.array_type == 'tuple'
|
||||
|
||||
@@ -497,7 +521,6 @@ def _remove_statements(evaluator, context, stmt, name):
|
||||
|
||||
|
||||
def tree_name_to_contexts(evaluator, context, tree_name):
|
||||
|
||||
context_set = ContextSet()
|
||||
module_node = context.get_root_context().tree_node
|
||||
if module_node is not None:
|
||||
|
||||
Reference in New Issue
Block a user