Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fb0a465

Browse filesBrowse files
authored
bpo-41840: Report module-level globals as both local and global in the symtable module (GH-22391)
1 parent d646e91 commit fb0a465
Copy full SHA for fb0a465

File tree

Expand file treeCollapse file tree

3 files changed

+31
-9
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+31
-9
lines changed

‎Lib/symtable.py

Copy file name to clipboardExpand all lines: Lib/symtable.py
+12-7Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def __call__(self, table, filename):
3939
_newSymbolTable = SymbolTableFactory()
4040

4141

42-
class SymbolTable(object):
42+
class SymbolTable:
4343

4444
def __init__(self, raw_table, filename):
4545
self._table = raw_table
@@ -52,7 +52,7 @@ def __repr__(self):
5252
else:
5353
kind = "%s " % self.__class__.__name__
5454

55-
if self._table.name == "global":
55+
if self._table.name == "top":
5656
return "<{0}SymbolTable for module {1}>".format(kind, self._filename)
5757
else:
5858
return "<{0}SymbolTable for {1} in {2}>".format(kind,
@@ -124,7 +124,9 @@ def lookup(self, name):
124124
if sym is None:
125125
flags = self._table.symbols[name]
126126
namespaces = self.__check_children(name)
127-
sym = self._symbols[name] = Symbol(name, flags, namespaces)
127+
module_scope = (self._table.name == "top")
128+
sym = self._symbols[name] = Symbol(name, flags, namespaces,
129+
module_scope=module_scope)
128130
return sym
129131

130132
def get_symbols(self):
@@ -214,13 +216,14 @@ def get_methods(self):
214216
return self.__methods
215217

216218

217-
class Symbol(object):
219+
class Symbol:
218220

219-
def __init__(self, name, flags, namespaces=None):
221+
def __init__(self, name, flags, namespaces=None, *, module_scope=False):
220222
self.__name = name
221223
self.__flags = flags
222224
self.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK # like PyST_GetScope()
223225
self.__namespaces = namespaces or ()
226+
self.__module_scope = module_scope
224227

225228
def __repr__(self):
226229
return "<symbol {0!r}>".format(self.__name)
@@ -244,7 +247,8 @@ def is_parameter(self):
244247
def is_global(self):
245248
"""Return *True* if the sysmbol is global.
246249
"""
247-
return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT))
250+
return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
251+
or (self.__module_scope and self.__flags & DEF_BOUND))
248252

249253
def is_nonlocal(self):
250254
"""Return *True* if the symbol is nonlocal."""
@@ -258,7 +262,8 @@ def is_declared_global(self):
258262
def is_local(self):
259263
"""Return *True* if the symbol is local.
260264
"""
261-
return bool(self.__scope in (LOCAL, CELL))
265+
return bool(self.__scope in (LOCAL, CELL)
266+
or (self.__module_scope and self.__flags & DEF_BOUND))
262267

263268
def is_annotated(self):
264269
"""Return *True* if the symbol is annotated.

‎Lib/test/test_symtable.py

Copy file name to clipboardExpand all lines: Lib/test/test_symtable.py
+16-2Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
1212
glob = 42
1313
some_var = 12
14+
some_non_assigned_global_var = 11
15+
some_assigned_global_var = 11
1416
1517
class Mine:
1618
instance_var = 24
@@ -19,6 +21,8 @@ def a_method(p1, p2):
1921
2022
def spam(a, b, *var, **kw):
2123
global bar
24+
global some_assigned_global_var
25+
some_assigned_global_var = 12
2226
bar = 47
2327
some_var = 10
2428
x = 23
@@ -88,14 +92,14 @@ def test_children(self):
8892

8993
def test_lineno(self):
9094
self.assertEqual(self.top.get_lineno(), 0)
91-
self.assertEqual(self.spam.get_lineno(), 12)
95+
self.assertEqual(self.spam.get_lineno(), 14)
9296

9397
def test_function_info(self):
9498
func = self.spam
9599
self.assertEqual(sorted(func.get_parameters()), ["a", "b", "kw", "var"])
96100
expected = ['a', 'b', 'internal', 'kw', 'other_internal', 'some_var', 'var', 'x']
97101
self.assertEqual(sorted(func.get_locals()), expected)
98-
self.assertEqual(sorted(func.get_globals()), ["bar", "glob"])
102+
self.assertEqual(sorted(func.get_globals()), ["bar", "glob", "some_assigned_global_var"])
99103
self.assertEqual(self.internal.get_frees(), ("x",))
100104

101105
def test_globals(self):
@@ -106,6 +110,9 @@ def test_globals(self):
106110
self.assertFalse(self.internal.lookup("x").is_global())
107111
self.assertFalse(self.Mine.lookup("instance_var").is_global())
108112
self.assertTrue(self.spam.lookup("bar").is_global())
113+
# Module-scope globals are both global and local
114+
self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_global())
115+
self.assertTrue(self.top.lookup("some_assigned_global_var").is_global())
109116

110117
def test_nonlocal(self):
111118
self.assertFalse(self.spam.lookup("some_var").is_nonlocal())
@@ -116,6 +123,9 @@ def test_nonlocal(self):
116123
def test_local(self):
117124
self.assertTrue(self.spam.lookup("x").is_local())
118125
self.assertFalse(self.spam.lookup("bar").is_local())
126+
# Module-scope globals are both global and local
127+
self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_local())
128+
self.assertTrue(self.top.lookup("some_assigned_global_var").is_local())
119129

120130
def test_free(self):
121131
self.assertTrue(self.internal.lookup("x").is_free())
@@ -234,6 +244,10 @@ def test_bytes(self):
234244
top = symtable.symtable(code, "?", "exec")
235245
self.assertIsNotNone(find_block(top, "\u017d"))
236246

247+
def test_symtable_repr(self):
248+
self.assertEqual(str(self.top), "<SymbolTable for module ?>")
249+
self.assertEqual(str(self.spam), "<Function SymbolTable for spam in ?>")
250+
237251

238252
if __name__ == '__main__':
239253
unittest.main()
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a bug in the :mod:`symtable` module that was causing module-scope global
2+
variables to not be reported as both local and global. Patch by Pablo
3+
Galindo.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.