Skip to content

Commit ba86632

Browse files
[3.13] gh-70764: inspect.getclosurevars now identifies global variables with LOAD_GLOBAL (GH-120143) (#126459)
gh-70764: inspect.getclosurevars now identifies global variables with LOAD_GLOBAL (GH-120143) (cherry picked from commit 83ba8c2) Co-authored-by: blhsing <[email protected]>
1 parent 9dd3add commit ba86632

File tree

3 files changed

+23
-5
lines changed

3 files changed

+23
-5
lines changed

Lib/inspect.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,11 +1609,15 @@ def getclosurevars(func):
16091609
global_vars = {}
16101610
builtin_vars = {}
16111611
unbound_names = set()
1612-
for name in code.co_names:
1613-
if name in ("None", "True", "False"):
1614-
# Because these used to be builtins instead of keywords, they
1615-
# may still show up as name references. We ignore them.
1616-
continue
1612+
global_names = set()
1613+
for instruction in dis.get_instructions(code):
1614+
opname = instruction.opname
1615+
name = instruction.argval
1616+
if opname == "LOAD_ATTR":
1617+
unbound_names.add(name)
1618+
elif opname == "LOAD_GLOBAL":
1619+
global_names.add(name)
1620+
for name in global_names:
16171621
try:
16181622
global_vars[name] = global_ns[name]
16191623
except KeyError:

Lib/test/test_inspect/test_inspect.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,6 +2160,19 @@ def g(local_ref):
21602160
builtin_vars, unbound_names)
21612161
self.assertEqual(inspect.getclosurevars(C().f(_arg)), expected)
21622162

2163+
def test_attribute_same_name_as_global_var(self):
2164+
class C:
2165+
_global_ref = object()
2166+
def f():
2167+
print(C._global_ref, _global_ref)
2168+
nonlocal_vars = {"C": C}
2169+
global_vars = {"_global_ref": _global_ref}
2170+
builtin_vars = {"print": print}
2171+
unbound_names = {"_global_ref"}
2172+
expected = inspect.ClosureVars(nonlocal_vars, global_vars,
2173+
builtin_vars, unbound_names)
2174+
self.assertEqual(inspect.getclosurevars(f), expected)
2175+
21632176
def test_nonlocal_vars(self):
21642177
# More complex tests of nonlocal resolution
21652178
def _nonlocal_vars(f):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed an issue where :func:`inspect.getclosurevars` would incorrectly classify an attribute name as a global variable when the name exists both as an attribute name and a global variable.

0 commit comments

Comments
 (0)