• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from contextlib import contextmanager
2import linecache
3import os
4import importlib
5import inspect
6from io import StringIO
7import re
8import sys
9import textwrap
10import types
11from typing import overload, get_overloads
12import unittest
13from test import support
14from test.support import import_helper
15from test.support import os_helper
16from test.support import warnings_helper
17from test.support import force_not_colorized
18from test.support.script_helper import assert_python_ok, assert_python_failure
19
20from test.test_warnings.data import package_helper
21from test.test_warnings.data import stacklevel as warning_tests
22
23import warnings as original_warnings
24from warnings import deprecated
25
26
27py_warnings = import_helper.import_fresh_module('warnings',
28                                                blocked=['_warnings'])
29c_warnings = import_helper.import_fresh_module('warnings',
30                                               fresh=['_warnings'])
31
32@contextmanager
33def warnings_state(module):
34    """Use a specific warnings implementation in warning_tests."""
35    global __warningregistry__
36    for to_clear in (sys, warning_tests):
37        try:
38            to_clear.__warningregistry__.clear()
39        except AttributeError:
40            pass
41    try:
42        __warningregistry__.clear()
43    except NameError:
44        pass
45    original_warnings = warning_tests.warnings
46    original_filters = module.filters
47    try:
48        module.filters = original_filters[:]
49        module.simplefilter("once")
50        warning_tests.warnings = module
51        yield
52    finally:
53        warning_tests.warnings = original_warnings
54        module.filters = original_filters
55
56
57class TestWarning(Warning):
58    pass
59
60
61class BaseTest:
62
63    """Basic bookkeeping required for testing."""
64
65    def setUp(self):
66        self.old_unittest_module = unittest.case.warnings
67        # The __warningregistry__ needs to be in a pristine state for tests
68        # to work properly.
69        if '__warningregistry__' in globals():
70            del globals()['__warningregistry__']
71        if hasattr(warning_tests, '__warningregistry__'):
72            del warning_tests.__warningregistry__
73        if hasattr(sys, '__warningregistry__'):
74            del sys.__warningregistry__
75        # The 'warnings' module must be explicitly set so that the proper
76        # interaction between _warnings and 'warnings' can be controlled.
77        sys.modules['warnings'] = self.module
78        # Ensure that unittest.TestCase.assertWarns() uses the same warnings
79        # module than warnings.catch_warnings(). Otherwise,
80        # warnings.catch_warnings() will be unable to remove the added filter.
81        unittest.case.warnings = self.module
82        super(BaseTest, self).setUp()
83
84    def tearDown(self):
85        sys.modules['warnings'] = original_warnings
86        unittest.case.warnings = self.old_unittest_module
87        super(BaseTest, self).tearDown()
88
89class PublicAPITests(BaseTest):
90
91    """Ensures that the correct values are exposed in the
92    public API.
93    """
94
95    def test_module_all_attribute(self):
96        self.assertTrue(hasattr(self.module, '__all__'))
97        target_api = ["warn", "warn_explicit", "showwarning",
98                      "formatwarning", "filterwarnings", "simplefilter",
99                      "resetwarnings", "catch_warnings", "deprecated"]
100        self.assertSetEqual(set(self.module.__all__),
101                            set(target_api))
102
103class CPublicAPITests(PublicAPITests, unittest.TestCase):
104    module = c_warnings
105
106class PyPublicAPITests(PublicAPITests, unittest.TestCase):
107    module = py_warnings
108
109class FilterTests(BaseTest):
110
111    """Testing the filtering functionality."""
112
113    def test_error(self):
114        with original_warnings.catch_warnings(module=self.module) as w:
115            self.module.resetwarnings()
116            self.module.filterwarnings("error", category=UserWarning)
117            self.assertRaises(UserWarning, self.module.warn,
118                                "FilterTests.test_error")
119
120    def test_error_after_default(self):
121        with original_warnings.catch_warnings(module=self.module) as w:
122            self.module.resetwarnings()
123            message = "FilterTests.test_ignore_after_default"
124            def f():
125                self.module.warn(message, UserWarning)
126
127            with support.captured_stderr() as stderr:
128                f()
129            stderr = stderr.getvalue()
130            self.assertIn("UserWarning: FilterTests.test_ignore_after_default",
131                          stderr)
132            self.assertIn("self.module.warn(message, UserWarning)",
133                          stderr)
134
135            self.module.filterwarnings("error", category=UserWarning)
136            self.assertRaises(UserWarning, f)
137
138    def test_ignore(self):
139        with original_warnings.catch_warnings(record=True,
140                module=self.module) as w:
141            self.module.resetwarnings()
142            self.module.filterwarnings("ignore", category=UserWarning)
143            self.module.warn("FilterTests.test_ignore", UserWarning)
144            self.assertEqual(len(w), 0)
145            self.assertEqual(list(__warningregistry__), ['version'])
146
147    def test_ignore_after_default(self):
148        with original_warnings.catch_warnings(record=True,
149                module=self.module) as w:
150            self.module.resetwarnings()
151            message = "FilterTests.test_ignore_after_default"
152            def f():
153                self.module.warn(message, UserWarning)
154            f()
155            self.module.filterwarnings("ignore", category=UserWarning)
156            f()
157            f()
158            self.assertEqual(len(w), 1)
159
160    def test_always(self):
161        with original_warnings.catch_warnings(record=True,
162                module=self.module) as w:
163            self.module.resetwarnings()
164            self.module.filterwarnings("always", category=UserWarning)
165            message = "FilterTests.test_always"
166            def f():
167                self.module.warn(message, UserWarning)
168            f()
169            self.assertEqual(len(w), 1)
170            self.assertEqual(w[-1].message.args[0], message)
171            f()
172            self.assertEqual(len(w), 2)
173            self.assertEqual(w[-1].message.args[0], message)
174
175    def test_always_after_default(self):
176        with original_warnings.catch_warnings(record=True,
177                module=self.module) as w:
178            self.module.resetwarnings()
179            message = "FilterTests.test_always_after_ignore"
180            def f():
181                self.module.warn(message, UserWarning)
182            f()
183            self.assertEqual(len(w), 1)
184            self.assertEqual(w[-1].message.args[0], message)
185            f()
186            self.assertEqual(len(w), 1)
187            self.module.filterwarnings("always", category=UserWarning)
188            f()
189            self.assertEqual(len(w), 2)
190            self.assertEqual(w[-1].message.args[0], message)
191            f()
192            self.assertEqual(len(w), 3)
193            self.assertEqual(w[-1].message.args[0], message)
194
195    def test_default(self):
196        with original_warnings.catch_warnings(record=True,
197                module=self.module) as w:
198            self.module.resetwarnings()
199            self.module.filterwarnings("default", category=UserWarning)
200            message = UserWarning("FilterTests.test_default")
201            for x in range(2):
202                self.module.warn(message, UserWarning)
203                if x == 0:
204                    self.assertEqual(w[-1].message, message)
205                    del w[:]
206                elif x == 1:
207                    self.assertEqual(len(w), 0)
208                else:
209                    raise ValueError("loop variant unhandled")
210
211    def test_module(self):
212        with original_warnings.catch_warnings(record=True,
213                module=self.module) as w:
214            self.module.resetwarnings()
215            self.module.filterwarnings("module", category=UserWarning)
216            message = UserWarning("FilterTests.test_module")
217            self.module.warn(message, UserWarning)
218            self.assertEqual(w[-1].message, message)
219            del w[:]
220            self.module.warn(message, UserWarning)
221            self.assertEqual(len(w), 0)
222
223    def test_once(self):
224        with original_warnings.catch_warnings(record=True,
225                module=self.module) as w:
226            self.module.resetwarnings()
227            self.module.filterwarnings("once", category=UserWarning)
228            message = UserWarning("FilterTests.test_once")
229            self.module.warn_explicit(message, UserWarning, "__init__.py",
230                                    42)
231            self.assertEqual(w[-1].message, message)
232            del w[:]
233            self.module.warn_explicit(message, UserWarning, "__init__.py",
234                                    13)
235            self.assertEqual(len(w), 0)
236            self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
237                                    42)
238            self.assertEqual(len(w), 0)
239
240    def test_module_globals(self):
241        with original_warnings.catch_warnings(record=True,
242                module=self.module) as w:
243            self.module.simplefilter("always", UserWarning)
244
245            # bpo-33509: module_globals=None must not crash
246            self.module.warn_explicit('msg', UserWarning, "filename", 42,
247                                      module_globals=None)
248            self.assertEqual(len(w), 1)
249
250            # Invalid module_globals type
251            with self.assertRaises(TypeError):
252                self.module.warn_explicit('msg', UserWarning, "filename", 42,
253                                          module_globals=True)
254            self.assertEqual(len(w), 1)
255
256            # Empty module_globals
257            self.module.warn_explicit('msg', UserWarning, "filename", 42,
258                                      module_globals={})
259            self.assertEqual(len(w), 2)
260
261    def test_inheritance(self):
262        with original_warnings.catch_warnings(module=self.module) as w:
263            self.module.resetwarnings()
264            self.module.filterwarnings("error", category=Warning)
265            self.assertRaises(UserWarning, self.module.warn,
266                                "FilterTests.test_inheritance", UserWarning)
267
268    def test_ordering(self):
269        with original_warnings.catch_warnings(record=True,
270                module=self.module) as w:
271            self.module.resetwarnings()
272            self.module.filterwarnings("ignore", category=UserWarning)
273            self.module.filterwarnings("error", category=UserWarning,
274                                        append=True)
275            del w[:]
276            try:
277                self.module.warn("FilterTests.test_ordering", UserWarning)
278            except UserWarning:
279                self.fail("order handling for actions failed")
280            self.assertEqual(len(w), 0)
281
282    def test_filterwarnings(self):
283        # Test filterwarnings().
284        # Implicitly also tests resetwarnings().
285        with original_warnings.catch_warnings(record=True,
286                module=self.module) as w:
287            self.module.filterwarnings("error", "", Warning, "", 0)
288            self.assertRaises(UserWarning, self.module.warn, 'convert to error')
289
290            self.module.resetwarnings()
291            text = 'handle normally'
292            self.module.warn(text)
293            self.assertEqual(str(w[-1].message), text)
294            self.assertIs(w[-1].category, UserWarning)
295
296            self.module.filterwarnings("ignore", "", Warning, "", 0)
297            text = 'filtered out'
298            self.module.warn(text)
299            self.assertNotEqual(str(w[-1].message), text)
300
301            self.module.resetwarnings()
302            self.module.filterwarnings("error", "hex*", Warning, "", 0)
303            self.assertRaises(UserWarning, self.module.warn, 'hex/oct')
304            text = 'nonmatching text'
305            self.module.warn(text)
306            self.assertEqual(str(w[-1].message), text)
307            self.assertIs(w[-1].category, UserWarning)
308
309    def test_message_matching(self):
310        with original_warnings.catch_warnings(record=True,
311                module=self.module) as w:
312            self.module.simplefilter("ignore", UserWarning)
313            self.module.filterwarnings("error", "match", UserWarning)
314            self.assertRaises(UserWarning, self.module.warn, "match")
315            self.assertRaises(UserWarning, self.module.warn, "match prefix")
316            self.module.warn("suffix match")
317            self.assertEqual(w, [])
318            self.module.warn("something completely different")
319            self.assertEqual(w, [])
320
321    def test_mutate_filter_list(self):
322        class X:
323            def match(self, a):
324                L[:] = []
325
326        L = [("default",X(),UserWarning,X(),0) for i in range(2)]
327        with original_warnings.catch_warnings(record=True,
328                module=self.module) as w:
329            self.module.filters = L
330            self.module.warn_explicit(UserWarning("b"), None, "f.py", 42)
331            self.assertEqual(str(w[-1].message), "b")
332
333    def test_filterwarnings_duplicate_filters(self):
334        with original_warnings.catch_warnings(module=self.module):
335            self.module.resetwarnings()
336            self.module.filterwarnings("error", category=UserWarning)
337            self.assertEqual(len(self.module.filters), 1)
338            self.module.filterwarnings("ignore", category=UserWarning)
339            self.module.filterwarnings("error", category=UserWarning)
340            self.assertEqual(
341                len(self.module.filters), 2,
342                "filterwarnings inserted duplicate filter"
343            )
344            self.assertEqual(
345                self.module.filters[0][0], "error",
346                "filterwarnings did not promote filter to "
347                "the beginning of list"
348            )
349
350    def test_simplefilter_duplicate_filters(self):
351        with original_warnings.catch_warnings(module=self.module):
352            self.module.resetwarnings()
353            self.module.simplefilter("error", category=UserWarning)
354            self.assertEqual(len(self.module.filters), 1)
355            self.module.simplefilter("ignore", category=UserWarning)
356            self.module.simplefilter("error", category=UserWarning)
357            self.assertEqual(
358                len(self.module.filters), 2,
359                "simplefilter inserted duplicate filter"
360            )
361            self.assertEqual(
362                self.module.filters[0][0], "error",
363                "simplefilter did not promote filter to the beginning of list"
364            )
365
366    def test_append_duplicate(self):
367        with original_warnings.catch_warnings(module=self.module,
368                record=True) as w:
369            self.module.resetwarnings()
370            self.module.simplefilter("ignore")
371            self.module.simplefilter("error", append=True)
372            self.module.simplefilter("ignore", append=True)
373            self.module.warn("test_append_duplicate", category=UserWarning)
374            self.assertEqual(len(self.module.filters), 2,
375                "simplefilter inserted duplicate filter"
376            )
377            self.assertEqual(len(w), 0,
378                "appended duplicate changed order of filters"
379            )
380
381    def test_argument_validation(self):
382        with self.assertRaises(ValueError):
383            self.module.filterwarnings(action='foo')
384        with self.assertRaises(TypeError):
385            self.module.filterwarnings('ignore', message=0)
386        with self.assertRaises(TypeError):
387            self.module.filterwarnings('ignore', category=0)
388        with self.assertRaises(TypeError):
389            self.module.filterwarnings('ignore', category=int)
390        with self.assertRaises(TypeError):
391            self.module.filterwarnings('ignore', module=0)
392        with self.assertRaises(TypeError):
393            self.module.filterwarnings('ignore', lineno=int)
394        with self.assertRaises(ValueError):
395            self.module.filterwarnings('ignore', lineno=-1)
396        with self.assertRaises(ValueError):
397            self.module.simplefilter(action='foo')
398        with self.assertRaises(TypeError):
399            self.module.simplefilter('ignore', lineno=int)
400        with self.assertRaises(ValueError):
401            self.module.simplefilter('ignore', lineno=-1)
402
403    def test_catchwarnings_with_simplefilter_ignore(self):
404        with original_warnings.catch_warnings(module=self.module):
405            self.module.resetwarnings()
406            self.module.simplefilter("error")
407            with self.module.catch_warnings(
408                module=self.module, action="ignore"
409            ):
410                self.module.warn("This will be ignored")
411
412    def test_catchwarnings_with_simplefilter_error(self):
413        with original_warnings.catch_warnings(module=self.module):
414            self.module.resetwarnings()
415            with self.module.catch_warnings(
416                module=self.module, action="error", category=FutureWarning
417            ):
418                with support.captured_stderr() as stderr:
419                    error_msg = "Other types of warnings are not errors"
420                    self.module.warn(error_msg)
421                    self.assertRaises(FutureWarning,
422                                      self.module.warn, FutureWarning("msg"))
423                    stderr = stderr.getvalue()
424                    self.assertIn(error_msg, stderr)
425
426class CFilterTests(FilterTests, unittest.TestCase):
427    module = c_warnings
428
429class PyFilterTests(FilterTests, unittest.TestCase):
430    module = py_warnings
431
432
433class WarnTests(BaseTest):
434
435    """Test warnings.warn() and warnings.warn_explicit()."""
436
437    def test_message(self):
438        with original_warnings.catch_warnings(record=True,
439                module=self.module) as w:
440            self.module.simplefilter("once")
441            for i in range(4):
442                text = 'multi %d' %i  # Different text on each call.
443                self.module.warn(text)
444                self.assertEqual(str(w[-1].message), text)
445                self.assertIs(w[-1].category, UserWarning)
446
447    # Issue 3639
448    def test_warn_nonstandard_types(self):
449        # warn() should handle non-standard types without issue.
450        for ob in (Warning, None, 42):
451            with original_warnings.catch_warnings(record=True,
452                    module=self.module) as w:
453                self.module.simplefilter("once")
454                self.module.warn(ob)
455                # Don't directly compare objects since
456                # ``Warning() != Warning()``.
457                self.assertEqual(str(w[-1].message), str(UserWarning(ob)))
458
459    def test_filename(self):
460        with warnings_state(self.module):
461            with original_warnings.catch_warnings(record=True,
462                    module=self.module) as w:
463                warning_tests.inner("spam1")
464                self.assertEqual(os.path.basename(w[-1].filename),
465                                    "stacklevel.py")
466                warning_tests.outer("spam2")
467                self.assertEqual(os.path.basename(w[-1].filename),
468                                    "stacklevel.py")
469
470    def test_stacklevel(self):
471        # Test stacklevel argument
472        # make sure all messages are different, so the warning won't be skipped
473        with warnings_state(self.module):
474            with original_warnings.catch_warnings(record=True,
475                    module=self.module) as w:
476                warning_tests.inner("spam3", stacklevel=1)
477                self.assertEqual(os.path.basename(w[-1].filename),
478                                    "stacklevel.py")
479                warning_tests.outer("spam4", stacklevel=1)
480                self.assertEqual(os.path.basename(w[-1].filename),
481                                    "stacklevel.py")
482
483                warning_tests.inner("spam5", stacklevel=2)
484                self.assertEqual(os.path.basename(w[-1].filename),
485                                    "__init__.py")
486                warning_tests.outer("spam6", stacklevel=2)
487                self.assertEqual(os.path.basename(w[-1].filename),
488                                    "stacklevel.py")
489                warning_tests.outer("spam6.5", stacklevel=3)
490                self.assertEqual(os.path.basename(w[-1].filename),
491                                    "__init__.py")
492
493                warning_tests.inner("spam7", stacklevel=9999)
494                self.assertEqual(os.path.basename(w[-1].filename),
495                                    "<sys>")
496
497    def test_stacklevel_import(self):
498        # Issue #24305: With stacklevel=2, module-level warnings should work.
499        import_helper.unload('test.test_warnings.data.import_warning')
500        with warnings_state(self.module):
501            with original_warnings.catch_warnings(record=True,
502                    module=self.module) as w:
503                self.module.simplefilter('always')
504                import test.test_warnings.data.import_warning
505                self.assertEqual(len(w), 1)
506                self.assertEqual(w[0].filename, __file__)
507
508    def test_skip_file_prefixes(self):
509        with warnings_state(self.module):
510            with original_warnings.catch_warnings(record=True,
511                    module=self.module) as w:
512                self.module.simplefilter('always')
513
514                # Warning never attributed to the data/ package.
515                package_helper.inner_api(
516                        "inner_api", stacklevel=2,
517                        warnings_module=warning_tests.warnings)
518                self.assertEqual(w[-1].filename, __file__)
519                warning_tests.package("package api", stacklevel=2)
520                self.assertEqual(w[-1].filename, __file__)
521                self.assertEqual(w[-2].filename, w[-1].filename)
522                # Low stacklevels are overridden to 2 behavior.
523                warning_tests.package("package api 1", stacklevel=1)
524                self.assertEqual(w[-1].filename, __file__)
525                warning_tests.package("package api 0", stacklevel=0)
526                self.assertEqual(w[-1].filename, __file__)
527                warning_tests.package("package api -99", stacklevel=-99)
528                self.assertEqual(w[-1].filename, __file__)
529
530                # The stacklevel still goes up out of the package.
531                warning_tests.package("prefix02", stacklevel=3)
532                self.assertIn("unittest", w[-1].filename)
533
534    def test_skip_file_prefixes_type_errors(self):
535        with warnings_state(self.module):
536            warn = warning_tests.warnings.warn
537            with self.assertRaises(TypeError):
538                warn("msg", skip_file_prefixes=[])
539            with self.assertRaises(TypeError):
540                warn("msg", skip_file_prefixes=(b"bytes",))
541            with self.assertRaises(TypeError):
542                warn("msg", skip_file_prefixes="a sequence of strs")
543
544    def test_exec_filename(self):
545        filename = "<warnings-test>"
546        codeobj = compile(("import warnings\n"
547                           "warnings.warn('hello', UserWarning)"),
548                          filename, "exec")
549        with original_warnings.catch_warnings(record=True) as w:
550            self.module.simplefilter("always", category=UserWarning)
551            exec(codeobj)
552        self.assertEqual(w[0].filename, filename)
553
554    def test_warn_explicit_non_ascii_filename(self):
555        with original_warnings.catch_warnings(record=True,
556                module=self.module) as w:
557            self.module.resetwarnings()
558            self.module.filterwarnings("always", category=UserWarning)
559            filenames = ["nonascii\xe9\u20ac"]
560            if not support.is_emscripten:
561                # JavaScript does not like surrogates.
562                # Invalid UTF-8 leading byte 0x80 encountered when
563                # deserializing a UTF-8 string in wasm memory to a JS
564                # string!
565                filenames.append("surrogate\udc80")
566            for filename in filenames:
567                try:
568                    os.fsencode(filename)
569                except UnicodeEncodeError:
570                    continue
571                self.module.warn_explicit("text", UserWarning, filename, 1)
572                self.assertEqual(w[-1].filename, filename)
573
574    def test_warn_explicit_type_errors(self):
575        # warn_explicit() should error out gracefully if it is given objects
576        # of the wrong types.
577        # lineno is expected to be an integer.
578        self.assertRaises(TypeError, self.module.warn_explicit,
579                            None, UserWarning, None, None)
580        # Either 'message' needs to be an instance of Warning or 'category'
581        # needs to be a subclass.
582        self.assertRaises(TypeError, self.module.warn_explicit,
583                            None, None, None, 1)
584        # 'registry' must be a dict or None.
585        self.assertRaises((TypeError, AttributeError),
586                            self.module.warn_explicit,
587                            None, Warning, None, 1, registry=42)
588
589    def test_bad_str(self):
590        # issue 6415
591        # Warnings instance with a bad format string for __str__ should not
592        # trigger a bus error.
593        class BadStrWarning(Warning):
594            """Warning with a bad format string for __str__."""
595            def __str__(self):
596                return ("A bad formatted string %(err)" %
597                        {"err" : "there is no %(err)s"})
598
599        with self.assertRaises(ValueError):
600            self.module.warn(BadStrWarning())
601
602    def test_warning_classes(self):
603        class MyWarningClass(Warning):
604            pass
605
606        class NonWarningSubclass:
607            pass
608
609        # passing a non-subclass of Warning should raise a TypeError
610        with self.assertRaises(TypeError) as cm:
611            self.module.warn('bad warning category', '')
612        self.assertIn('category must be a Warning subclass, not ',
613                      str(cm.exception))
614
615        with self.assertRaises(TypeError) as cm:
616            self.module.warn('bad warning category', NonWarningSubclass)
617        self.assertIn('category must be a Warning subclass, not ',
618                      str(cm.exception))
619
620        # check that warning instances also raise a TypeError
621        with self.assertRaises(TypeError) as cm:
622            self.module.warn('bad warning category', MyWarningClass())
623        self.assertIn('category must be a Warning subclass, not ',
624                      str(cm.exception))
625
626        with original_warnings.catch_warnings(module=self.module):
627            self.module.resetwarnings()
628            self.module.filterwarnings('default')
629            with self.assertWarns(MyWarningClass) as cm:
630                self.module.warn('good warning category', MyWarningClass)
631            self.assertEqual('good warning category', str(cm.warning))
632
633            with self.assertWarns(UserWarning) as cm:
634                self.module.warn('good warning category', None)
635            self.assertEqual('good warning category', str(cm.warning))
636
637            with self.assertWarns(MyWarningClass) as cm:
638                self.module.warn('good warning category', MyWarningClass)
639            self.assertIsInstance(cm.warning, Warning)
640
641    def check_module_globals(self, module_globals):
642        with original_warnings.catch_warnings(module=self.module, record=True) as w:
643            self.module.filterwarnings('default')
644            self.module.warn_explicit(
645                'eggs', UserWarning, 'bar', 1,
646                module_globals=module_globals)
647        self.assertEqual(len(w), 1)
648        self.assertEqual(w[0].category, UserWarning)
649        self.assertEqual(str(w[0].message), 'eggs')
650
651    def check_module_globals_error(self, module_globals, errmsg, errtype=ValueError):
652        if self.module is py_warnings:
653            self.check_module_globals(module_globals)
654            return
655        with original_warnings.catch_warnings(module=self.module, record=True) as w:
656            self.module.filterwarnings('always')
657            with self.assertRaisesRegex(errtype, re.escape(errmsg)):
658                self.module.warn_explicit(
659                    'eggs', UserWarning, 'bar', 1,
660                    module_globals=module_globals)
661        self.assertEqual(len(w), 0)
662
663    def check_module_globals_deprecated(self, module_globals, msg):
664        if self.module is py_warnings:
665            self.check_module_globals(module_globals)
666            return
667        with original_warnings.catch_warnings(module=self.module, record=True) as w:
668            self.module.filterwarnings('always')
669            self.module.warn_explicit(
670                'eggs', UserWarning, 'bar', 1,
671                module_globals=module_globals)
672        self.assertEqual(len(w), 2)
673        self.assertEqual(w[0].category, DeprecationWarning)
674        self.assertEqual(str(w[0].message), msg)
675        self.assertEqual(w[1].category, UserWarning)
676        self.assertEqual(str(w[1].message), 'eggs')
677
678    def test_gh86298_no_loader_and_no_spec(self):
679        self.check_module_globals({'__name__': 'bar'})
680
681    def test_gh86298_loader_is_none_and_no_spec(self):
682        self.check_module_globals({'__name__': 'bar', '__loader__': None})
683
684    def test_gh86298_no_loader_and_spec_is_none(self):
685        self.check_module_globals_error(
686            {'__name__': 'bar', '__spec__': None},
687            'Module globals is missing a __spec__.loader')
688
689    def test_gh86298_loader_is_none_and_spec_is_none(self):
690        self.check_module_globals_error(
691            {'__name__': 'bar', '__loader__': None, '__spec__': None},
692            'Module globals is missing a __spec__.loader')
693
694    def test_gh86298_loader_is_none_and_spec_loader_is_none(self):
695        self.check_module_globals_error(
696            {'__name__': 'bar', '__loader__': None,
697             '__spec__': types.SimpleNamespace(loader=None)},
698            'Module globals is missing a __spec__.loader')
699
700    def test_gh86298_no_spec(self):
701        self.check_module_globals_deprecated(
702            {'__name__': 'bar', '__loader__': object()},
703            'Module globals is missing a __spec__.loader')
704
705    def test_gh86298_spec_is_none(self):
706        self.check_module_globals_deprecated(
707            {'__name__': 'bar', '__loader__': object(), '__spec__': None},
708            'Module globals is missing a __spec__.loader')
709
710    def test_gh86298_no_spec_loader(self):
711        self.check_module_globals_deprecated(
712            {'__name__': 'bar', '__loader__': object(),
713             '__spec__': types.SimpleNamespace()},
714            'Module globals is missing a __spec__.loader')
715
716    def test_gh86298_loader_and_spec_loader_disagree(self):
717        self.check_module_globals_deprecated(
718            {'__name__': 'bar', '__loader__': object(),
719             '__spec__': types.SimpleNamespace(loader=object())},
720            'Module globals; __loader__ != __spec__.loader')
721
722    def test_gh86298_no_loader_and_no_spec_loader(self):
723        self.check_module_globals_error(
724            {'__name__': 'bar', '__spec__': types.SimpleNamespace()},
725            'Module globals is missing a __spec__.loader', AttributeError)
726
727    def test_gh86298_no_loader_with_spec_loader_okay(self):
728        self.check_module_globals(
729            {'__name__': 'bar',
730             '__spec__': types.SimpleNamespace(loader=object())})
731
732class CWarnTests(WarnTests, unittest.TestCase):
733    module = c_warnings
734
735    # As an early adopter, we sanity check the
736    # test.import_helper.import_fresh_module utility function
737    def test_accelerated(self):
738        self.assertIsNot(original_warnings, self.module)
739        self.assertFalse(hasattr(self.module.warn, '__code__'))
740
741class PyWarnTests(WarnTests, unittest.TestCase):
742    module = py_warnings
743
744    # As an early adopter, we sanity check the
745    # test.import_helper.import_fresh_module utility function
746    def test_pure_python(self):
747        self.assertIsNot(original_warnings, self.module)
748        self.assertTrue(hasattr(self.module.warn, '__code__'))
749
750
751class WCmdLineTests(BaseTest):
752
753    def test_improper_input(self):
754        # Uses the private _setoption() function to test the parsing
755        # of command-line warning arguments
756        with original_warnings.catch_warnings(module=self.module):
757            self.assertRaises(self.module._OptionError,
758                              self.module._setoption, '1:2:3:4:5:6')
759            self.assertRaises(self.module._OptionError,
760                              self.module._setoption, 'bogus::Warning')
761            self.assertRaises(self.module._OptionError,
762                              self.module._setoption, 'ignore:2::4:-5')
763            with self.assertRaises(self.module._OptionError):
764                self.module._setoption('ignore::123')
765            with self.assertRaises(self.module._OptionError):
766                self.module._setoption('ignore::123abc')
767            with self.assertRaises(self.module._OptionError):
768                self.module._setoption('ignore::===')
769            with self.assertRaisesRegex(self.module._OptionError, 'Wärning'):
770                self.module._setoption('ignore::Wärning')
771            self.module._setoption('error::Warning::0')
772            self.assertRaises(UserWarning, self.module.warn, 'convert to error')
773
774    def test_import_from_module(self):
775        with original_warnings.catch_warnings(module=self.module):
776            self.module._setoption('ignore::Warning')
777            with self.assertRaises(self.module._OptionError):
778                self.module._setoption('ignore::TestWarning')
779            with self.assertRaises(self.module._OptionError):
780                self.module._setoption('ignore::test.test_warnings.bogus')
781            self.module._setoption('error::test.test_warnings.TestWarning')
782            with self.assertRaises(TestWarning):
783                self.module.warn('test warning', TestWarning)
784
785
786class CWCmdLineTests(WCmdLineTests, unittest.TestCase):
787    module = c_warnings
788
789
790class PyWCmdLineTests(WCmdLineTests, unittest.TestCase):
791    module = py_warnings
792
793    def test_improper_option(self):
794        # Same as above, but check that the message is printed out when
795        # the interpreter is executed. This also checks that options are
796        # actually parsed at all.
797        rc, out, err = assert_python_ok("-Wxxx", "-c", "pass")
798        self.assertIn(b"Invalid -W option ignored: invalid action: 'xxx'", err)
799
800    def test_warnings_bootstrap(self):
801        # Check that the warnings module does get loaded when -W<some option>
802        # is used (see issue #10372 for an example of silent bootstrap failure).
803        rc, out, err = assert_python_ok("-Wi", "-c",
804            "import sys; sys.modules['warnings'].warn('foo', RuntimeWarning)")
805        # '-Wi' was observed
806        self.assertFalse(out.strip())
807        self.assertNotIn(b'RuntimeWarning', err)
808
809
810class _WarningsTests(BaseTest, unittest.TestCase):
811
812    """Tests specific to the _warnings module."""
813
814    module = c_warnings
815
816    def test_filter(self):
817        # Everything should function even if 'filters' is not in warnings.
818        with original_warnings.catch_warnings(module=self.module) as w:
819            self.module.filterwarnings("error", "", Warning, "", 0)
820            self.assertRaises(UserWarning, self.module.warn,
821                                'convert to error')
822            del self.module.filters
823            self.assertRaises(UserWarning, self.module.warn,
824                                'convert to error')
825
826    def test_onceregistry(self):
827        # Replacing or removing the onceregistry should be okay.
828        global __warningregistry__
829        message = UserWarning('onceregistry test')
830        try:
831            original_registry = self.module.onceregistry
832            __warningregistry__ = {}
833            with original_warnings.catch_warnings(record=True,
834                    module=self.module) as w:
835                self.module.resetwarnings()
836                self.module.filterwarnings("once", category=UserWarning)
837                self.module.warn_explicit(message, UserWarning, "file", 42)
838                self.assertEqual(w[-1].message, message)
839                del w[:]
840                self.module.warn_explicit(message, UserWarning, "file", 42)
841                self.assertEqual(len(w), 0)
842                # Test the resetting of onceregistry.
843                self.module.onceregistry = {}
844                __warningregistry__ = {}
845                self.module.warn('onceregistry test')
846                self.assertEqual(w[-1].message.args, message.args)
847                # Removal of onceregistry is okay.
848                del w[:]
849                del self.module.onceregistry
850                __warningregistry__ = {}
851                self.module.warn_explicit(message, UserWarning, "file", 42)
852                self.assertEqual(len(w), 0)
853        finally:
854            self.module.onceregistry = original_registry
855
856    def test_default_action(self):
857        # Replacing or removing defaultaction should be okay.
858        message = UserWarning("defaultaction test")
859        original = self.module.defaultaction
860        try:
861            with original_warnings.catch_warnings(record=True,
862                    module=self.module) as w:
863                self.module.resetwarnings()
864                registry = {}
865                self.module.warn_explicit(message, UserWarning, "<test>", 42,
866                                            registry=registry)
867                self.assertEqual(w[-1].message, message)
868                self.assertEqual(len(w), 1)
869                # One actual registry key plus the "version" key
870                self.assertEqual(len(registry), 2)
871                self.assertIn("version", registry)
872                del w[:]
873                # Test removal.
874                del self.module.defaultaction
875                __warningregistry__ = {}
876                registry = {}
877                self.module.warn_explicit(message, UserWarning, "<test>", 43,
878                                            registry=registry)
879                self.assertEqual(w[-1].message, message)
880                self.assertEqual(len(w), 1)
881                self.assertEqual(len(registry), 2)
882                del w[:]
883                # Test setting.
884                self.module.defaultaction = "ignore"
885                __warningregistry__ = {}
886                registry = {}
887                self.module.warn_explicit(message, UserWarning, "<test>", 44,
888                                            registry=registry)
889                self.assertEqual(len(w), 0)
890        finally:
891            self.module.defaultaction = original
892
893    def test_showwarning_missing(self):
894        # Test that showwarning() missing is okay.
895        text = 'del showwarning test'
896        with original_warnings.catch_warnings(module=self.module):
897            self.module.filterwarnings("always", category=UserWarning)
898            del self.module.showwarning
899            with support.captured_output('stderr') as stream:
900                self.module.warn(text)
901                result = stream.getvalue()
902        self.assertIn(text, result)
903
904    def test_showwarnmsg_missing(self):
905        # Test that _showwarnmsg() missing is okay.
906        text = 'del _showwarnmsg test'
907        with original_warnings.catch_warnings(module=self.module):
908            self.module.filterwarnings("always", category=UserWarning)
909
910            show = self.module._showwarnmsg
911            try:
912                del self.module._showwarnmsg
913                with support.captured_output('stderr') as stream:
914                    self.module.warn(text)
915                    result = stream.getvalue()
916            finally:
917                self.module._showwarnmsg = show
918        self.assertIn(text, result)
919
920    def test_showwarning_not_callable(self):
921        with original_warnings.catch_warnings(module=self.module):
922            self.module.filterwarnings("always", category=UserWarning)
923            self.module.showwarning = print
924            with support.captured_output('stdout'):
925                self.module.warn('Warning!')
926            self.module.showwarning = 23
927            self.assertRaises(TypeError, self.module.warn, "Warning!")
928
929    def test_show_warning_output(self):
930        # With showwarning() missing, make sure that output is okay.
931        text = 'test show_warning'
932        with original_warnings.catch_warnings(module=self.module):
933            self.module.filterwarnings("always", category=UserWarning)
934            del self.module.showwarning
935            with support.captured_output('stderr') as stream:
936                warning_tests.inner(text)
937                result = stream.getvalue()
938        self.assertEqual(result.count('\n'), 2,
939                             "Too many newlines in %r" % result)
940        first_line, second_line = result.split('\n', 1)
941        expected_file = os.path.splitext(warning_tests.__file__)[0] + '.py'
942        first_line_parts = first_line.rsplit(':', 3)
943        path, line, warning_class, message = first_line_parts
944        line = int(line)
945        self.assertEqual(expected_file, path)
946        self.assertEqual(warning_class, ' ' + UserWarning.__name__)
947        self.assertEqual(message, ' ' + text)
948        expected_line = '  ' + linecache.getline(path, line).strip() + '\n'
949        assert expected_line
950        self.assertEqual(second_line, expected_line)
951
952    def test_filename_none(self):
953        # issue #12467: race condition if a warning is emitted at shutdown
954        globals_dict = globals()
955        oldfile = globals_dict['__file__']
956        try:
957            catch = original_warnings.catch_warnings(record=True,
958                                                     module=self.module)
959            with catch as w:
960                self.module.filterwarnings("always", category=UserWarning)
961                globals_dict['__file__'] = None
962                original_warnings.warn('test', UserWarning)
963                self.assertTrue(len(w))
964        finally:
965            globals_dict['__file__'] = oldfile
966
967    def test_stderr_none(self):
968        rc, stdout, stderr = assert_python_ok("-c",
969            "import sys; sys.stderr = None; "
970            "import warnings; warnings.simplefilter('always'); "
971            "warnings.warn('Warning!')")
972        self.assertEqual(stdout, b'')
973        self.assertNotIn(b'Warning!', stderr)
974        self.assertNotIn(b'Error', stderr)
975
976    def test_issue31285(self):
977        # warn_explicit() should neither raise a SystemError nor cause an
978        # assertion failure, in case the return value of get_source() has a
979        # bad splitlines() method.
980        get_source_called = []
981        def get_module_globals(*, splitlines_ret_val):
982            class BadSource(str):
983                def splitlines(self):
984                    return splitlines_ret_val
985
986            class BadLoader:
987                def get_source(self, fullname):
988                    get_source_called.append(splitlines_ret_val)
989                    return BadSource('spam')
990
991            loader = BadLoader()
992            spec = importlib.machinery.ModuleSpec('foobar', loader)
993            return {'__loader__': loader,
994                    '__spec__': spec,
995                    '__name__': 'foobar'}
996
997
998        wmod = self.module
999        with original_warnings.catch_warnings(module=wmod):
1000            wmod.filterwarnings('default', category=UserWarning)
1001
1002            linecache.clearcache()
1003            with support.captured_stderr() as stderr:
1004                wmod.warn_explicit(
1005                    'foo', UserWarning, 'bar', 1,
1006                    module_globals=get_module_globals(splitlines_ret_val=42))
1007            self.assertIn('UserWarning: foo', stderr.getvalue())
1008            self.assertEqual(get_source_called, [42])
1009
1010            linecache.clearcache()
1011            with support.swap_attr(wmod, '_showwarnmsg', None):
1012                del wmod._showwarnmsg
1013                with support.captured_stderr() as stderr:
1014                    wmod.warn_explicit(
1015                        'eggs', UserWarning, 'bar', 1,
1016                        module_globals=get_module_globals(splitlines_ret_val=[42]))
1017                self.assertIn('UserWarning: eggs', stderr.getvalue())
1018            self.assertEqual(get_source_called, [42, [42]])
1019            linecache.clearcache()
1020
1021    @support.cpython_only
1022    def test_issue31411(self):
1023        # warn_explicit() shouldn't raise a SystemError in case
1024        # warnings.onceregistry isn't a dictionary.
1025        wmod = self.module
1026        with original_warnings.catch_warnings(module=wmod):
1027            wmod.filterwarnings('once')
1028            with support.swap_attr(wmod, 'onceregistry', None):
1029                with self.assertRaises(TypeError):
1030                    wmod.warn_explicit('foo', Warning, 'bar', 1, registry=None)
1031
1032    @support.cpython_only
1033    def test_issue31416(self):
1034        # warn_explicit() shouldn't cause an assertion failure in case of a
1035        # bad warnings.filters or warnings.defaultaction.
1036        wmod = self.module
1037        with original_warnings.catch_warnings(module=wmod):
1038            wmod.filters = [(None, None, Warning, None, 0)]
1039            with self.assertRaises(TypeError):
1040                wmod.warn_explicit('foo', Warning, 'bar', 1)
1041
1042            wmod.filters = []
1043            with support.swap_attr(wmod, 'defaultaction', None), \
1044                 self.assertRaises(TypeError):
1045                wmod.warn_explicit('foo', Warning, 'bar', 1)
1046
1047    @support.cpython_only
1048    def test_issue31566(self):
1049        # warn() shouldn't cause an assertion failure in case of a bad
1050        # __name__ global.
1051        with original_warnings.catch_warnings(module=self.module):
1052            self.module.filterwarnings('error', category=UserWarning)
1053            with support.swap_item(globals(), '__name__', b'foo'), \
1054                 support.swap_item(globals(), '__file__', None):
1055                self.assertRaises(UserWarning, self.module.warn, 'bar')
1056
1057
1058class WarningsDisplayTests(BaseTest):
1059
1060    """Test the displaying of warnings and the ability to overload functions
1061    related to displaying warnings."""
1062
1063    def test_formatwarning(self):
1064        message = "msg"
1065        category = Warning
1066        file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
1067        line_num = 5
1068        file_line = linecache.getline(file_name, line_num).strip()
1069        format = "%s:%s: %s: %s\n  %s\n"
1070        expect = format % (file_name, line_num, category.__name__, message,
1071                            file_line)
1072        self.assertEqual(expect, self.module.formatwarning(message,
1073                                                category, file_name, line_num))
1074        # Test the 'line' argument.
1075        file_line += " for the win!"
1076        expect = format % (file_name, line_num, category.__name__, message,
1077                            file_line)
1078        self.assertEqual(expect, self.module.formatwarning(message,
1079                                    category, file_name, line_num, file_line))
1080
1081    def test_showwarning(self):
1082        file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
1083        line_num = 3
1084        expected_file_line = linecache.getline(file_name, line_num).strip()
1085        message = 'msg'
1086        category = Warning
1087        file_object = StringIO()
1088        expect = self.module.formatwarning(message, category, file_name,
1089                                            line_num)
1090        self.module.showwarning(message, category, file_name, line_num,
1091                                file_object)
1092        self.assertEqual(file_object.getvalue(), expect)
1093        # Test 'line' argument.
1094        expected_file_line += "for the win!"
1095        expect = self.module.formatwarning(message, category, file_name,
1096                                            line_num, expected_file_line)
1097        file_object = StringIO()
1098        self.module.showwarning(message, category, file_name, line_num,
1099                                file_object, expected_file_line)
1100        self.assertEqual(expect, file_object.getvalue())
1101
1102    def test_formatwarning_override(self):
1103        # bpo-35178: Test that a custom formatwarning function gets the 'line'
1104        # argument as a positional argument, and not only as a keyword argument
1105        def myformatwarning(message, category, filename, lineno, text):
1106            return f'm={message}:c={category}:f={filename}:l={lineno}:t={text}'
1107
1108        file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
1109        line_num = 3
1110        file_line = linecache.getline(file_name, line_num).strip()
1111        message = 'msg'
1112        category = Warning
1113        file_object = StringIO()
1114        expected = f'm={message}:c={category}:f={file_name}:l={line_num}' + \
1115                   f':t={file_line}'
1116        with support.swap_attr(self.module, 'formatwarning', myformatwarning):
1117            self.module.showwarning(message, category, file_name, line_num,
1118                                    file_object, file_line)
1119            self.assertEqual(file_object.getvalue(), expected)
1120
1121
1122class CWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
1123    module = c_warnings
1124
1125class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
1126    module = py_warnings
1127
1128    def test_tracemalloc(self):
1129        self.addCleanup(os_helper.unlink, os_helper.TESTFN)
1130
1131        with open(os_helper.TESTFN, 'w', encoding="utf-8") as fp:
1132            fp.write(textwrap.dedent("""
1133                def func():
1134                    f = open(__file__, "rb")
1135                    # Emit ResourceWarning
1136                    f = None
1137
1138                func()
1139            """))
1140
1141        def run(*args):
1142            res = assert_python_ok(*args, PYTHONIOENCODING='utf-8')
1143            stderr = res.err.decode('utf-8', 'replace')
1144            stderr = '\n'.join(stderr.splitlines())
1145
1146            # normalize newlines
1147            stderr = re.sub('<.*>', '<...>', stderr)
1148            return stderr
1149
1150        # tracemalloc disabled
1151        filename = os.path.abspath(os_helper.TESTFN)
1152        stderr = run('-Wd', os_helper.TESTFN)
1153        expected = textwrap.dedent(f'''
1154            {filename}:5: ResourceWarning: unclosed file <...>
1155              f = None
1156            ResourceWarning: Enable tracemalloc to get the object allocation traceback
1157        ''').strip()
1158        self.assertEqual(stderr, expected)
1159
1160        # tracemalloc enabled
1161        stderr = run('-Wd', '-X', 'tracemalloc=2', os_helper.TESTFN)
1162        expected = textwrap.dedent(f'''
1163            {filename}:5: ResourceWarning: unclosed file <...>
1164              f = None
1165            Object allocated at (most recent call last):
1166              File "{filename}", lineno 7
1167                func()
1168              File "{filename}", lineno 3
1169                f = open(__file__, "rb")
1170        ''').strip()
1171        self.assertEqual(stderr, expected)
1172
1173
1174class CatchWarningTests(BaseTest):
1175
1176    """Test catch_warnings()."""
1177
1178    def test_catch_warnings_restore(self):
1179        wmod = self.module
1180        orig_filters = wmod.filters
1181        orig_showwarning = wmod.showwarning
1182        # Ensure both showwarning and filters are restored when recording
1183        with wmod.catch_warnings(module=wmod, record=True):
1184            wmod.filters = wmod.showwarning = object()
1185        self.assertIs(wmod.filters, orig_filters)
1186        self.assertIs(wmod.showwarning, orig_showwarning)
1187        # Same test, but with recording disabled
1188        with wmod.catch_warnings(module=wmod, record=False):
1189            wmod.filters = wmod.showwarning = object()
1190        self.assertIs(wmod.filters, orig_filters)
1191        self.assertIs(wmod.showwarning, orig_showwarning)
1192
1193    def test_catch_warnings_recording(self):
1194        wmod = self.module
1195        # Ensure warnings are recorded when requested
1196        with wmod.catch_warnings(module=wmod, record=True) as w:
1197            self.assertEqual(w, [])
1198            self.assertIs(type(w), list)
1199            wmod.simplefilter("always")
1200            wmod.warn("foo")
1201            self.assertEqual(str(w[-1].message), "foo")
1202            wmod.warn("bar")
1203            self.assertEqual(str(w[-1].message), "bar")
1204            self.assertEqual(str(w[0].message), "foo")
1205            self.assertEqual(str(w[1].message), "bar")
1206            del w[:]
1207            self.assertEqual(w, [])
1208        # Ensure warnings are not recorded when not requested
1209        orig_showwarning = wmod.showwarning
1210        with wmod.catch_warnings(module=wmod, record=False) as w:
1211            self.assertIsNone(w)
1212            self.assertIs(wmod.showwarning, orig_showwarning)
1213
1214    def test_catch_warnings_reentry_guard(self):
1215        wmod = self.module
1216        # Ensure catch_warnings is protected against incorrect usage
1217        x = wmod.catch_warnings(module=wmod, record=True)
1218        self.assertRaises(RuntimeError, x.__exit__)
1219        with x:
1220            self.assertRaises(RuntimeError, x.__enter__)
1221        # Same test, but with recording disabled
1222        x = wmod.catch_warnings(module=wmod, record=False)
1223        self.assertRaises(RuntimeError, x.__exit__)
1224        with x:
1225            self.assertRaises(RuntimeError, x.__enter__)
1226
1227    def test_catch_warnings_defaults(self):
1228        wmod = self.module
1229        orig_filters = wmod.filters
1230        orig_showwarning = wmod.showwarning
1231        # Ensure default behaviour is not to record warnings
1232        with wmod.catch_warnings(module=wmod) as w:
1233            self.assertIsNone(w)
1234            self.assertIs(wmod.showwarning, orig_showwarning)
1235            self.assertIsNot(wmod.filters, orig_filters)
1236        self.assertIs(wmod.filters, orig_filters)
1237        if wmod is sys.modules['warnings']:
1238            # Ensure the default module is this one
1239            with wmod.catch_warnings() as w:
1240                self.assertIsNone(w)
1241                self.assertIs(wmod.showwarning, orig_showwarning)
1242                self.assertIsNot(wmod.filters, orig_filters)
1243            self.assertIs(wmod.filters, orig_filters)
1244
1245    def test_record_override_showwarning_before(self):
1246        # Issue #28835: If warnings.showwarning() was overridden, make sure
1247        # that catch_warnings(record=True) overrides it again.
1248        text = "This is a warning"
1249        wmod = self.module
1250        my_log = []
1251
1252        def my_logger(message, category, filename, lineno, file=None, line=None):
1253            nonlocal my_log
1254            my_log.append(message)
1255
1256        # Override warnings.showwarning() before calling catch_warnings()
1257        with support.swap_attr(wmod, 'showwarning', my_logger):
1258            with wmod.catch_warnings(module=wmod, record=True) as log:
1259                self.assertIsNot(wmod.showwarning, my_logger)
1260
1261                wmod.simplefilter("always")
1262                wmod.warn(text)
1263
1264            self.assertIs(wmod.showwarning, my_logger)
1265
1266        self.assertEqual(len(log), 1, log)
1267        self.assertEqual(log[0].message.args[0], text)
1268        self.assertEqual(my_log, [])
1269
1270    def test_record_override_showwarning_inside(self):
1271        # Issue #28835: It is possible to override warnings.showwarning()
1272        # in the catch_warnings(record=True) context manager.
1273        text = "This is a warning"
1274        wmod = self.module
1275        my_log = []
1276
1277        def my_logger(message, category, filename, lineno, file=None, line=None):
1278            nonlocal my_log
1279            my_log.append(message)
1280
1281        with wmod.catch_warnings(module=wmod, record=True) as log:
1282            wmod.simplefilter("always")
1283            wmod.showwarning = my_logger
1284            wmod.warn(text)
1285
1286        self.assertEqual(len(my_log), 1, my_log)
1287        self.assertEqual(my_log[0].args[0], text)
1288        self.assertEqual(log, [])
1289
1290    def test_check_warnings(self):
1291        # Explicit tests for the test.support convenience wrapper
1292        wmod = self.module
1293        if wmod is not sys.modules['warnings']:
1294            self.skipTest('module to test is not loaded warnings module')
1295        with warnings_helper.check_warnings(quiet=False) as w:
1296            self.assertEqual(w.warnings, [])
1297            wmod.simplefilter("always")
1298            wmod.warn("foo")
1299            self.assertEqual(str(w.message), "foo")
1300            wmod.warn("bar")
1301            self.assertEqual(str(w.message), "bar")
1302            self.assertEqual(str(w.warnings[0].message), "foo")
1303            self.assertEqual(str(w.warnings[1].message), "bar")
1304            w.reset()
1305            self.assertEqual(w.warnings, [])
1306
1307        with warnings_helper.check_warnings():
1308            # defaults to quiet=True without argument
1309            pass
1310        with warnings_helper.check_warnings(('foo', UserWarning)):
1311            wmod.warn("foo")
1312
1313        with self.assertRaises(AssertionError):
1314            with warnings_helper.check_warnings(('', RuntimeWarning)):
1315                # defaults to quiet=False with argument
1316                pass
1317        with self.assertRaises(AssertionError):
1318            with warnings_helper.check_warnings(('foo', RuntimeWarning)):
1319                wmod.warn("foo")
1320
1321class CCatchWarningTests(CatchWarningTests, unittest.TestCase):
1322    module = c_warnings
1323
1324class PyCatchWarningTests(CatchWarningTests, unittest.TestCase):
1325    module = py_warnings
1326
1327
1328class EnvironmentVariableTests(BaseTest):
1329
1330    def test_single_warning(self):
1331        rc, stdout, stderr = assert_python_ok("-c",
1332            "import sys; sys.stdout.write(str(sys.warnoptions))",
1333            PYTHONWARNINGS="ignore::DeprecationWarning",
1334            PYTHONDEVMODE="")
1335        self.assertEqual(stdout, b"['ignore::DeprecationWarning']")
1336
1337    def test_comma_separated_warnings(self):
1338        rc, stdout, stderr = assert_python_ok("-c",
1339            "import sys; sys.stdout.write(str(sys.warnoptions))",
1340            PYTHONWARNINGS="ignore::DeprecationWarning,ignore::UnicodeWarning",
1341            PYTHONDEVMODE="")
1342        self.assertEqual(stdout,
1343            b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']")
1344
1345    @force_not_colorized
1346    def test_envvar_and_command_line(self):
1347        rc, stdout, stderr = assert_python_ok("-Wignore::UnicodeWarning", "-c",
1348            "import sys; sys.stdout.write(str(sys.warnoptions))",
1349            PYTHONWARNINGS="ignore::DeprecationWarning",
1350            PYTHONDEVMODE="")
1351        self.assertEqual(stdout,
1352            b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']")
1353
1354    @force_not_colorized
1355    def test_conflicting_envvar_and_command_line(self):
1356        rc, stdout, stderr = assert_python_failure("-Werror::DeprecationWarning", "-c",
1357            "import sys, warnings; sys.stdout.write(str(sys.warnoptions)); "
1358            "warnings.warn('Message', DeprecationWarning)",
1359            PYTHONWARNINGS="default::DeprecationWarning",
1360            PYTHONDEVMODE="")
1361        self.assertEqual(stdout,
1362            b"['default::DeprecationWarning', 'error::DeprecationWarning']")
1363        self.assertEqual(stderr.splitlines(),
1364            [b"Traceback (most recent call last):",
1365             b"  File \"<string>\", line 1, in <module>",
1366             b'    import sys, warnings; sys.stdout.write(str(sys.warnoptions)); warnings.w'
1367             b"arn('Message', DeprecationWarning)",
1368             b'                                                                  ~~~~~~~~~~'
1369             b'~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^',
1370             b"DeprecationWarning: Message"])
1371
1372    def test_default_filter_configuration(self):
1373        pure_python_api = self.module is py_warnings
1374        if support.Py_DEBUG:
1375            expected_default_filters = []
1376        else:
1377            if pure_python_api:
1378                main_module_filter = re.compile("__main__")
1379            else:
1380                main_module_filter = "__main__"
1381            expected_default_filters = [
1382                ('default', None, DeprecationWarning, main_module_filter, 0),
1383                ('ignore', None, DeprecationWarning, None, 0),
1384                ('ignore', None, PendingDeprecationWarning, None, 0),
1385                ('ignore', None, ImportWarning, None, 0),
1386                ('ignore', None, ResourceWarning, None, 0),
1387            ]
1388        expected_output = [str(f).encode() for f in expected_default_filters]
1389
1390        if pure_python_api:
1391            # Disable the warnings acceleration module in the subprocess
1392            code = "import sys; sys.modules.pop('warnings', None); sys.modules['_warnings'] = None; "
1393        else:
1394            code = ""
1395        code += "import warnings; [print(f) for f in warnings.filters]"
1396
1397        rc, stdout, stderr = assert_python_ok("-c", code, __isolated=True)
1398        stdout_lines = [line.strip() for line in stdout.splitlines()]
1399        self.maxDiff = None
1400        self.assertEqual(stdout_lines, expected_output)
1401
1402
1403    @unittest.skipUnless(sys.getfilesystemencoding() != 'ascii',
1404                         'requires non-ascii filesystemencoding')
1405    def test_nonascii(self):
1406        PYTHONWARNINGS="ignore:DeprecationWarning" + os_helper.FS_NONASCII
1407        rc, stdout, stderr = assert_python_ok("-c",
1408            "import sys; sys.stdout.write(str(sys.warnoptions))",
1409            PYTHONIOENCODING="utf-8",
1410            PYTHONWARNINGS=PYTHONWARNINGS,
1411            PYTHONDEVMODE="")
1412        self.assertEqual(stdout, str([PYTHONWARNINGS]).encode())
1413
1414class CEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase):
1415    module = c_warnings
1416
1417class PyEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase):
1418    module = py_warnings
1419
1420
1421class _DeprecatedTest(BaseTest, unittest.TestCase):
1422
1423    """Test _deprecated()."""
1424
1425    module = original_warnings
1426
1427    def test_warning(self):
1428        version = (3, 11, 0, "final", 0)
1429        test = [(4, 12), (4, 11), (4, 0), (3, 12)]
1430        for remove in test:
1431            msg = rf".*test_warnings.*{remove[0]}\.{remove[1]}"
1432            filter = msg, DeprecationWarning
1433            with self.subTest(remove=remove):
1434                with warnings_helper.check_warnings(filter, quiet=False):
1435                    self.module._deprecated("test_warnings", remove=remove,
1436                                            _version=version)
1437
1438        version = (3, 11, 0, "alpha", 0)
1439        msg = r".*test_warnings.*3\.11"
1440        with warnings_helper.check_warnings((msg, DeprecationWarning), quiet=False):
1441            self.module._deprecated("test_warnings", remove=(3, 11),
1442                                    _version=version)
1443
1444    def test_RuntimeError(self):
1445        version = (3, 11, 0, "final", 0)
1446        test = [(2, 0), (2, 12), (3, 10)]
1447        for remove in test:
1448            with self.subTest(remove=remove):
1449                with self.assertRaises(RuntimeError):
1450                    self.module._deprecated("test_warnings", remove=remove,
1451                                            _version=version)
1452        for level in ["beta", "candidate", "final"]:
1453            version = (3, 11, 0, level, 0)
1454            with self.subTest(releaselevel=level):
1455                with self.assertRaises(RuntimeError):
1456                    self.module._deprecated("test_warnings", remove=(3, 11),
1457                                            _version=version)
1458
1459
1460class BootstrapTest(unittest.TestCase):
1461
1462    def test_issue_8766(self):
1463        # "import encodings" emits a warning whereas the warnings is not loaded
1464        # or not completely loaded (warnings imports indirectly encodings by
1465        # importing linecache) yet
1466        with os_helper.temp_cwd() as cwd, os_helper.temp_cwd('encodings'):
1467            # encodings loaded by initfsencoding()
1468            assert_python_ok('-c', 'pass', PYTHONPATH=cwd)
1469
1470            # Use -W to load warnings module at startup
1471            assert_python_ok('-c', 'pass', '-W', 'always', PYTHONPATH=cwd)
1472
1473
1474class FinalizationTest(unittest.TestCase):
1475    def test_finalization(self):
1476        # Issue #19421: warnings.warn() should not crash
1477        # during Python finalization
1478        code = """
1479import warnings
1480warn = warnings.warn
1481
1482class A:
1483    def __del__(self):
1484        warn("test")
1485
1486a=A()
1487        """
1488        rc, out, err = assert_python_ok("-c", code)
1489        self.assertEqual(err.decode().rstrip(),
1490                         '<string>:7: UserWarning: test')
1491
1492    def test_late_resource_warning(self):
1493        # Issue #21925: Emitting a ResourceWarning late during the Python
1494        # shutdown must be logged.
1495
1496        expected = b"<sys>:0: ResourceWarning: unclosed file "
1497
1498        # don't import the warnings module
1499        # (_warnings will try to import it)
1500        code = "f = open(%a)" % __file__
1501        rc, out, err = assert_python_ok("-Wd", "-c", code)
1502        self.assertTrue(err.startswith(expected), ascii(err))
1503
1504        # import the warnings module
1505        code = "import warnings; f = open(%a)" % __file__
1506        rc, out, err = assert_python_ok("-Wd", "-c", code)
1507        self.assertTrue(err.startswith(expected), ascii(err))
1508
1509
1510class DeprecatedTests(unittest.TestCase):
1511    def test_dunder_deprecated(self):
1512        @deprecated("A will go away soon")
1513        class A:
1514            pass
1515
1516        self.assertEqual(A.__deprecated__, "A will go away soon")
1517        self.assertIsInstance(A, type)
1518
1519        @deprecated("b will go away soon")
1520        def b():
1521            pass
1522
1523        self.assertEqual(b.__deprecated__, "b will go away soon")
1524        self.assertIsInstance(b, types.FunctionType)
1525
1526        @overload
1527        @deprecated("no more ints")
1528        def h(x: int) -> int: ...
1529        @overload
1530        def h(x: str) -> str: ...
1531        def h(x):
1532            return x
1533
1534        overloads = get_overloads(h)
1535        self.assertEqual(len(overloads), 2)
1536        self.assertEqual(overloads[0].__deprecated__, "no more ints")
1537
1538    def test_class(self):
1539        @deprecated("A will go away soon")
1540        class A:
1541            pass
1542
1543        with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"):
1544            A()
1545        with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"):
1546            with self.assertRaises(TypeError):
1547                A(42)
1548
1549    def test_class_with_init(self):
1550        @deprecated("HasInit will go away soon")
1551        class HasInit:
1552            def __init__(self, x):
1553                self.x = x
1554
1555        with self.assertWarnsRegex(DeprecationWarning, "HasInit will go away soon"):
1556            instance = HasInit(42)
1557        self.assertEqual(instance.x, 42)
1558
1559    def test_class_with_new(self):
1560        has_new_called = False
1561
1562        @deprecated("HasNew will go away soon")
1563        class HasNew:
1564            def __new__(cls, x):
1565                nonlocal has_new_called
1566                has_new_called = True
1567                return super().__new__(cls)
1568
1569            def __init__(self, x) -> None:
1570                self.x = x
1571
1572        with self.assertWarnsRegex(DeprecationWarning, "HasNew will go away soon"):
1573            instance = HasNew(42)
1574        self.assertEqual(instance.x, 42)
1575        self.assertTrue(has_new_called)
1576
1577    def test_class_with_inherited_new(self):
1578        new_base_called = False
1579
1580        class NewBase:
1581            def __new__(cls, x):
1582                nonlocal new_base_called
1583                new_base_called = True
1584                return super().__new__(cls)
1585
1586            def __init__(self, x) -> None:
1587                self.x = x
1588
1589        @deprecated("HasInheritedNew will go away soon")
1590        class HasInheritedNew(NewBase):
1591            pass
1592
1593        with self.assertWarnsRegex(DeprecationWarning, "HasInheritedNew will go away soon"):
1594            instance = HasInheritedNew(42)
1595        self.assertEqual(instance.x, 42)
1596        self.assertTrue(new_base_called)
1597
1598    def test_class_with_new_but_no_init(self):
1599        new_called = False
1600
1601        @deprecated("HasNewNoInit will go away soon")
1602        class HasNewNoInit:
1603            def __new__(cls, x):
1604                nonlocal new_called
1605                new_called = True
1606                obj = super().__new__(cls)
1607                obj.x = x
1608                return obj
1609
1610        with self.assertWarnsRegex(DeprecationWarning, "HasNewNoInit will go away soon"):
1611            instance = HasNewNoInit(42)
1612        self.assertEqual(instance.x, 42)
1613        self.assertTrue(new_called)
1614
1615    def test_mixin_class(self):
1616        @deprecated("Mixin will go away soon")
1617        class Mixin:
1618            pass
1619
1620        class Base:
1621            def __init__(self, a) -> None:
1622                self.a = a
1623
1624        with self.assertWarnsRegex(DeprecationWarning, "Mixin will go away soon"):
1625            class Child(Base, Mixin):
1626                pass
1627
1628        instance = Child(42)
1629        self.assertEqual(instance.a, 42)
1630
1631    def test_existing_init_subclass(self):
1632        @deprecated("C will go away soon")
1633        class C:
1634            def __init_subclass__(cls) -> None:
1635                cls.inited = True
1636
1637        with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"):
1638            C()
1639
1640        with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"):
1641            class D(C):
1642                pass
1643
1644        self.assertTrue(D.inited)
1645        self.assertIsInstance(D(), D)  # no deprecation
1646
1647    def test_existing_init_subclass_in_base(self):
1648        class Base:
1649            def __init_subclass__(cls, x) -> None:
1650                cls.inited = x
1651
1652        @deprecated("C will go away soon")
1653        class C(Base, x=42):
1654            pass
1655
1656        self.assertEqual(C.inited, 42)
1657
1658        with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"):
1659            C()
1660
1661        with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"):
1662            class D(C, x=3):
1663                pass
1664
1665        self.assertEqual(D.inited, 3)
1666
1667    def test_init_subclass_has_correct_cls(self):
1668        init_subclass_saw = None
1669
1670        @deprecated("Base will go away soon")
1671        class Base:
1672            def __init_subclass__(cls) -> None:
1673                nonlocal init_subclass_saw
1674                init_subclass_saw = cls
1675
1676        self.assertIsNone(init_subclass_saw)
1677
1678        with self.assertWarnsRegex(DeprecationWarning, "Base will go away soon"):
1679            class C(Base):
1680                pass
1681
1682        self.assertIs(init_subclass_saw, C)
1683
1684    def test_init_subclass_with_explicit_classmethod(self):
1685        init_subclass_saw = None
1686
1687        @deprecated("Base will go away soon")
1688        class Base:
1689            @classmethod
1690            def __init_subclass__(cls) -> None:
1691                nonlocal init_subclass_saw
1692                init_subclass_saw = cls
1693
1694        self.assertIsNone(init_subclass_saw)
1695
1696        with self.assertWarnsRegex(DeprecationWarning, "Base will go away soon"):
1697            class C(Base):
1698                pass
1699
1700        self.assertIs(init_subclass_saw, C)
1701
1702    def test_function(self):
1703        @deprecated("b will go away soon")
1704        def b():
1705            pass
1706
1707        with self.assertWarnsRegex(DeprecationWarning, "b will go away soon"):
1708            b()
1709
1710    def test_method(self):
1711        class Capybara:
1712            @deprecated("x will go away soon")
1713            def x(self):
1714                pass
1715
1716        instance = Capybara()
1717        with self.assertWarnsRegex(DeprecationWarning, "x will go away soon"):
1718            instance.x()
1719
1720    def test_property(self):
1721        class Capybara:
1722            @property
1723            @deprecated("x will go away soon")
1724            def x(self):
1725                pass
1726
1727            @property
1728            def no_more_setting(self):
1729                return 42
1730
1731            @no_more_setting.setter
1732            @deprecated("no more setting")
1733            def no_more_setting(self, value):
1734                pass
1735
1736        instance = Capybara()
1737        with self.assertWarnsRegex(DeprecationWarning, "x will go away soon"):
1738            instance.x
1739
1740        with py_warnings.catch_warnings():
1741            py_warnings.simplefilter("error")
1742            self.assertEqual(instance.no_more_setting, 42)
1743
1744        with self.assertWarnsRegex(DeprecationWarning, "no more setting"):
1745            instance.no_more_setting = 42
1746
1747    def test_category(self):
1748        @deprecated("c will go away soon", category=RuntimeWarning)
1749        def c():
1750            pass
1751
1752        with self.assertWarnsRegex(RuntimeWarning, "c will go away soon"):
1753            c()
1754
1755    def test_turn_off_warnings(self):
1756        @deprecated("d will go away soon", category=None)
1757        def d():
1758            pass
1759
1760        with py_warnings.catch_warnings():
1761            py_warnings.simplefilter("error")
1762            d()
1763
1764    def test_only_strings_allowed(self):
1765        with self.assertRaisesRegex(
1766            TypeError,
1767            "Expected an object of type str for 'message', not 'type'"
1768        ):
1769            @deprecated
1770            class Foo: ...
1771
1772        with self.assertRaisesRegex(
1773            TypeError,
1774            "Expected an object of type str for 'message', not 'function'"
1775        ):
1776            @deprecated
1777            def foo(): ...
1778
1779    def test_no_retained_references_to_wrapper_instance(self):
1780        @deprecated('depr')
1781        def d(): pass
1782
1783        self.assertFalse(any(
1784            isinstance(cell.cell_contents, deprecated) for cell in d.__closure__
1785        ))
1786
1787    def test_inspect(self):
1788        @deprecated("depr")
1789        def sync():
1790            pass
1791
1792        @deprecated("depr")
1793        async def coro():
1794            pass
1795
1796        class Cls:
1797            @deprecated("depr")
1798            def sync(self):
1799                pass
1800
1801            @deprecated("depr")
1802            async def coro(self):
1803                pass
1804
1805        self.assertFalse(inspect.iscoroutinefunction(sync))
1806        self.assertTrue(inspect.iscoroutinefunction(coro))
1807        self.assertFalse(inspect.iscoroutinefunction(Cls.sync))
1808        self.assertTrue(inspect.iscoroutinefunction(Cls.coro))
1809
1810def setUpModule():
1811    py_warnings.onceregistry.clear()
1812    c_warnings.onceregistry.clear()
1813
1814tearDownModule = setUpModule
1815
1816if __name__ == "__main__":
1817    unittest.main()
1818