test_warnings.py 33.1 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 274 275 276 277 278 279 280 281 282 283 284
        finally:
            warning_tests.__file__ = filename

    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.
        if not hasattr(sys, 'argv'):
            return
        filename = warning_tests.__file__
        module_name = warning_tests.__name__
        try:
            del warning_tests.__file__
            warning_tests.__name__ = '__main__'
            with warnings_state(self.module):
285 286
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
287
                    warning_tests.inner('spam9', stacklevel=1)
288
                    self.assertEqual(w[-1].filename, sys.argv[0])
Christian Heimes's avatar
Christian Heimes committed
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
        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):
304 305
                with original_warnings.catch_warnings(record=True,
                        module=self.module) as w:
Christian Heimes's avatar
Christian Heimes committed
306
                    warning_tests.inner('spam10', stacklevel=1)
307
                    self.assertEqual(w[-1].filename, '__main__')
Christian Heimes's avatar
Christian Heimes committed
308 309 310 311 312
        finally:
            warning_tests.__file__ = filename
            warning_tests.__name__ = module_name
            sys.argv = argv

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

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

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


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

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

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

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

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

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

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

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

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


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

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

    module = c_warnings
425

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

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

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 500
    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
501 502 503
    def test_showwarning_missing(self):
        # Test that showwarning() missing is okay.
        text = 'del showwarning test'
504
        with original_warnings.catch_warnings(module=self.module):
Christian Heimes's avatar
Christian Heimes committed
505 506
            self.module.filterwarnings("always", category=UserWarning)
            del self.module.showwarning
507
            with support.captured_output('stderr') as stream:
Christian Heimes's avatar
Christian Heimes committed
508 509
                self.module.warn(text)
                result = stream.getvalue()
510
        self.assertIn(text, result)
Christian Heimes's avatar
Christian Heimes committed
511

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

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

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

559

560
class WarningsDisplayTests(BaseTest):
561

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

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

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

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

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

610

611
class CatchWarningTests(BaseTest):
612

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

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

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

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

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

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

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

719

720 721 722 723 724 725 726 727
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)
728 729
        self.assertEqual(p.communicate()[0], b"['ignore::DeprecationWarning']")
        self.assertEqual(p.wait(), 0)
730 731 732 733 734 735 736 737

    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)
738
        self.assertEqual(p.communicate()[0],
739
                b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']")
740
        self.assertEqual(p.wait(), 0)
741 742 743 744 745 746 747

    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)
748
        self.assertEqual(p.communicate()[0],
749
                b"['ignore::UnicodeWarning', 'ignore::DeprecationWarning']")
750
        self.assertEqual(p.wait(), 0)
751

752 753 754 755 756 757 758 759 760 761 762 763 764
    @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)

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

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


772 773 774
class BootstrapTest(unittest.TestCase):
    def test_issue_8766(self):
        # "import encodings" emits a warning whereas the warnings is not loaded
775
        # or not completely loaded (warnings imports indirectly encodings by
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
        # 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)

791 792

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

796
tearDownModule = setUpModule
797 798

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