test_warnings.py 33.2 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
import subprocess
8
from test import support
9
from test.script_helper import assert_python_ok
10

11
from test import warning_tests
12

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

15 16
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
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

@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
32
    original_filters = module.filters
Christian Heimes's avatar
Christian Heimes committed
33
    try:
34 35
        module.filters = original_filters[:]
        module.simplefilter("once")
Christian Heimes's avatar
Christian Heimes committed
36 37 38 39
        warning_tests.warnings = module
        yield
    finally:
        warning_tests.warnings = original_warnings
40
        module.filters = original_filters
Christian Heimes's avatar
Christian Heimes committed
41 42


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

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

47
    def setUp(self):
Christian Heimes's avatar
Christian Heimes committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
        # 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()
64 65


66
class FilterTests(BaseTest):
Christian Heimes's avatar
Christian Heimes committed
67 68 69 70

    """Testing the filtering functionality."""

    def test_error(self):
71
        with original_warnings.catch_warnings(module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
72 73 74 75 76 77
            self.module.resetwarnings()
            self.module.filterwarnings("error", category=UserWarning)
            self.assertRaises(UserWarning, self.module.warn,
                                "FilterTests.test_error")

    def test_ignore(self):
78 79
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
80 81 82
            self.module.resetwarnings()
            self.module.filterwarnings("ignore", category=UserWarning)
            self.module.warn("FilterTests.test_ignore", UserWarning)
83
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
84 85

    def test_always(self):
86 87
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
88 89 90 91
            self.module.resetwarnings()
            self.module.filterwarnings("always", category=UserWarning)
            message = "FilterTests.test_always"
            self.module.warn(message, UserWarning)
92
            self.assertTrue(message, w[-1].message)
Christian Heimes's avatar
Christian Heimes committed
93
            self.module.warn(message, UserWarning)
94
            self.assertTrue(w[-1].message, message)
Christian Heimes's avatar
Christian Heimes committed
95 96

    def test_default(self):
97 98
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
99 100 101 102 103 104
            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:
105
                    self.assertEqual(w[-1].message, message)
106
                    del w[:]
Christian Heimes's avatar
Christian Heimes committed
107
                elif x == 1:
108
                    self.assertEqual(len(w), 0)
109
                else:
Christian Heimes's avatar
Christian Heimes committed
110 111 112
                    raise ValueError("loop variant unhandled")

    def test_module(self):
113 114
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
115 116 117 118
            self.module.resetwarnings()
            self.module.filterwarnings("module", category=UserWarning)
            message = UserWarning("FilterTests.test_module")
            self.module.warn(message, UserWarning)
119
            self.assertEqual(w[-1].message, message)
120
            del w[:]
Christian Heimes's avatar
Christian Heimes committed
121
            self.module.warn(message, UserWarning)
122
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
123 124

    def test_once(self):
125 126
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
127 128 129 130 131
            self.module.resetwarnings()
            self.module.filterwarnings("once", category=UserWarning)
            message = UserWarning("FilterTests.test_once")
            self.module.warn_explicit(message, UserWarning, "test_warnings.py",
                                    42)
132
            self.assertEqual(w[-1].message, message)
133
            del w[:]
Christian Heimes's avatar
Christian Heimes committed
134 135
            self.module.warn_explicit(message, UserWarning, "test_warnings.py",
                                    13)
136
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
137 138
            self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
                                    42)
139
            self.assertEqual(len(w), 0)
140

Christian Heimes's avatar
Christian Heimes committed
141
    def test_inheritance(self):
142
        with original_warnings.catch_warnings(module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
143 144 145 146 147 148
            self.module.resetwarnings()
            self.module.filterwarnings("error", category=Warning)
            self.assertRaises(UserWarning, self.module.warn,
                                "FilterTests.test_inheritance", UserWarning)

    def test_ordering(self):
149 150
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
151 152 153 154
            self.module.resetwarnings()
            self.module.filterwarnings("ignore", category=UserWarning)
            self.module.filterwarnings("error", category=UserWarning,
                                        append=True)
155
            del w[:]
Christian Heimes's avatar
Christian Heimes committed
156 157 158 159
            try:
                self.module.warn("FilterTests.test_ordering", UserWarning)
            except UserWarning:
                self.fail("order handling for actions failed")
160
            self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
161 162

    def test_filterwarnings(self):
163 164
        # Test filterwarnings().
        # Implicitly also tests resetwarnings().
165 166
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
167 168
            self.module.filterwarnings("error", "", Warning, "", 0)
            self.assertRaises(UserWarning, self.module.warn, 'convert to error')
169

Christian Heimes's avatar
Christian Heimes committed
170
            self.module.resetwarnings()
171
            text = 'handle normally'
Christian Heimes's avatar
Christian Heimes committed
172
            self.module.warn(text)
173
            self.assertEqual(str(w[-1].message), text)
174
            self.assertTrue(w[-1].category is UserWarning)
175

Christian Heimes's avatar
Christian Heimes committed
176
            self.module.filterwarnings("ignore", "", Warning, "", 0)
177
            text = 'filtered out'
Christian Heimes's avatar
Christian Heimes committed
178
            self.module.warn(text)
179
            self.assertNotEqual(str(w[-1].message), text)
180

Christian Heimes's avatar
Christian Heimes committed
181 182 183
            self.module.resetwarnings()
            self.module.filterwarnings("error", "hex*", Warning, "", 0)
            self.assertRaises(UserWarning, self.module.warn, 'hex/oct')
184
            text = 'nonmatching text'
Christian Heimes's avatar
Christian Heimes committed
185
            self.module.warn(text)
186
            self.assertEqual(str(w[-1].message), text)
187
            self.assertTrue(w[-1].category is UserWarning)
188

189
class CFilterTests(FilterTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
190 191
    module = c_warnings

192
class PyFilterTests(FilterTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
193 194 195
    module = py_warnings


196
class WarnTests(BaseTest):
Christian Heimes's avatar
Christian Heimes committed
197 198 199 200

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

    def test_message(self):
201 202
        with original_warnings.catch_warnings(record=True,
                module=self.module) as w:
203
            self.module.simplefilter("once")
Christian Heimes's avatar
Christian Heimes committed
204 205 206
            for i in range(4):
                text = 'multi %d' %i  # Different text on each call.
                self.module.warn(text)
207
                self.assertEqual(str(w[-1].message), text)
208
                self.assertTrue(w[-1].category is UserWarning)
209

210 211 212 213
    # 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
214 215
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
216
                self.module.simplefilter("once")
217 218 219
                self.module.warn(ob)
                # Don't directly compare objects since
                # ``Warning() != Warning()``.
220
                self.assertEqual(str(w[-1].message), str(UserWarning(ob)))
221

222
    def test_filename(self):
Christian Heimes's avatar
Christian Heimes committed
223
        with warnings_state(self.module):
224 225
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
226
                warning_tests.inner("spam1")
227 228
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
Christian Heimes's avatar
Christian Heimes committed
229
                warning_tests.outer("spam2")
230 231
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
232 233 234 235

    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
236
        with warnings_state(self.module):
237 238
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
239
                warning_tests.inner("spam3", stacklevel=1)
240 241
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
Christian Heimes's avatar
Christian Heimes committed
242
                warning_tests.outer("spam4", stacklevel=1)
243 244
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
Christian Heimes's avatar
Christian Heimes committed
245 246

                warning_tests.inner("spam5", stacklevel=2)
247 248
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "test_warnings.py")
Christian Heimes's avatar
Christian Heimes committed
249
                warning_tests.outer("spam6", stacklevel=2)
250 251
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "warning_tests.py")
252
                warning_tests.outer("spam6.5", stacklevel=3)
253 254
                self.assertEqual(os.path.basename(w[-1].filename),
                                    "test_warnings.py")
Christian Heimes's avatar
Christian Heimes committed
255 256

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

Christian Heimes's avatar
Christian Heimes committed
260 261 262 263 264 265 266
    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):
267 268
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
269
                    warning_tests.inner("spam8", stacklevel=1)
270
                    self.assertEqual(w[-1].filename, warning_tests.__name__)
Christian Heimes's avatar
Christian Heimes committed
271 272 273
        finally:
            warning_tests.__file__ = filename

274
    @unittest.skipUnless(hasattr(sys, 'argv'), 'test needs sys.argv')
Christian Heimes's avatar
Christian Heimes committed
275 276 277 278 279 280 281 282 283
    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):
284 285
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
286
                    warning_tests.inner('spam9', stacklevel=1)
287
                    self.assertEqual(w[-1].filename, sys.argv[0])
Christian Heimes's avatar
Christian Heimes committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
        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):
303 304
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
305
                    warning_tests.inner('spam10', stacklevel=1)
306
                    self.assertEqual(w[-1].filename, '__main__')
Christian Heimes's avatar
Christian Heimes committed
307 308 309 310 311
        finally:
            warning_tests.__file__ = filename
            warning_tests.__name__ = module_name
            sys.argv = argv

Christian Heimes's avatar
Christian Heimes committed
312
    def test_missing_filename_main_with_argv_empty_string(self):
Christian Heimes's avatar
Christian Heimes committed
313 314 315 316 317 318 319 320 321 322 323
        # 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):
324 325
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
326
                    warning_tests.inner('spam11', stacklevel=1)
327
                    self.assertEqual(w[-1].filename, '__main__')
Christian Heimes's avatar
Christian Heimes committed
328 329 330 331 332
        finally:
            warning_tests.__file__ = file_name
            warning_tests.__name__ = module_name
            sys.argv = argv

333
    def test_warn_explicit_type_errors(self):
334
        # warn_explicit() should error out gracefully if it is given objects
335 336 337 338 339 340 341 342 343 344 345 346 347
        # 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)

348 349 350 351 352 353 354 355 356 357 358 359 360 361
    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())


362
class CWarnTests(WarnTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
363 364
    module = c_warnings

365 366 367 368 369 370
    # 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__'))

371
class PyWarnTests(WarnTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
372 373
    module = py_warnings

374 375 376 377 378 379
    # 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
380

381
class WCmdLineTests(BaseTest):
Christian Heimes's avatar
Christian Heimes committed
382 383 384 385

    def test_improper_input(self):
        # Uses the private _setoption() function to test the parsing
        # of command-line warning arguments
386
        with original_warnings.catch_warnings(module=self.module):
Christian Heimes's avatar
Christian Heimes committed
387 388 389 390 391 392 393 394 395
            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')

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
    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)

412
class CWCmdLineTests(WCmdLineTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
413 414
    module = c_warnings

415
class PyWCmdLineTests(WCmdLineTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
416 417 418
    module = py_warnings


419
class _WarningsTests(BaseTest, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
420 421 422 423

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

    module = c_warnings
424

Christian Heimes's avatar
Christian Heimes committed
425 426
    def test_filter(self):
        # Everything should function even if 'filters' is not in warnings.
427
        with original_warnings.catch_warnings(module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
428 429 430 431 432 433
            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')
434

Christian Heimes's avatar
Christian Heimes committed
435 436 437 438 439 440 441
    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__ = {}
442 443
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
444 445 446
                self.module.resetwarnings()
                self.module.filterwarnings("once", category=UserWarning)
                self.module.warn_explicit(message, UserWarning, "file", 42)
447
                self.assertEqual(w[-1].message, message)
448
                del w[:]
Christian Heimes's avatar
Christian Heimes committed
449
                self.module.warn_explicit(message, UserWarning, "file", 42)
450
                self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
451 452 453 454
                # Test the resetting of onceregistry.
                self.module.onceregistry = {}
                __warningregistry__ = {}
                self.module.warn('onceregistry test')
455
                self.assertEqual(w[-1].message.args, message.args)
Christian Heimes's avatar
Christian Heimes committed
456
                # Removal of onceregistry is okay.
457
                del w[:]
Christian Heimes's avatar
Christian Heimes committed
458 459 460
                del self.module.onceregistry
                __warningregistry__ = {}
                self.module.warn_explicit(message, UserWarning, "file", 42)
461
                self.assertEqual(len(w), 0)
Christian Heimes's avatar
Christian Heimes committed
462 463 464
        finally:
            self.module.onceregistry = original_registry

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
    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)
                self.assertEqual(len(registry), 1)
                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)
                self.assertEqual(len(registry), 1)
                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
500 501 502
    def test_showwarning_missing(self):
        # Test that showwarning() missing is okay.
        text = 'del showwarning test'
503
        with original_warnings.catch_warnings(module=self.module):
Christian Heimes's avatar
Christian Heimes committed
504 505
            self.module.filterwarnings("always", category=UserWarning)
            del self.module.showwarning
506
            with support.captured_output('stderr') as stream:
Christian Heimes's avatar
Christian Heimes committed
507 508
                self.module.warn(text)
                result = stream.getvalue()
509
        self.assertIn(text, result)
Christian Heimes's avatar
Christian Heimes committed
510

511
    def test_showwarning_not_callable(self):
512 513
        with original_warnings.catch_warnings(module=self.module):
            self.module.filterwarnings("always", category=UserWarning)
514 515 516
            self.module.showwarning = print
            with support.captured_output('stdout'):
                self.module.warn('Warning!')
517
            self.module.showwarning = 23
518
            self.assertRaises(TypeError, self.module.warn, "Warning!")
519

Christian Heimes's avatar
Christian Heimes committed
520 521 522
    def test_show_warning_output(self):
        # With showarning() missing, make sure that output is okay.
        text = 'test show_warning'
523
        with original_warnings.catch_warnings(module=self.module):
Christian Heimes's avatar
Christian Heimes committed
524 525
            self.module.filterwarnings("always", category=UserWarning)
            del self.module.showwarning
526
            with support.captured_output('stderr') as stream:
Christian Heimes's avatar
Christian Heimes committed
527 528
                warning_tests.inner(text)
                result = stream.getvalue()
529
        self.assertEqual(result.count('\n'), 2,
Christian Heimes's avatar
Christian Heimes committed
530 531 532
                             "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
533 534
        first_line_parts = first_line.rsplit(':', 3)
        path, line, warning_class, message = first_line_parts
Christian Heimes's avatar
Christian Heimes committed
535
        line = int(line)
536 537 538
        self.assertEqual(expected_file, path)
        self.assertEqual(warning_class, ' ' + UserWarning.__name__)
        self.assertEqual(message, ' ' + text)
Christian Heimes's avatar
Christian Heimes committed
539 540
        expected_line = '  ' + linecache.getline(path, line).strip() + '\n'
        assert expected_line
541
        self.assertEqual(second_line, expected_line)
542

543 544 545 546 547
    def test_filename_none(self):
        # issue #12467: race condition if a warning is emitted at shutdown
        globals_dict = globals()
        oldfile = globals_dict['__file__']
        try:
548 549 550
            catch = original_warnings.catch_warnings(record=True,
                                                     module=self.module)
            with catch as w:
551 552 553
                self.module.filterwarnings("always", category=UserWarning)
                globals_dict['__file__'] = None
                original_warnings.warn('test', UserWarning)
554
                self.assertTrue(len(w))
555 556 557
        finally:
            globals_dict['__file__'] = oldfile

558

559
class WarningsDisplayTests(BaseTest):
560

Christian Heimes's avatar
Christian Heimes committed
561 562 563
    """Test the displaying of warnings and the ability to overload functions
    related to displaying warnings."""

564 565 566 567 568 569
    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
570 571 572
        format = "%s:%s: %s: %s\n  %s\n"
        expect = format % (file_name, line_num, category.__name__, message,
                            file_line)
573
        self.assertEqual(expect, self.module.formatwarning(message,
Christian Heimes's avatar
Christian Heimes committed
574 575 576 577 578
                                                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)
579
        self.assertEqual(expect, self.module.formatwarning(message,
Christian Heimes's avatar
Christian Heimes committed
580
                                    category, file_name, line_num, file_line))
581 582 583 584 585 586 587 588

    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
589 590 591
        expect = self.module.formatwarning(message, category, file_name,
                                            line_num)
        self.module.showwarning(message, category, file_name, line_num,
592
                                file_object)
593
        self.assertEqual(file_object.getvalue(), expect)
Christian Heimes's avatar
Christian Heimes committed
594 595 596 597 598 599 600
        # 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)
601
        self.assertEqual(expect, file_object.getvalue())
Christian Heimes's avatar
Christian Heimes committed
602

603
class CWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
604 605
    module = c_warnings

606
class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
Christian Heimes's avatar
Christian Heimes committed
607 608
    module = py_warnings

609

610
class CatchWarningTests(BaseTest):
611

612 613 614
    """Test catch_warnings()."""

    def test_catch_warnings_restore(self):
615 616 617
        wmod = self.module
        orig_filters = wmod.filters
        orig_showwarning = wmod.showwarning
Benjamin Peterson's avatar
Benjamin Peterson committed
618 619
        # Ensure both showwarning and filters are restored when recording
        with wmod.catch_warnings(module=wmod, record=True):
620
            wmod.filters = wmod.showwarning = object()
621 622
        self.assertTrue(wmod.filters is orig_filters)
        self.assertTrue(wmod.showwarning is orig_showwarning)
Benjamin Peterson's avatar
Benjamin Peterson committed
623 624
        # Same test, but with recording disabled
        with wmod.catch_warnings(module=wmod, record=False):
625
            wmod.filters = wmod.showwarning = object()
626 627
        self.assertTrue(wmod.filters is orig_filters)
        self.assertTrue(wmod.showwarning is orig_showwarning)
628

629
    def test_catch_warnings_recording(self):
630
        wmod = self.module
Benjamin Peterson's avatar
Benjamin Peterson committed
631 632
        # Ensure warnings are recorded when requested
        with wmod.catch_warnings(module=wmod, record=True) as w:
633
            self.assertEqual(w, [])
634
            self.assertTrue(type(w) is list)
635 636
            wmod.simplefilter("always")
            wmod.warn("foo")
637
            self.assertEqual(str(w[-1].message), "foo")
638
            wmod.warn("bar")
639
            self.assertEqual(str(w[-1].message), "bar")
640 641
            self.assertEqual(str(w[0].message), "foo")
            self.assertEqual(str(w[1].message), "bar")
642
            del w[:]
643
            self.assertEqual(w, [])
Benjamin Peterson's avatar
Benjamin Peterson committed
644
        # Ensure warnings are not recorded when not requested
645
        orig_showwarning = wmod.showwarning
Benjamin Peterson's avatar
Benjamin Peterson committed
646
        with wmod.catch_warnings(module=wmod, record=False) as w:
647 648
            self.assertTrue(w is None)
            self.assertTrue(wmod.showwarning is orig_showwarning)
649

Benjamin Peterson's avatar
Benjamin Peterson committed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
    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:
669 670 671 672
            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
673 674 675
        if wmod is sys.modules['warnings']:
            # Ensure the default module is this one
            with wmod.catch_warnings() as w:
676 677 678 679
                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
680 681 682 683

    def test_check_warnings(self):
        # Explicit tests for the test.support convenience wrapper
        wmod = self.module
684
        if wmod is not sys.modules['warnings']:
685
            self.skipTest('module to test is not loaded warnings module')
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
        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
710 711
                wmod.warn("foo")

712
class CCatchWarningTests(CatchWarningTests, unittest.TestCase):
713 714
    module = c_warnings

715
class PyCatchWarningTests(CatchWarningTests, unittest.TestCase):
716 717
    module = py_warnings

718

719 720 721 722 723 724 725 726
class EnvironmentVariableTests(BaseTest):

    def test_single_warning(self):
        newenv = os.environ.copy()
        newenv["PYTHONWARNINGS"] = "ignore::DeprecationWarning"
        p = subprocess.Popen([sys.executable,
                "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"],
                stdout=subprocess.PIPE, env=newenv)
727 728
        self.assertEqual(p.communicate()[0], b"['ignore::DeprecationWarning']")
        self.assertEqual(p.wait(), 0)
729 730 731 732 733 734 735 736

    def test_comma_separated_warnings(self):
        newenv = os.environ.copy()
        newenv["PYTHONWARNINGS"] = ("ignore::DeprecationWarning,"
                                    "ignore::UnicodeWarning")
        p = subprocess.Popen([sys.executable,
                "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"],
                stdout=subprocess.PIPE, env=newenv)
737
        self.assertEqual(p.communicate()[0],
738
                b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']")
739
        self.assertEqual(p.wait(), 0)
740 741 742 743 744 745 746

    def test_envvar_and_command_line(self):
        newenv = os.environ.copy()
        newenv["PYTHONWARNINGS"] = "ignore::DeprecationWarning"
        p = subprocess.Popen([sys.executable, "-W" "ignore::UnicodeWarning",
                "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"],
                stdout=subprocess.PIPE, env=newenv)
747
        self.assertEqual(p.communicate()[0],
748
                b"['ignore::UnicodeWarning', 'ignore::DeprecationWarning']")
749
        self.assertEqual(p.wait(), 0)
750

751 752 753 754 755 756 757 758 759 760 761 762 763
    @unittest.skipUnless(sys.getfilesystemencoding() != 'ascii',
                         'requires non-ascii filesystemencoding')
    def test_nonascii(self):
        newenv = os.environ.copy()
        newenv["PYTHONWARNINGS"] = "ignore:DeprecaciónWarning"
        newenv["PYTHONIOENCODING"] = "utf-8"
        p = subprocess.Popen([sys.executable,
                "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"],
                stdout=subprocess.PIPE, env=newenv)
        self.assertEqual(p.communicate()[0],
                "['ignore:DeprecaciónWarning']".encode('utf-8'))
        self.assertEqual(p.wait(), 0)

764
class CEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase):
765 766
    module = c_warnings

767
class PyEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase):
768 769 770
    module = py_warnings


771 772 773
class BootstrapTest(unittest.TestCase):
    def test_issue_8766(self):
        # "import encodings" emits a warning whereas the warnings is not loaded
774
        # or not completely loaded (warnings imports indirectly encodings by
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
        # importing linecache) yet
        with support.temp_cwd() as cwd, support.temp_cwd('encodings'):
            env = os.environ.copy()
            env['PYTHONPATH'] = cwd

            # encodings loaded by initfsencoding()
            retcode = subprocess.call([sys.executable, '-c', 'pass'], env=env)
            self.assertEqual(retcode, 0)

            # Use -W to load warnings module at startup
            retcode = subprocess.call(
                [sys.executable, '-c', 'pass', '-W', 'always'],
                env=env)
            self.assertEqual(retcode, 0)

790 791

def setUpModule():
Christian Heimes's avatar
Christian Heimes committed
792 793
    py_warnings.onceregistry.clear()
    c_warnings.onceregistry.clear()
794

795
tearDownModule = setUpModule
796 797

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