bpo-38469: Handle named expression scope with global/nonlocal keywords (GH-16755)
The symbol table handing of PEP572's assignment expressions is not resolving correctly the scope of some variables in presence of global/nonlocal keywords in conjunction with comprehensions.
This commit is contained in:
parent
8a6cbf8adb
commit
fd5c414880
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import unittest
|
||||
|
||||
GLOBAL_VAR = None
|
||||
|
||||
class NamedExpressionInvalidTest(unittest.TestCase):
|
||||
|
||||
|
@ -470,5 +471,49 @@ spam()"""
|
|||
self.assertEqual(ns["x"], 2)
|
||||
self.assertEqual(ns["result"], [0, 1, 2])
|
||||
|
||||
def test_named_expression_global_scope(self):
|
||||
sentinel = object()
|
||||
global GLOBAL_VAR
|
||||
def f():
|
||||
global GLOBAL_VAR
|
||||
[GLOBAL_VAR := sentinel for _ in range(1)]
|
||||
self.assertEqual(GLOBAL_VAR, sentinel)
|
||||
try:
|
||||
f()
|
||||
self.assertEqual(GLOBAL_VAR, sentinel)
|
||||
finally:
|
||||
GLOBAL_VAR = None
|
||||
|
||||
def test_named_expression_global_scope_no_global_keyword(self):
|
||||
sentinel = object()
|
||||
def f():
|
||||
GLOBAL_VAR = None
|
||||
[GLOBAL_VAR := sentinel for _ in range(1)]
|
||||
self.assertEqual(GLOBAL_VAR, sentinel)
|
||||
f()
|
||||
self.assertEqual(GLOBAL_VAR, None)
|
||||
|
||||
def test_named_expression_nonlocal_scope(self):
|
||||
sentinel = object()
|
||||
def f():
|
||||
nonlocal_var = None
|
||||
def g():
|
||||
nonlocal nonlocal_var
|
||||
[nonlocal_var := sentinel for _ in range(1)]
|
||||
g()
|
||||
self.assertEqual(nonlocal_var, sentinel)
|
||||
f()
|
||||
|
||||
def test_named_expression_nonlocal_scope_no_nonlocal_keyword(self):
|
||||
sentinel = object()
|
||||
def f():
|
||||
nonlocal_var = None
|
||||
def g():
|
||||
[nonlocal_var := sentinel for _ in range(1)]
|
||||
g()
|
||||
self.assertEqual(nonlocal_var, None)
|
||||
f()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fixed a bug where the scope of named expressions was not being resolved
|
||||
correctly in the presence of the *global* keyword. Patch by Pablo Galindo.
|
|
@ -1467,10 +1467,16 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* If we find a FunctionBlock entry, add as NONLOCAL/LOCAL */
|
||||
/* If we find a FunctionBlock entry, add as GLOBAL/LOCAL or NONLOCAL/LOCAL */
|
||||
if (ste->ste_type == FunctionBlock) {
|
||||
if (!symtable_add_def(st, target_name, DEF_NONLOCAL))
|
||||
VISIT_QUIT(st, 0);
|
||||
long target_in_scope = _PyST_GetSymbol(ste, target_name);
|
||||
if (target_in_scope & DEF_GLOBAL) {
|
||||
if (!symtable_add_def(st, target_name, DEF_GLOBAL))
|
||||
VISIT_QUIT(st, 0);
|
||||
} else {
|
||||
if (!symtable_add_def(st, target_name, DEF_NONLOCAL))
|
||||
VISIT_QUIT(st, 0);
|
||||
}
|
||||
if (!symtable_record_directive(st, target_name, e->lineno, e->col_offset))
|
||||
VISIT_QUIT(st, 0);
|
||||
|
||||
|
|
Loading…
Reference in New Issue