summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_global.py
blob: 11d0bd54e8b69b9ccb8be722b44db1e7d586559c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
"""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()