| """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() |