Basic implementation support for namedexpr, fixes #1647

This commit is contained in:
Dave Halter
2020-08-05 10:12:47 +02:00
parent 76c0c373da
commit abf63d73d3
6 changed files with 55 additions and 3 deletions

View File

@@ -16,6 +16,7 @@ Unreleased
- Functions with ``@property`` now return ``property`` instead of ``function``
in ``Name().type``
- Started using annotations
- Better support for the walrus operator
- Project attributes are now read accessible
This is likely going to be the last minor release before 1.0.

View File

@@ -170,6 +170,8 @@ class InferenceState:
return tree_name_to_values(self, context, name)
elif type_ == 'param':
return context.py__getattribute__(name.value, position=name.end_pos)
elif type_ == 'namedexpr_test':
return context.infer_node(def_)
else:
result = follow_error_node_imports_if_possible(context, name)
if result is not None:

View File

@@ -753,6 +753,8 @@ def tree_name_to_values(inference_state, context, tree_name):
types = NO_VALUES
elif typ == 'del_stmt':
types = NO_VALUES
elif typ == 'namedexpr_test':
types = infer_node(context, node)
else:
raise ValueError("Should not happen. type: %s" % typ)
return types

View File

@@ -90,7 +90,7 @@ def get_flow_branch_keyword(flow_node, node):
first_leaf = child.get_first_leaf()
if first_leaf in _FLOW_KEYWORDS:
keyword = first_leaf
return 0
return None
def clean_scope_docstring(scope_node):
@@ -239,7 +239,7 @@ def get_parent_scope(node, include_flows=False):
return None # It's a module already.
while True:
if is_scope(scope) or include_flows and isinstance(scope, tree.Flow):
if is_scope(scope):
if scope.type in ('classdef', 'funcdef', 'lambdef'):
index = scope.children.index(':')
if scope.children[index].start_pos >= node.start_pos:
@@ -251,6 +251,14 @@ def get_parent_scope(node, include_flows=False):
scope = scope.parent
continue
return scope
elif include_flows and isinstance(scope, tree.Flow):
# The cursor might be on `if foo`, so the parent scope will not be
# the if, but the parent of the if.
if not (scope.type == 'if_stmt'
and any(n.start_pos <= node.start_pos < n.end_pos
for n in scope.get_test_nodes())):
return scope
scope = scope.parent

View File

@@ -5,7 +5,7 @@
x = 3
if NOT_DEFINED:
x = ''
#? 6 int()
#? 6 int() str()
elif x:
pass
else:

View File

@@ -1,3 +1,6 @@
# For assignment expressions / named expressions / walrus operators / whatever
# they are called.
# python >= 3.8
b = (a:=1, a)
@@ -11,3 +14,39 @@ b = ('':=1,)
#? int()
b[0]
def test_assignments():
match = ''
#? str()
match
#? 8 int()
if match := 1:
#? int()
match
#? int()
match
def test_assignments2():
class Foo:
match = ''
#? str()
Foo.match
#? 13 int()
if Foo.match := 1:
#? str()
Foo.match
#? str()
Foo.match
#?
y
#? 16 str()
if y := Foo.match:
#? str()
y
#? str()
y
#? 8 str()
if z := Foo.match:
pass