test_warnings.py 36.6 KB
Newer Older
Christian Heimes's avatar
Christian Heimes committed
1
from contextlib import contextmanager
2
import linecache
3
import os
4
from io import StringIO
5
import sys
6
import unittest
7
from test import support
8
from test.script_helper import assert_python_ok
9

10
from test import warning_tests
11

Christian Heimes's avatar
Christian Heimes committed
12 13
import warnings as original_warnings

14 15
py_warnings = support.import_fresh_module('warnings', blocked=['_warnings'])
c_warnings = support.import_fresh_module('warnings', fresh=['_warnings'])
Christian Heimes's avatar
Christian Heimes committed
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

@contextmanager
def warnings_state(module):
    """Use a specific warnings implementation in warning_tests."""
    global __warningregistry__
    for to_clear in (sys, warning_tests):
        try:
            to_clear.__warningregistry__.clear()
        except AttributeError:
            pass
    try:
        __warningregistry__.clear()
    except NameError:
        pass
    original_warnings = warning_tests.warnings
31
    original_filters = module.filters
Christian Heimes's avatar
Christian Heimes committed
32
    try:
33 34
        module.filters = original_filters[:]
        module.simplefilter("once")
Christian Heimes's avatar
Christian Heimes committed
35 36 37 38
        warning_tests.warnings = module
        yield
    finally:
        warning_tests.warnings = original_warnings
39
        module.filters = original_filters
Christian Heimes's avatar
Christian Heimes committed
40 41


42
class BaseTest:
Christian Heimes's avatar
Christian Heimes committed
43 44 45

    """Basic bookkeeping required for testing."""

46
    def setUp(self):
Christian Heimes's avatar
Christian Heimes committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
        # The __warningregistry__ needs to be in a pristine state for tests
        # to work properly.
        if '__warningregistry__' in globals():
            del globals()['__warningregistry__']
        if hasattr(warning_tests, '__warningregistry__'):
            del warning_tests.__warningregistry__
        if hasattr(sys, '__warningregistry__'):
            del sys.__warningregistry__
        # The 'warnings' module must be explicitly set so that the proper
        # interaction between _warnings and 'warnings' can be controlled.
        sys.modules['warnings'] = self.module
        super(BaseTest, self).setUp()

    def tearDown(self):
        sys.modules['warnings'] = original_warnings
        super(BaseTest, self).tearDown()
63

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
class PublicAPITests(BaseTest):

    """Ensures that the correct values are exposed in the
    public API.
    """

    def test_module_all_attribute(self):
        self.assertTrue(hasattr(self.module, '__all__'))
        target_api = ["warn", "warn_explicit", "showwarning",
                      "formatwarning", "filterwarnings", "simplefilter",
                      "resetwarnings", "catch_warnings"]
        self.assertSetEqual(set(self.module.__all__),
                            set(target_api))

class CPublicAPITests(PublicAPITests, unittest.TestCase):
    module = c_warnings

class PyPublicAPITests(PublicAPITests, unittest.TestCase):
    module = py_warnings
83

84
class FilterTests(BaseTest):
Christian Heimes's avatar
Christian Heimes committed
85 86 87 88

    """Testing the filtering functionality."""

    def test_error(self):
89
        with original_warnings.catch_warnings(module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
90 91 92 93 94
            self.module.resetwarnings()
            self.module.filterwarnings("error", category=UserWarning)
            self.assertRaises(UserWarning, self.module.warn,
                                "FilterTests.test_error")

95 96 97 98 99 100 101 102 103 104
    def test_error_after_default(self):
        with original_warnings.catch_warnings(module=self.module) as w:
            self.module.resetwarnings()
            message = "FilterTests.test_ignore_after_default"
            def f():
                self.module.warn(message, UserWarning)
            f()
            self.module.filterwarnings("error", category=UserWarning)
            self.assertRaises(UserWarning, f)

Christian Heimes's avatar
Christian Heimes committed
105
    def test_ignore(self):
106 107
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
108 109 110
            self.module.resetwarnings()
            self.module.filterwarnings("ignore", category=UserWarning)
            self.module.warn("FilterTests.test_ignore", UserWarning)
111
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
112

113 114 115 116 117 118 119 120 121 122 123 124 125
    def test_ignore_after_default(self):
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
            self.module.resetwarnings()
            message = "FilterTests.test_ignore_after_default"
            def f():
                self.module.warn(message, UserWarning)
            f()
            self.module.filterwarnings("ignore", category=UserWarning)
            f()
            f()
            self.assertEqual(len(w), 1)

Christian Heimes's avatar
Christian Heimes committed
126
    def test_always(self):
127 128
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
129 130 131 132
            self.module.resetwarnings()
            self.module.filterwarnings("always", category=UserWarning)
            message = "FilterTests.test_always"
            self.module.warn(message, UserWarning)
133
            self.assertTrue(message, w[-1].message)
Christian Heimes's avatar
Christian Heimes committed
134
            self.module.warn(message, UserWarning)
135
            self.assertTrue(w[-1].message, message)
Christian Heimes's avatar
Christian Heimes committed
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    def test_always_after_default(self):
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
            self.module.resetwarnings()
            message = "FilterTests.test_always_after_ignore"
            def f():
                self.module.warn(message, UserWarning)
            f()
            self.assertEqual(len(w), 1)
            self.assertEqual(w[-1].message.args[0], message)
            f()
            self.assertEqual(len(w), 1)
            self.module.filterwarnings("always", category=UserWarning)
            f()
            self.assertEqual(len(w), 2)
            self.assertEqual(w[-1].message.args[0], message)
            f()
            self.assertEqual(len(w), 3)
            self.assertEqual(w[-1].message.args[0], message)

Christian Heimes's avatar
Christian Heimes committed
157
    def test_default(self):
158 159
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
160 161 162 163 164 165
            self.module.resetwarnings()
            self.module.filterwarnings("default", category=UserWarning)
            message = UserWarning("FilterTests.test_default")
            for x in range(2):
                self.module.warn(message, UserWarning)
                if x == 0:
166
                    self.assertEqual(w[-1].message, message)
167
                    del w[:]
Christian Heimes's avatar
Christian Heimes committed
168
                elif x == 1:
169
                    self.assertEqual(len(w), 0)
170
                else:
Christian Heimes's avatar
Christian Heimes committed
171 172 173
                    raise ValueError("loop variant unhandled")

    def test_module(self):
174 175
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
176 177 178 179
            self.module.resetwarnings()
            self.module.filterwarnings("module", category=UserWarning)
            message = UserWarning("FilterTests.test_module")
            self.module.warn(message, UserWarning)
180
            self.assertEqual(w[-1].message, message)
181
            del w[:]
Christian Heimes's avatar
Christian Heimes committed
182
            self.module.warn(message, UserWarning)
183
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
184 185

    def test_once(self):
186 187
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
188 189 190 191 192
            self.module.resetwarnings()
            self.module.filterwarnings("once", category=UserWarning)
            message = UserWarning("FilterTests.test_once")
            self.module.warn_explicit(message, UserWarning, "test_warnings.py",
                                    42)
193
            self.assertEqual(w[-1].message, message)
194
            del w[:]
Christian Heimes's avatar
Christian Heimes committed
195 196
            self.module.warn_explicit(message, UserWarning, "test_warnings.py",
                                    13)
197
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
198 199
            self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
                                    42)
200
            self.assertEqual(len(w), 0)
201

Christian Heimes's avatar
Christian Heimes committed
202
    def test_inheritance(self):
203
        with original_warnings.catch_warnings(module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
204 205 206 207 208 209
            self.module.resetwarnings()
            self.module.filterwarnings("error", category=Warning)
            self.assertRaises(UserWarning, self.module.warn,
                                "FilterTests.test_inheritance", UserWarning)

    def test_ordering(self):
210 211
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
212 213 214 215
            self.module.resetwarnings()
            self.module.filterwarnings("ignore", category=UserWarning)
            self.module.filterwarnings("error", category=UserWarning,
                                        append=True)
216
            del w[:]
Christian Heimes's avatar
Christian Heimes committed
217 218 219 220
            try:
                self.module.warn("FilterTests.test_ordering", UserWarning)
            except UserWarning:
                self.fail("order handling for actions failed")
221
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
222 223

    def test_filterwarnings(self):
224 225
        # Test filterwarnings().
        # Implicitly also tests resetwarnings().
226 227
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
228 229
            self.module.filterwarnings("error", "", Warning, "", 0)
            self.assertRaises(UserWarning, self.module.warn, 'convert to error')
230

Christian Heimes's avatar
Christian Heimes committed
231
            self.module.resetwarnings()
232
            text = 'handle normally'
Christian Heimes's avatar
Christian Heimes committed
233
            self.module.warn(text)
234
            self.assertEqual(str(w[-1].message), text)
235
            self.assertTrue(w[-1].category is UserWarning)
236

Christian Heimes's avatar
Christian Heimes committed
237
            self.module.filterwarnings("ignore", "", Warning, "", 0)
238
            text = 'filtered out'
Christian Heimes's avatar
Christian Heimes committed
239
            self.module.warn(text)
240
            self.assertNotEqual(str(w[-1].message), text)
241

Christian Heimes's avatar
Christian Heimes committed
242 243 244
            self.module.resetwarnings()
            self.module.filterwarnings("error", "hex*", Warning, "", 0)
            self.assertRaises(UserWarning, self.module.warn, 'hex/oct')
245
            text = 'nonmatching text'
Christian Heimes's avatar
Christian Heimes committed
246
            self.module.warn(text)
247
            self.assertEqual(str(w[-1].message), text)
248
            self.assertTrue(w[-1].category is UserWarning)
249

250 251 252 253 254 255 256 257 258 259 260 261
    def test_mutate_filter_list(self):
        class X:
            def match(self, a):
                L[:] = []

        L = [("default",X(),UserWarning,X(),0) for i in range(2)]
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
            self.module.filters = L
            self.module.warn_explicit(UserWarning("b"), None, "f.py", 42)
            self.assertEqual(str(w[-1].message), "b")

262
class CFilterTests(FilterTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
263 264
    module = c_warnings

265
class PyFilterTests(FilterTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
266 267 268
    module = py_warnings


269
class WarnTests(BaseTest):
Christian Heimes's avatar
Christian Heimes committed
270 271 272 273

    """Test warnings.warn() and warnings.warn_explicit()."""

    def test_message(self):
274 275
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
276
            self.module.simplefilter("once")
Christian Heimes's avatar
Christian Heimes committed
277 278 279
            for i in range(4):
                text = 'multi %d' %i  # Different text on each call.
                self.module.warn(text)
280
                self.assertEqual(str(w[-1].message), text)
281
                self.assertTrue(w[-1].category is UserWarning)
282

283 284 285 286
    # Issue 3639
    def test_warn_nonstandard_types(self):
        # warn() should handle non-standard types without issue.
        for ob in (Warning, None, 42):
Benjamin Peterson's avatar
Benjamin Peterson committed
287 288
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
289
                self.module.simplefilter("once")
290 291 292
                self.module.warn(ob)
                # Don't directly compare objects since
                # ``Warning() != Warning()``.
293
                self.assertEqual(str(w[-1].message), str(UserWarning(ob)))
294

295
    def test_filename(self):
Christian Heimes's avatar
Christian Heimes committed
296
        with warnings_state(self.module):
297 298
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
299
                warning_tests.inner("spam1")
300 301
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
Christian Heimes's avatar
Christian Heimes committed
302
                warning_tests.outer("spam2")
303 304
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
305 306 307 308

    def test_stacklevel(self):
        # Test stacklevel argument
        # make sure all messages are different, so the warning won't be skipped
Christian Heimes's avatar
Christian Heimes committed
309
        with warnings_state(self.module):
310 311
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
312
                warning_tests.inner("spam3", stacklevel=1)
313 314
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
Christian Heimes's avatar
Christian Heimes committed
315
                warning_tests.outer("spam4", stacklevel=1)
316 317
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
Christian Heimes's avatar
Christian Heimes committed
318 319

                warning_tests.inner("spam5", stacklevel=2)
320 321
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "test_warnings.py")
Christian Heimes's avatar
Christian Heimes committed
322
                warning_tests.outer("spam6", stacklevel=2)
323 324
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
325
                warning_tests.outer("spam6.5", stacklevel=3)
326 327
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "test_warnings.py")
Christian Heimes's avatar
Christian Heimes committed
328 329

                warning_tests.inner("spam7", stacklevel=9999)
330 331
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "sys")
Christian Heimes's avatar
Christian Heimes committed
332

Christian Heimes's avatar
Christian Heimes committed
333 334 335 336 337 338 339
    def test_missing_filename_not_main(self):
        # If __file__ is not specified and __main__ is not the module name,
        # then __file__ should be set to the module name.
        filename = warning_tests.__file__
        try:
            del warning_tests.__file__
            with warnings_state(self.module):
340 341
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
342
                    warning_tests.inner("spam8", stacklevel=1)
343
                    self.assertEqual(w[-1].filename, warning_tests.__name__)
Christian Heimes's avatar
Christian Heimes committed
344 345 346
        finally:
            warning_tests.__file__ = filename

347
    @unittest.skipUnless(hasattr(sys, 'argv'), 'test needs sys.argv')
Christian Heimes's avatar
Christian Heimes committed
348 349 350 351 352 353 354 355 356
    def test_missing_filename_main_with_argv(self):
        # If __file__ is not specified and the caller is __main__ and sys.argv
        # exists, then use sys.argv[0] as the file.
        filename = warning_tests.__file__
        module_name = warning_tests.__name__
        try:
            del warning_tests.__file__
            warning_tests.__name__ = '__main__'
            with warnings_state(self.module):
357 358
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
359
                    warning_tests.inner('spam9', stacklevel=1)
360
                    self.assertEqual(w[-1].filename, sys.argv[0])
Christian Heimes's avatar
Christian Heimes committed
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
        finally:
            warning_tests.__file__ = filename
            warning_tests.__name__ = module_name

    def test_missing_filename_main_without_argv(self):
        # If __file__ is not specified, the caller is __main__, and sys.argv
        # is not set, then '__main__' is the file name.
        filename = warning_tests.__file__
        module_name = warning_tests.__name__
        argv = sys.argv
        try:
            del warning_tests.__file__
            warning_tests.__name__ = '__main__'
            del sys.argv
            with warnings_state(self.module):
376 377
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
378
                    warning_tests.inner('spam10', stacklevel=1)
379
                    self.assertEqual(w[-1].filename, '__main__')
Christian Heimes's avatar
Christian Heimes committed
380 381 382 383 384
        finally:
            warning_tests.__file__ = filename
            warning_tests.__name__ = module_name
            sys.argv = argv

Christian Heimes's avatar
Christian Heimes committed
385
    def test_missing_filename_main_with_argv_empty_string(self):
Christian Heimes's avatar
Christian Heimes committed
386 387 388 389 390 391 392 393 394 395 396
        # If __file__ is not specified, the caller is __main__, and sys.argv[0]
        # is the empty string, then '__main__ is the file name.
        # Tests issue 2743.
        file_name = warning_tests.__file__
        module_name = warning_tests.__name__
        argv = sys.argv
        try:
            del warning_tests.__file__
            warning_tests.__name__ = '__main__'
            sys.argv = ['']
            with warnings_state(self.module):
397 398
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
399
                    warning_tests.inner('spam11', stacklevel=1)
400
                    self.assertEqual(w[-1].filename, '__main__')
Christian Heimes's avatar
Christian Heimes committed
401 402 403 404 405
        finally:
            warning_tests.__file__ = file_name
            warning_tests.__name__ = module_name
            sys.argv = argv

406 407 408 409 410
    def test_warn_explicit_non_ascii_filename(self):
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
            self.module.resetwarnings()
            self.module.filterwarnings("always", category=UserWarning)
411 412 413 414 415 416 417
            for filename in ("nonascii\xe9\u20ac", "surrogate\udc80"):
                try:
                    os.fsencode(filename)
                except UnicodeEncodeError:
                    continue
                self.module.warn_explicit("text", UserWarning, filename, 1)
                self.assertEqual(w[-1].filename, filename)
418

419
    def test_warn_explicit_type_errors(self):
420
        # warn_explicit() should error out gracefully if it is given objects
421 422 423 424 425 426 427 428 429 430 431 432 433
        # of the wrong types.
        # lineno is expected to be an integer.
        self.assertRaises(TypeError, self.module.warn_explicit,
                            None, UserWarning, None, None)
        # Either 'message' needs to be an instance of Warning or 'category'
        # needs to be a subclass.
        self.assertRaises(TypeError, self.module.warn_explicit,
                            None, None, None, 1)
        # 'registry' must be a dict or None.
        self.assertRaises((TypeError, AttributeError),
                            self.module.warn_explicit,
                            None, Warning, None, 1, registry=42)

434 435 436 437 438 439 440 441 442 443 444 445 446 447
    def test_bad_str(self):
        # issue 6415
        # Warnings instance with a bad format string for __str__ should not
        # trigger a bus error.
        class BadStrWarning(Warning):
            """Warning with a bad format string for __str__."""
            def __str__(self):
                return ("A bad formatted string %(err)" %
                        {"err" : "there is no %(err)s"})

        with self.assertRaises(ValueError):
            self.module.warn(BadStrWarning())


448
class CWarnTests(WarnTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
449 450
    module = c_warnings

451 452 453 454 455 456
    # As an early adopter, we sanity check the
    # test.support.import_fresh_module utility function
    def test_accelerated(self):
        self.assertFalse(original_warnings is self.module)
        self.assertFalse(hasattr(self.module.warn, '__code__'))

457
class PyWarnTests(WarnTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
458 459
    module = py_warnings

460 461 462 463 464 465
    # As an early adopter, we sanity check the
    # test.support.import_fresh_module utility function
    def test_pure_python(self):
        self.assertFalse(original_warnings is self.module)
        self.assertTrue(hasattr(self.module.warn, '__code__'))

Christian Heimes's avatar
Christian Heimes committed
466

467
class WCmdLineTests(BaseTest):
Christian Heimes's avatar
Christian Heimes committed
468 469 470 471

    def test_improper_input(self):
        # Uses the private _setoption() function to test the parsing
        # of command-line warning arguments
472
        with original_warnings.catch_warnings(module=self.module):
Christian Heimes's avatar
Christian Heimes committed
473 474 475 476 477 478 479 480 481
            self.assertRaises(self.module._OptionError,
                              self.module._setoption, '1:2:3:4:5:6')
            self.assertRaises(self.module._OptionError,
                              self.module._setoption, 'bogus::Warning')
            self.assertRaises(self.module._OptionError,
                              self.module._setoption, 'ignore:2::4:-5')
            self.module._setoption('error::Warning::0')
            self.assertRaises(UserWarning, self.module.warn, 'convert to error')

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
    def test_improper_option(self):
        # Same as above, but check that the message is printed out when
        # the interpreter is executed. This also checks that options are
        # actually parsed at all.
        rc, out, err = assert_python_ok("-Wxxx", "-c", "pass")
        self.assertIn(b"Invalid -W option ignored: invalid action: 'xxx'", err)

    def test_warnings_bootstrap(self):
        # Check that the warnings module does get loaded when -W<some option>
        # is used (see issue #10372 for an example of silent bootstrap failure).
        rc, out, err = assert_python_ok("-Wi", "-c",
            "import sys; sys.modules['warnings'].warn('foo', RuntimeWarning)")
        # '-Wi' was observed
        self.assertFalse(out.strip())
        self.assertNotIn(b'RuntimeWarning', err)

498
class CWCmdLineTests(WCmdLineTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
499 500
    module = c_warnings

501
class PyWCmdLineTests(WCmdLineTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
502 503 504
    module = py_warnings


505
class _WarningsTests(BaseTest, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
506 507 508 509

    """Tests specific to the _warnings module."""

    module = c_warnings
510

Christian Heimes's avatar
Christian Heimes committed
511 512
    def test_filter(self):
        # Everything should function even if 'filters' is not in warnings.
513
        with original_warnings.catch_warnings(module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
514 515 516 517 518 519
            self.module.filterwarnings("error", "", Warning, "", 0)
            self.assertRaises(UserWarning, self.module.warn,
                                'convert to error')
            del self.module.filters
            self.assertRaises(UserWarning, self.module.warn,
                                'convert to error')
520

Christian Heimes's avatar
Christian Heimes committed
521 522 523 524 525 526 527
    def test_onceregistry(self):
        # Replacing or removing the onceregistry should be okay.
        global __warningregistry__
        message = UserWarning('onceregistry test')
        try:
            original_registry = self.module.onceregistry
            __warningregistry__ = {}
528 529
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
530 531 532
                self.module.resetwarnings()
                self.module.filterwarnings("once", category=UserWarning)
                self.module.warn_explicit(message, UserWarning, "file", 42)
533
                self.assertEqual(w[-1].message, message)
534
                del w[:]
Christian Heimes's avatar
Christian Heimes committed
535
                self.module.warn_explicit(message, UserWarning, "file", 42)
536
                self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
537 538 539 540
                # Test the resetting of onceregistry.
                self.module.onceregistry = {}
                __warningregistry__ = {}
                self.module.warn('onceregistry test')
541
                self.assertEqual(w[-1].message.args, message.args)
Christian Heimes's avatar
Christian Heimes committed
542
                # Removal of onceregistry is okay.
543
                del w[:]
Christian Heimes's avatar
Christian Heimes committed
544 545 546
                del self.module.onceregistry
                __warningregistry__ = {}
                self.module.warn_explicit(message, UserWarning, "file", 42)
547
                self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
548 549 550
        finally:
            self.module.onceregistry = original_registry

551 552 553 554 555 556 557 558 559 560 561 562 563
    def test_default_action(self):
        # Replacing or removing defaultaction should be okay.
        message = UserWarning("defaultaction test")
        original = self.module.defaultaction
        try:
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
                self.module.resetwarnings()
                registry = {}
                self.module.warn_explicit(message, UserWarning, "<test>", 42,
                                            registry=registry)
                self.assertEqual(w[-1].message, message)
                self.assertEqual(len(w), 1)
564 565 566
                # One actual registry key plus the "version" key
                self.assertEqual(len(registry), 2)
                self.assertIn("version", registry)
567 568 569 570 571 572 573 574 575
                del w[:]
                # Test removal.
                del self.module.defaultaction
                __warningregistry__ = {}
                registry = {}
                self.module.warn_explicit(message, UserWarning, "<test>", 43,
                                            registry=registry)
                self.assertEqual(w[-1].message, message)
                self.assertEqual(len(w), 1)
576
                self.assertEqual(len(registry), 2)
577 578 579 580 581 582 583 584 585 586 587
                del w[:]
                # Test setting.
                self.module.defaultaction = "ignore"
                __warningregistry__ = {}
                registry = {}
                self.module.warn_explicit(message, UserWarning, "<test>", 44,
                                            registry=registry)
                self.assertEqual(len(w), 0)
        finally:
            self.module.defaultaction = original

Christian Heimes's avatar
Christian Heimes committed
588 589 590
    def test_showwarning_missing(self):
        # Test that showwarning() missing is okay.
        text = 'del showwarning test'
591
        with original_warnings.catch_warnings(module=self.module):
Christian Heimes's avatar
Christian Heimes committed
592 593
            self.module.filterwarnings("always", category=UserWarning)
            del self.module.showwarning
594
            with support.captured_output('stderr') as stream:
Christian Heimes's avatar
Christian Heimes committed
595 596
                self.module.warn(text)
                result = stream.getvalue()
597
        self.assertIn(text, result)
Christian Heimes's avatar
Christian Heimes committed
598

599
    def test_showwarning_not_callable(self):
600 601
        with original_warnings.catch_warnings(module=self.module):
            self.module.filterwarnings("always", category=UserWarning)
602 603 604
            self.module.showwarning = print
            with support.captured_output('stdout'):
                self.module.warn('Warning!')
605
            self.module.showwarning = 23
606
            self.assertRaises(TypeError, self.module.warn, "Warning!")
607

Christian Heimes's avatar
Christian Heimes committed
608 609 610
    def test_show_warning_output(self):
        # With showarning() missing, make sure that output is okay.
        text = 'test show_warning'
611
        with original_warnings.catch_warnings(module=self.module):
Christian Heimes's avatar
Christian Heimes committed
612 613
            self.module.filterwarnings("always", category=UserWarning)
            del self.module.showwarning
614
            with support.captured_output('stderr') as stream:
Christian Heimes's avatar
Christian Heimes committed
615 616
                warning_tests.inner(text)
                result = stream.getvalue()
617
        self.assertEqual(result.count('\n'), 2,
Christian Heimes's avatar
Christian Heimes committed
618 619 620
                             "Too many newlines in %r" % result)
        first_line, second_line = result.split('\n', 1)
        expected_file = os.path.splitext(warning_tests.__file__)[0] + '.py'
Neal Norwitz's avatar
Neal Norwitz committed
621 622
        first_line_parts = first_line.rsplit(':', 3)
        path, line, warning_class, message = first_line_parts
Christian Heimes's avatar
Christian Heimes committed
623
        line = int(line)
624 625 626
        self.assertEqual(expected_file, path)
        self.assertEqual(warning_class, ' ' + UserWarning.__name__)
        self.assertEqual(message, ' ' + text)
Christian Heimes's avatar
Christian Heimes committed
627 628
        expected_line = '  ' + linecache.getline(path, line).strip() + '\n'
        assert expected_line
629
        self.assertEqual(second_line, expected_line)
630

631 632 633 634 635
    def test_filename_none(self):
        # issue #12467: race condition if a warning is emitted at shutdown
        globals_dict = globals()
        oldfile = globals_dict['__file__']
        try:
636 637 638
            catch = original_warnings.catch_warnings(record=True,
                                                     module=self.module)
            with catch as w:
639 640 641
                self.module.filterwarnings("always", category=UserWarning)
                globals_dict['__file__'] = None
                original_warnings.warn('test', UserWarning)
642
                self.assertTrue(len(w))
643 644 645
        finally:
            globals_dict['__file__'] = oldfile

646 647 648 649 650 651 652 653 654
    def test_stderr_none(self):
        rc, stdout, stderr = assert_python_ok("-c",
            "import sys; sys.stderr = None; "
            "import warnings; warnings.simplefilter('always'); "
            "warnings.warn('Warning!')")
        self.assertEqual(stdout, b'')
        self.assertNotIn(b'Warning!', stderr)
        self.assertNotIn(b'Error', stderr)

655

656
class WarningsDisplayTests(BaseTest):
657

Christian Heimes's avatar
Christian Heimes committed
658 659 660
    """Test the displaying of warnings and the ability to overload functions
    related to displaying warnings."""

661 662 663 664 665 666
    def test_formatwarning(self):
        message = "msg"
        category = Warning
        file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
        line_num = 3
        file_line = linecache.getline(file_name, line_num).strip()
Christian Heimes's avatar
Christian Heimes committed
667 668 669
        format = "%s:%s: %s: %s\n  %s\n"
        expect = format % (file_name, line_num, category.__name__, message,
                            file_line)
670
        self.assertEqual(expect, self.module.formatwarning(message,
Christian Heimes's avatar
Christian Heimes committed
671 672 673 674 675
                                                category, file_name, line_num))
        # Test the 'line' argument.
        file_line += " for the win!"
        expect = format % (file_name, line_num, category.__name__, message,
                            file_line)
676
        self.assertEqual(expect, self.module.formatwarning(message,
Christian Heimes's avatar
Christian Heimes committed
677
                                    category, file_name, line_num, file_line))
678 679 680 681 682 683 684 685

    def test_showwarning(self):
        file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
        line_num = 3
        expected_file_line = linecache.getline(file_name, line_num).strip()
        message = 'msg'
        category = Warning
        file_object = StringIO()
Christian Heimes's avatar
Christian Heimes committed
686 687 688
        expect = self.module.formatwarning(message, category, file_name,
                                            line_num)
        self.module.showwarning(message, category, file_name, line_num,
689
                                file_object)
690
        self.assertEqual(file_object.getvalue(), expect)
Christian Heimes's avatar
Christian Heimes committed
691 692 693 694 695 696 697
        # Test 'line' argument.
        expected_file_line += "for the win!"
        expect = self.module.formatwarning(message, category, file_name,
                                            line_num, expected_file_line)
        file_object = StringIO()
        self.module.showwarning(message, category, file_name, line_num,
                                file_object, expected_file_line)
698
        self.assertEqual(expect, file_object.getvalue())
Christian Heimes's avatar
Christian Heimes committed
699

700
class CWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
701 702
    module = c_warnings

703
class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
704 705
    module = py_warnings

706

707
class CatchWarningTests(BaseTest):
708

709 710 711
    """Test catch_warnings()."""

    def test_catch_warnings_restore(self):
712 713 714
        wmod = self.module
        orig_filters = wmod.filters
        orig_showwarning = wmod.showwarning
Benjamin Peterson's avatar
Benjamin Peterson committed
715 716
        # Ensure both showwarning and filters are restored when recording
        with wmod.catch_warnings(module=wmod, record=True):
717
            wmod.filters = wmod.showwarning = object()
718 719
        self.assertTrue(wmod.filters is orig_filters)
        self.assertTrue(wmod.showwarning is orig_showwarning)
Benjamin Peterson's avatar
Benjamin Peterson committed
720 721
        # Same test, but with recording disabled
        with wmod.catch_warnings(module=wmod, record=False):
722
            wmod.filters = wmod.showwarning = object()
723 724
        self.assertTrue(wmod.filters is orig_filters)
        self.assertTrue(wmod.showwarning is orig_showwarning)
725

726
    def test_catch_warnings_recording(self):
727
        wmod = self.module
Benjamin Peterson's avatar
Benjamin Peterson committed
728 729
        # Ensure warnings are recorded when requested
        with wmod.catch_warnings(module=wmod, record=True) as w:
730
            self.assertEqual(w, [])
731
            self.assertTrue(type(w) is list)
732 733
            wmod.simplefilter("always")
            wmod.warn("foo")
734
            self.assertEqual(str(w[-1].message), "foo")
735
            wmod.warn("bar")
736
            self.assertEqual(str(w[-1].message), "bar")
737 738
            self.assertEqual(str(w[0].message), "foo")
            self.assertEqual(str(w[1].message), "bar")
739
            del w[:]
740
            self.assertEqual(w, [])
Benjamin Peterson's avatar
Benjamin Peterson committed
741
        # Ensure warnings are not recorded when not requested
742
        orig_showwarning = wmod.showwarning
Benjamin Peterson's avatar
Benjamin Peterson committed
743
        with wmod.catch_warnings(module=wmod, record=False) as w:
744 745
            self.assertTrue(w is None)
            self.assertTrue(wmod.showwarning is orig_showwarning)
746

Benjamin Peterson's avatar
Benjamin Peterson committed
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
    def test_catch_warnings_reentry_guard(self):
        wmod = self.module
        # Ensure catch_warnings is protected against incorrect usage
        x = wmod.catch_warnings(module=wmod, record=True)
        self.assertRaises(RuntimeError, x.__exit__)
        with x:
            self.assertRaises(RuntimeError, x.__enter__)
        # Same test, but with recording disabled
        x = wmod.catch_warnings(module=wmod, record=False)
        self.assertRaises(RuntimeError, x.__exit__)
        with x:
            self.assertRaises(RuntimeError, x.__enter__)

    def test_catch_warnings_defaults(self):
        wmod = self.module
        orig_filters = wmod.filters
        orig_showwarning = wmod.showwarning
        # Ensure default behaviour is not to record warnings
        with wmod.catch_warnings(module=wmod) as w:
766 767 768 769
            self.assertTrue(w is None)
            self.assertTrue(wmod.showwarning is orig_showwarning)
            self.assertTrue(wmod.filters is not orig_filters)
        self.assertTrue(wmod.filters is orig_filters)
Benjamin Peterson's avatar
Benjamin Peterson committed
770 771 772
        if wmod is sys.modules['warnings']:
            # Ensure the default module is this one
            with wmod.catch_warnings() as w:
773 774 775 776
                self.assertTrue(w is None)
                self.assertTrue(wmod.showwarning is orig_showwarning)
                self.assertTrue(wmod.filters is not orig_filters)
            self.assertTrue(wmod.filters is orig_filters)
Benjamin Peterson's avatar
Benjamin Peterson committed
777 778 779 780

    def test_check_warnings(self):
        # Explicit tests for the test.support convenience wrapper
        wmod = self.module
781
        if wmod is not sys.modules['warnings']:
782
            self.skipTest('module to test is not loaded warnings module')
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
        with support.check_warnings(quiet=False) as w:
            self.assertEqual(w.warnings, [])
            wmod.simplefilter("always")
            wmod.warn("foo")
            self.assertEqual(str(w.message), "foo")
            wmod.warn("bar")
            self.assertEqual(str(w.message), "bar")
            self.assertEqual(str(w.warnings[0].message), "foo")
            self.assertEqual(str(w.warnings[1].message), "bar")
            w.reset()
            self.assertEqual(w.warnings, [])

        with support.check_warnings():
            # defaults to quiet=True without argument
            pass
        with support.check_warnings(('foo', UserWarning)):
            wmod.warn("foo")

        with self.assertRaises(AssertionError):
            with support.check_warnings(('', RuntimeWarning)):
                # defaults to quiet=False with argument
                pass
        with self.assertRaises(AssertionError):
            with support.check_warnings(('foo', RuntimeWarning)):
Benjamin Peterson's avatar
Benjamin Peterson committed
807 808
                wmod.warn("foo")

809
class CCatchWarningTests(CatchWarningTests, unittest.TestCase):
810 811
    module = c_warnings

812
class PyCatchWarningTests(CatchWarningTests, unittest.TestCase):
813 814
    module = py_warnings

815

816 817 818
class EnvironmentVariableTests(BaseTest):

    def test_single_warning(self):
819 820 821 822
        rc, stdout, stderr = assert_python_ok("-c",
            "import sys; sys.stdout.write(str(sys.warnoptions))",
            PYTHONWARNINGS="ignore::DeprecationWarning")
        self.assertEqual(stdout, b"['ignore::DeprecationWarning']")
823 824

    def test_comma_separated_warnings(self):
825 826 827 828 829
        rc, stdout, stderr = assert_python_ok("-c",
            "import sys; sys.stdout.write(str(sys.warnoptions))",
            PYTHONWARNINGS="ignore::DeprecationWarning,ignore::UnicodeWarning")
        self.assertEqual(stdout,
            b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']")
830 831

    def test_envvar_and_command_line(self):
832 833 834 835 836
        rc, stdout, stderr = assert_python_ok("-Wignore::UnicodeWarning", "-c",
            "import sys; sys.stdout.write(str(sys.warnoptions))",
            PYTHONWARNINGS="ignore::DeprecationWarning")
        self.assertEqual(stdout,
            b"['ignore::UnicodeWarning', 'ignore::DeprecationWarning']")
837

838 839 840
    @unittest.skipUnless(sys.getfilesystemencoding() != 'ascii',
                         'requires non-ascii filesystemencoding')
    def test_nonascii(self):
841 842 843 844 845 846
        rc, stdout, stderr = assert_python_ok("-c",
            "import sys; sys.stdout.write(str(sys.warnoptions))",
            PYTHONIOENCODING="utf-8",
            PYTHONWARNINGS="ignore:DeprecaciónWarning")
        self.assertEqual(stdout,
            "['ignore:DeprecaciónWarning']".encode('utf-8'))
847

848
class CEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase):
849 850
    module = c_warnings

851
class PyEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase):
852 853 854
    module = py_warnings


855 856 857
class BootstrapTest(unittest.TestCase):
    def test_issue_8766(self):
        # "import encodings" emits a warning whereas the warnings is not loaded
858
        # or not completely loaded (warnings imports indirectly encodings by
859 860 861
        # importing linecache) yet
        with support.temp_cwd() as cwd, support.temp_cwd('encodings'):
            # encodings loaded by initfsencoding()
862
            assert_python_ok('-c', 'pass', PYTHONPATH=cwd)
863 864

            # Use -W to load warnings module at startup
865
            assert_python_ok('-c', 'pass', '-W', 'always', PYTHONPATH=cwd)
866

867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
class FinalizationTest(unittest.TestCase):
    def test_finalization(self):
        # Issue #19421: warnings.warn() should not crash
        # during Python finalization
        code = """
import warnings
warn = warnings.warn

class A:
    def __del__(self):
        warn("test")

a=A()
        """
        rc, out, err = assert_python_ok("-c", code)
        # note: "__main__" filename is not correct, it should be the name
        # of the script
        self.assertEqual(err, b'__main__:7: UserWarning: test')

886 887

def setUpModule():
Christian Heimes's avatar
Christian Heimes committed
888 889
    py_warnings.onceregistry.clear()
    c_warnings.onceregistry.clear()
890

891
tearDownModule = setUpModule
892 893

if __name__ == "__main__":
894
    unittest.main()