mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	* 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
		
			
				
	
	
		
			214 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			214 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()
 |