0
0
mirror of https://github.com/python/cpython.git synced 2024-11-21 12:59:38 +01:00
cpython/Lib/test/test_global.py
Beomsoo Kim 494360afd0
gh-58749: Remove incorrect language spec claims about the global statement (GH-126523)
* Removes erroneous explanation of the `global` statement restrictions; a name declared as global can be subsequently bound using any kind of name binding operation.
* Updates `test_global.py` to also test various name-binding scenarios for global
variables to ensure correct behavior
2024-11-12 10:11:40 +10:00

215 lines
6.5 KiB
Python

"""This module includes tests for syntax errors that occur when a name
declared as `global` is used in ways that violate the language
specification, such as after assignment, usage, or annotation. The tests
verify that syntax errors are correctly raised for improper `global`
statements following variable use or assignment within functions.
Additionally, it tests various name-binding scenarios for global
variables to ensure correct behavior.
See `test_scope.py` for additional related behavioral tests covering
variable scoping and usage in different contexts.
"""
import contextlib
from test.support import check_syntax_error
from test.support.warnings_helper import check_warnings
from types import SimpleNamespace
import unittest
import warnings
class GlobalTests(unittest.TestCase):
def setUp(self):
self.enterContext(check_warnings())
warnings.filterwarnings("error", module="<test string>")
######################################################
### Syntax error cases as covered in Python/symtable.c
######################################################
def test_name_param(self):
prog_text = """\
def fn(name_param):
global name_param
"""
check_syntax_error(self, prog_text, lineno=2, offset=5)
def test_name_after_assign(self):
prog_text = """\
def fn():
name_assign = 1
global name_assign
"""
check_syntax_error(self, prog_text, lineno=3, offset=5)
def test_name_after_use(self):
prog_text = """\
def fn():
print(name_use)
global name_use
"""
check_syntax_error(self, prog_text, lineno=3, offset=5)
def test_name_annot(self):
prog_text_3 = """\
def fn():
name_annot: int
global name_annot
"""
check_syntax_error(self, prog_text_3, lineno=3, offset=5)
#############################################################
### Tests for global variables across all name binding cases,
### as described in executionmodel.rst
#############################################################
def test_assignment_statement(self):
global name_assignment_statement
value = object()
name_assignment_statement = value
self.assertIs(globals()["name_assignment_statement"], value)
del name_assignment_statement
def test_unpacking_assignment(self):
global name_unpacking_assignment
value = object()
_, name_unpacking_assignment = [None, value]
self.assertIs(globals()["name_unpacking_assignment"], value)
del name_unpacking_assignment
def test_assignment_expression(self):
global name_assignment_expression
value = object()
if name_assignment_expression := value:
pass
self.assertIs(globals()["name_assignment_expression"], value)
del name_assignment_expression
def test_iteration_variable(self):
global name_iteration_variable
value = object()
for name_iteration_variable in [value]:
pass
self.assertIs(globals()["name_iteration_variable"], value)
del name_iteration_variable
def test_func_def(self):
global name_func_def
def name_func_def():
pass
value = name_func_def
self.assertIs(globals()["name_func_def"], value)
del name_func_def
def test_class_def(self):
global name_class_def
class name_class_def:
pass
value = name_class_def
self.assertIs(globals()["name_class_def"], value)
del name_class_def
def test_type_alias(self):
global name_type_alias
type name_type_alias = tuple[int, int]
value = name_type_alias
self.assertIs(globals()["name_type_alias"], value)
del name_type_alias
def test_caught_exception(self):
global name_caught_exc
try:
1 / 0
except ZeroDivisionError as name_caught_exc:
value = name_caught_exc
# `name_caught_exc` is cleared automatically after the except block
self.assertIs(globals()["name_caught_exc"], value)
def test_caught_exception_group(self):
global name_caught_exc_group
try:
try:
1 / 0
except ZeroDivisionError as exc:
raise ExceptionGroup("eg", [exc])
except* ZeroDivisionError as name_caught_exc_group:
value = name_caught_exc_group
# `name_caught_exc` is cleared automatically after the except block
self.assertIs(globals()["name_caught_exc_group"], value)
def test_enter_result(self):
global name_enter_result
value = object()
with contextlib.nullcontext(value) as name_enter_result:
pass
self.assertIs(globals()["name_enter_result"], value)
del name_enter_result
def test_import_result(self):
global name_import_result
value = contextlib
import contextlib as name_import_result
self.assertIs(globals()["name_import_result"], value)
del name_import_result
def test_match(self):
global name_match
value = object()
match value:
case name_match:
pass
self.assertIs(globals()["name_match"], value)
del name_match
def test_match_as(self):
global name_match_as
value = object()
match value:
case _ as name_match_as:
pass
self.assertIs(globals()["name_match_as"], value)
del name_match_as
def test_match_seq(self):
global name_match_seq
value = object()
match (None, value):
case (_, name_match_seq):
pass
self.assertIs(globals()["name_match_seq"], value)
del name_match_seq
def test_match_map(self):
global name_match_map
value = object()
match {"key": value}:
case {"key": name_match_map}:
pass
self.assertIs(globals()["name_match_map"], value)
del name_match_map
def test_match_attr(self):
global name_match_attr
value = object()
match SimpleNamespace(key=value):
case SimpleNamespace(key=name_match_attr):
pass
self.assertIs(globals()["name_match_attr"], value)
del name_match_attr
def setUpModule():
unittest.enterModuleContext(warnings.catch_warnings())
warnings.filterwarnings("error", module="<test string>")
if __name__ == "__main__":
unittest.main()