Skip to content

Commit fc01844

Browse files
[3.12] gh-70764: inspect.getclosurevars now identifies global variables with LOAD_GLOBAL (GH-120143) (#126460)
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 b00887d commit fc01844

File tree

3 files changed

+23
-5
lines changed

3 files changed

+23
-5
lines changed

Lib/inspect.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -1638,11 +1638,15 @@ def getclosurevars(func):
16381638
global_vars = {}
16391639
builtin_vars = {}
16401640
unbound_names = set()
1641-
for name in code.co_names:
1642-
if name in ("None", "True", "False"):
1643-
# Because these used to be builtins instead of keywords, they
1644-
# may still show up as name references. We ignore them.
1645-
continue
1641+
global_names = set()
1642+
for instruction in dis.get_instructions(code):
1643+
opname = instruction.opname
1644+
name = instruction.argval
1645+
if opname == "LOAD_ATTR":
1646+
unbound_names.add(name)
1647+
elif opname == "LOAD_GLOBAL":
1648+
global_names.add(name)
1649+
for name in global_names:
16461650
try:
16471651
global_vars[name] = global_ns[name]
16481652
except KeyError:

Lib/test/test_inspect/test_inspect.py

+13
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,19 @@ def g(local_ref):
17801780
builtin_vars, unbound_names)
17811781
self.assertEqual(inspect.getclosurevars(C().f(_arg)), expected)
17821782

1783+
def test_attribute_same_name_as_global_var(self):
1784+
class C:
1785+
_global_ref = object()
1786+
def f():
1787+
print(C._global_ref, _global_ref)
1788+
nonlocal_vars = {"C": C}
1789+
global_vars = {"_global_ref": _global_ref}
1790+
builtin_vars = {"print": print}
1791+
unbound_names = {"_global_ref"}
1792+
expected = inspect.ClosureVars(nonlocal_vars, global_vars,
1793+
builtin_vars, unbound_names)
1794+
self.assertEqual(inspect.getclosurevars(f), expected)
1795+
17831796
def test_nonlocal_vars(self):
17841797
# More complex tests of nonlocal resolution
17851798
def _nonlocal_vars(f):
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)