1from contextlib import contextmanager 2import linecache 3import os 4from io import StringIO 5import re 6import sys 7import textwrap 8import unittest 9from test import support 10from test.support.script_helper import assert_python_ok, assert_python_failure 11 12from test.test_warnings.data import stacklevel as warning_tests 13 14import warnings as original_warnings 15 16py_warnings = support.import_fresh_module('warnings', blocked=['_warnings']) 17c_warnings = support.import_fresh_module('warnings', fresh=['_warnings']) 18 19Py_DEBUG = hasattr(sys, 'gettotalrefcount') 20 21@contextmanager 22def warnings_state(module): 23 """Use a specific warnings implementation in warning_tests.""" 24 global __warningregistry__ 25 for to_clear in (sys, warning_tests): 26 try: 27 to_clear.__warningregistry__.clear() 28 except AttributeError: 29 pass 30 try: 31 __warningregistry__.clear() 32 except NameError: 33 pass 34 original_warnings = warning_tests.warnings 35 original_filters = module.filters 36 try: 37 module.filters = original_filters[:] 38 module.simplefilter("once") 39 warning_tests.warnings = module 40 yield 41 finally: 42 warning_tests.warnings = original_warnings 43 module.filters = original_filters 44 45 46class TestWarning(Warning): 47 pass 48 49 50class BaseTest: 51 52 """Basic bookkeeping required for testing.""" 53 54 def setUp(self): 55 self.old_unittest_module = unittest.case.warnings 56 # The __warningregistry__ needs to be in a pristine state for tests 57 # to work properly. 58 if '__warningregistry__' in globals(): 59 del globals()['__warningregistry__'] 60 if hasattr(warning_tests, '__warningregistry__'): 61 del warning_tests.__warningregistry__ 62 if hasattr(sys, '__warningregistry__'): 63 del sys.__warningregistry__ 64 # The 'warnings' module must be explicitly set so that the proper 65 # interaction between _warnings and 'warnings' can be controlled. 66 sys.modules['warnings'] = self.module 67 # Ensure that unittest.TestCase.assertWarns() uses the same warnings 68 # module than warnings.catch_warnings(). Otherwise, 69 # warnings.catch_warnings() will be unable to remove the added filter. 70 unittest.case.warnings = self.module 71 super(BaseTest, self).setUp() 72 73 def tearDown(self): 74 sys.modules['warnings'] = original_warnings 75 unittest.case.warnings = self.old_unittest_module 76 super(BaseTest, self).tearDown() 77 78class PublicAPITests(BaseTest): 79 80 """Ensures that the correct values are exposed in the 81 public API. 82 """ 83 84 def test_module_all_attribute(self): 85 self.assertTrue(hasattr(self.module, '__all__')) 86 target_api = ["warn", "warn_explicit", "showwarning", 87 "formatwarning", "filterwarnings", "simplefilter", 88 "resetwarnings", "catch_warnings"] 89 self.assertSetEqual(set(self.module.__all__), 90 set(target_api)) 91 92class CPublicAPITests(PublicAPITests, unittest.TestCase): 93 module = c_warnings 94 95class PyPublicAPITests(PublicAPITests, unittest.TestCase): 96 module = py_warnings 97 98class FilterTests(BaseTest): 99 100 """Testing the filtering functionality.""" 101 102 def test_error(self): 103 with original_warnings.catch_warnings(module=self.module) as w: 104 self.module.resetwarnings() 105 self.module.filterwarnings("error", category=UserWarning) 106 self.assertRaises(UserWarning, self.module.warn, 107 "FilterTests.test_error") 108 109 def test_error_after_default(self): 110 with original_warnings.catch_warnings(module=self.module) as w: 111 self.module.resetwarnings() 112 message = "FilterTests.test_ignore_after_default" 113 def f(): 114 self.module.warn(message, UserWarning) 115 116 with support.captured_stderr() as stderr: 117 f() 118 stderr = stderr.getvalue() 119 self.assertIn("UserWarning: FilterTests.test_ignore_after_default", 120 stderr) 121 self.assertIn("self.module.warn(message, UserWarning)", 122 stderr) 123 124 self.module.filterwarnings("error", category=UserWarning) 125 self.assertRaises(UserWarning, f) 126 127 def test_ignore(self): 128 with original_warnings.catch_warnings(record=True, 129 module=self.module) as w: 130 self.module.resetwarnings() 131 self.module.filterwarnings("ignore", category=UserWarning) 132 self.module.warn("FilterTests.test_ignore", UserWarning) 133 self.assertEqual(len(w), 0) 134 self.assertEqual(list(__warningregistry__), ['version']) 135 136 def test_ignore_after_default(self): 137 with original_warnings.catch_warnings(record=True, 138 module=self.module) as w: 139 self.module.resetwarnings() 140 message = "FilterTests.test_ignore_after_default" 141 def f(): 142 self.module.warn(message, UserWarning) 143 f() 144 self.module.filterwarnings("ignore", category=UserWarning) 145 f() 146 f() 147 self.assertEqual(len(w), 1) 148 149 def test_always(self): 150 with original_warnings.catch_warnings(record=True, 151 module=self.module) as w: 152 self.module.resetwarnings() 153 self.module.filterwarnings("always", category=UserWarning) 154 message = "FilterTests.test_always" 155 def f(): 156 self.module.warn(message, UserWarning) 157 f() 158 self.assertEqual(len(w), 1) 159 self.assertEqual(w[-1].message.args[0], message) 160 f() 161 self.assertEqual(len(w), 2) 162 self.assertEqual(w[-1].message.args[0], message) 163 164 def test_always_after_default(self): 165 with original_warnings.catch_warnings(record=True, 166 module=self.module) as w: 167 self.module.resetwarnings() 168 message = "FilterTests.test_always_after_ignore" 169 def f(): 170 self.module.warn(message, UserWarning) 171 f() 172 self.assertEqual(len(w), 1) 173 self.assertEqual(w[-1].message.args[0], message) 174 f() 175 self.assertEqual(len(w), 1) 176 self.module.filterwarnings("always", category=UserWarning) 177 f() 178 self.assertEqual(len(w), 2) 179 self.assertEqual(w[-1].message.args[0], message) 180 f() 181 self.assertEqual(len(w), 3) 182 self.assertEqual(w[-1].message.args[0], message) 183 184 def test_default(self): 185 with original_warnings.catch_warnings(record=True, 186 module=self.module) as w: 187 self.module.resetwarnings() 188 self.module.filterwarnings("default", category=UserWarning) 189 message = UserWarning("FilterTests.test_default") 190 for x in range(2): 191 self.module.warn(message, UserWarning) 192 if x == 0: 193 self.assertEqual(w[-1].message, message) 194 del w[:] 195 elif x == 1: 196 self.assertEqual(len(w), 0) 197 else: 198 raise ValueError("loop variant unhandled") 199 200 def test_module(self): 201 with original_warnings.catch_warnings(record=True, 202 module=self.module) as w: 203 self.module.resetwarnings() 204 self.module.filterwarnings("module", category=UserWarning) 205 message = UserWarning("FilterTests.test_module") 206 self.module.warn(message, UserWarning) 207 self.assertEqual(w[-1].message, message) 208 del w[:] 209 self.module.warn(message, UserWarning) 210 self.assertEqual(len(w), 0) 211 212 def test_once(self): 213 with original_warnings.catch_warnings(record=True, 214 module=self.module) as w: 215 self.module.resetwarnings() 216 self.module.filterwarnings("once", category=UserWarning) 217 message = UserWarning("FilterTests.test_once") 218 self.module.warn_explicit(message, UserWarning, "__init__.py", 219 42) 220 self.assertEqual(w[-1].message, message) 221 del w[:] 222 self.module.warn_explicit(message, UserWarning, "__init__.py", 223 13) 224 self.assertEqual(len(w), 0) 225 self.module.warn_explicit(message, UserWarning, "test_warnings2.py", 226 42) 227 self.assertEqual(len(w), 0) 228 229 def test_module_globals(self): 230 with original_warnings.catch_warnings(record=True, 231 module=self.module) as w: 232 self.module.simplefilter("always", UserWarning) 233 234 # bpo-33509: module_globals=None must not crash 235 self.module.warn_explicit('msg', UserWarning, "filename", 42, 236 module_globals=None) 237 self.assertEqual(len(w), 1) 238 239 # Invalid module_globals type 240 with self.assertRaises(TypeError): 241 self.module.warn_explicit('msg', UserWarning, "filename", 42, 242 module_globals=True) 243 self.assertEqual(len(w), 1) 244 245 # Empty module_globals 246 self.module.warn_explicit('msg', UserWarning, "filename", 42, 247 module_globals={}) 248 self.assertEqual(len(w), 2) 249 250 def test_inheritance(self): 251 with original_warnings.catch_warnings(module=self.module) as w: 252 self.module.resetwarnings() 253 self.module.filterwarnings("error", category=Warning) 254 self.assertRaises(UserWarning, self.module.warn, 255 "FilterTests.test_inheritance", UserWarning) 256 257 def test_ordering(self): 258 with original_warnings.catch_warnings(record=True, 259 module=self.module) as w: 260 self.module.resetwarnings() 261 self.module.filterwarnings("ignore", category=UserWarning) 262 self.module.filterwarnings("error", category=UserWarning, 263 append=True) 264 del w[:] 265 try: 266 self.module.warn("FilterTests.test_ordering", UserWarning) 267 except UserWarning: 268 self.fail("order handling for actions failed") 269 self.assertEqual(len(w), 0) 270 271 def test_filterwarnings(self): 272 # Test filterwarnings(). 273 # Implicitly also tests resetwarnings(). 274 with original_warnings.catch_warnings(record=True, 275 module=self.module) as w: 276 self.module.filterwarnings("error", "", Warning, "", 0) 277 self.assertRaises(UserWarning, self.module.warn, 'convert to error') 278 279 self.module.resetwarnings() 280 text = 'handle normally' 281 self.module.warn(text) 282 self.assertEqual(str(w[-1].message), text) 283 self.assertIs(w[-1].category, UserWarning) 284 285 self.module.filterwarnings("ignore", "", Warning, "", 0) 286 text = 'filtered out' 287 self.module.warn(text) 288 self.assertNotEqual(str(w[-1].message), text) 289 290 self.module.resetwarnings() 291 self.module.filterwarnings("error", "hex*", Warning, "", 0) 292 self.assertRaises(UserWarning, self.module.warn, 'hex/oct') 293 text = 'nonmatching text' 294 self.module.warn(text) 295 self.assertEqual(str(w[-1].message), text) 296 self.assertIs(w[-1].category, UserWarning) 297 298 def test_message_matching(self): 299 with original_warnings.catch_warnings(record=True, 300 module=self.module) as w: 301 self.module.simplefilter("ignore", UserWarning) 302 self.module.filterwarnings("error", "match", UserWarning) 303 self.assertRaises(UserWarning, self.module.warn, "match") 304 self.assertRaises(UserWarning, self.module.warn, "match prefix") 305 self.module.warn("suffix match") 306 self.assertEqual(w, []) 307 self.module.warn("something completely different") 308 self.assertEqual(w, []) 309 310 def test_mutate_filter_list(self): 311 class X: 312 def match(self, a): 313 L[:] = [] 314 315 L = [("default",X(),UserWarning,X(),0) for i in range(2)] 316 with original_warnings.catch_warnings(record=True, 317 module=self.module) as w: 318 self.module.filters = L 319 self.module.warn_explicit(UserWarning("b"), None, "f.py", 42) 320 self.assertEqual(str(w[-1].message), "b") 321 322 def test_filterwarnings_duplicate_filters(self): 323 with original_warnings.catch_warnings(module=self.module): 324 self.module.resetwarnings() 325 self.module.filterwarnings("error", category=UserWarning) 326 self.assertEqual(len(self.module.filters), 1) 327 self.module.filterwarnings("ignore", category=UserWarning) 328 self.module.filterwarnings("error", category=UserWarning) 329 self.assertEqual( 330 len(self.module.filters), 2, 331 "filterwarnings inserted duplicate filter" 332 ) 333 self.assertEqual( 334 self.module.filters[0][0], "error", 335 "filterwarnings did not promote filter to " 336 "the beginning of list" 337 ) 338 339 def test_simplefilter_duplicate_filters(self): 340 with original_warnings.catch_warnings(module=self.module): 341 self.module.resetwarnings() 342 self.module.simplefilter("error", category=UserWarning) 343 self.assertEqual(len(self.module.filters), 1) 344 self.module.simplefilter("ignore", category=UserWarning) 345 self.module.simplefilter("error", category=UserWarning) 346 self.assertEqual( 347 len(self.module.filters), 2, 348 "simplefilter inserted duplicate filter" 349 ) 350 self.assertEqual( 351 self.module.filters[0][0], "error", 352 "simplefilter did not promote filter to the beginning of list" 353 ) 354 355 def test_append_duplicate(self): 356 with original_warnings.catch_warnings(module=self.module, 357 record=True) as w: 358 self.module.resetwarnings() 359 self.module.simplefilter("ignore") 360 self.module.simplefilter("error", append=True) 361 self.module.simplefilter("ignore", append=True) 362 self.module.warn("test_append_duplicate", category=UserWarning) 363 self.assertEqual(len(self.module.filters), 2, 364 "simplefilter inserted duplicate filter" 365 ) 366 self.assertEqual(len(w), 0, 367 "appended duplicate changed order of filters" 368 ) 369 370class CFilterTests(FilterTests, unittest.TestCase): 371 module = c_warnings 372 373class PyFilterTests(FilterTests, unittest.TestCase): 374 module = py_warnings 375 376 377class WarnTests(BaseTest): 378 379 """Test warnings.warn() and warnings.warn_explicit().""" 380 381 def test_message(self): 382 with original_warnings.catch_warnings(record=True, 383 module=self.module) as w: 384 self.module.simplefilter("once") 385 for i in range(4): 386 text = 'multi %d' %i # Different text on each call. 387 self.module.warn(text) 388 self.assertEqual(str(w[-1].message), text) 389 self.assertIs(w[-1].category, UserWarning) 390 391 # Issue 3639 392 def test_warn_nonstandard_types(self): 393 # warn() should handle non-standard types without issue. 394 for ob in (Warning, None, 42): 395 with original_warnings.catch_warnings(record=True, 396 module=self.module) as w: 397 self.module.simplefilter("once") 398 self.module.warn(ob) 399 # Don't directly compare objects since 400 # ``Warning() != Warning()``. 401 self.assertEqual(str(w[-1].message), str(UserWarning(ob))) 402 403 def test_filename(self): 404 with warnings_state(self.module): 405 with original_warnings.catch_warnings(record=True, 406 module=self.module) as w: 407 warning_tests.inner("spam1") 408 self.assertEqual(os.path.basename(w[-1].filename), 409 "stacklevel.py") 410 warning_tests.outer("spam2") 411 self.assertEqual(os.path.basename(w[-1].filename), 412 "stacklevel.py") 413 414 def test_stacklevel(self): 415 # Test stacklevel argument 416 # make sure all messages are different, so the warning won't be skipped 417 with warnings_state(self.module): 418 with original_warnings.catch_warnings(record=True, 419 module=self.module) as w: 420 warning_tests.inner("spam3", stacklevel=1) 421 self.assertEqual(os.path.basename(w[-1].filename), 422 "stacklevel.py") 423 warning_tests.outer("spam4", stacklevel=1) 424 self.assertEqual(os.path.basename(w[-1].filename), 425 "stacklevel.py") 426 427 warning_tests.inner("spam5", stacklevel=2) 428 self.assertEqual(os.path.basename(w[-1].filename), 429 "__init__.py") 430 warning_tests.outer("spam6", stacklevel=2) 431 self.assertEqual(os.path.basename(w[-1].filename), 432 "stacklevel.py") 433 warning_tests.outer("spam6.5", stacklevel=3) 434 self.assertEqual(os.path.basename(w[-1].filename), 435 "__init__.py") 436 437 warning_tests.inner("spam7", stacklevel=9999) 438 self.assertEqual(os.path.basename(w[-1].filename), 439 "sys") 440 441 def test_stacklevel_import(self): 442 # Issue #24305: With stacklevel=2, module-level warnings should work. 443 support.unload('test.test_warnings.data.import_warning') 444 with warnings_state(self.module): 445 with original_warnings.catch_warnings(record=True, 446 module=self.module) as w: 447 self.module.simplefilter('always') 448 import test.test_warnings.data.import_warning 449 self.assertEqual(len(w), 1) 450 self.assertEqual(w[0].filename, __file__) 451 452 def test_exec_filename(self): 453 filename = "<warnings-test>" 454 codeobj = compile(("import warnings\n" 455 "warnings.warn('hello', UserWarning)"), 456 filename, "exec") 457 with original_warnings.catch_warnings(record=True) as w: 458 self.module.simplefilter("always", category=UserWarning) 459 exec(codeobj) 460 self.assertEqual(w[0].filename, filename) 461 462 def test_warn_explicit_non_ascii_filename(self): 463 with original_warnings.catch_warnings(record=True, 464 module=self.module) as w: 465 self.module.resetwarnings() 466 self.module.filterwarnings("always", category=UserWarning) 467 for filename in ("nonascii\xe9\u20ac", "surrogate\udc80"): 468 try: 469 os.fsencode(filename) 470 except UnicodeEncodeError: 471 continue 472 self.module.warn_explicit("text", UserWarning, filename, 1) 473 self.assertEqual(w[-1].filename, filename) 474 475 def test_warn_explicit_type_errors(self): 476 # warn_explicit() should error out gracefully if it is given objects 477 # of the wrong types. 478 # lineno is expected to be an integer. 479 self.assertRaises(TypeError, self.module.warn_explicit, 480 None, UserWarning, None, None) 481 # Either 'message' needs to be an instance of Warning or 'category' 482 # needs to be a subclass. 483 self.assertRaises(TypeError, self.module.warn_explicit, 484 None, None, None, 1) 485 # 'registry' must be a dict or None. 486 self.assertRaises((TypeError, AttributeError), 487 self.module.warn_explicit, 488 None, Warning, None, 1, registry=42) 489 490 def test_bad_str(self): 491 # issue 6415 492 # Warnings instance with a bad format string for __str__ should not 493 # trigger a bus error. 494 class BadStrWarning(Warning): 495 """Warning with a bad format string for __str__.""" 496 def __str__(self): 497 return ("A bad formatted string %(err)" % 498 {"err" : "there is no %(err)s"}) 499 500 with self.assertRaises(ValueError): 501 self.module.warn(BadStrWarning()) 502 503 def test_warning_classes(self): 504 class MyWarningClass(Warning): 505 pass 506 507 class NonWarningSubclass: 508 pass 509 510 # passing a non-subclass of Warning should raise a TypeError 511 with self.assertRaises(TypeError) as cm: 512 self.module.warn('bad warning category', '') 513 self.assertIn('category must be a Warning subclass, not ', 514 str(cm.exception)) 515 516 with self.assertRaises(TypeError) as cm: 517 self.module.warn('bad warning category', NonWarningSubclass) 518 self.assertIn('category must be a Warning subclass, not ', 519 str(cm.exception)) 520 521 # check that warning instances also raise a TypeError 522 with self.assertRaises(TypeError) as cm: 523 self.module.warn('bad warning category', MyWarningClass()) 524 self.assertIn('category must be a Warning subclass, not ', 525 str(cm.exception)) 526 527 with original_warnings.catch_warnings(module=self.module): 528 self.module.resetwarnings() 529 self.module.filterwarnings('default') 530 with self.assertWarns(MyWarningClass) as cm: 531 self.module.warn('good warning category', MyWarningClass) 532 self.assertEqual('good warning category', str(cm.warning)) 533 534 with self.assertWarns(UserWarning) as cm: 535 self.module.warn('good warning category', None) 536 self.assertEqual('good warning category', str(cm.warning)) 537 538 with self.assertWarns(MyWarningClass) as cm: 539 self.module.warn('good warning category', MyWarningClass) 540 self.assertIsInstance(cm.warning, Warning) 541 542class CWarnTests(WarnTests, unittest.TestCase): 543 module = c_warnings 544 545 # As an early adopter, we sanity check the 546 # test.support.import_fresh_module utility function 547 def test_accelerated(self): 548 self.assertIsNot(original_warnings, self.module) 549 self.assertFalse(hasattr(self.module.warn, '__code__')) 550 551class PyWarnTests(WarnTests, unittest.TestCase): 552 module = py_warnings 553 554 # As an early adopter, we sanity check the 555 # test.support.import_fresh_module utility function 556 def test_pure_python(self): 557 self.assertIsNot(original_warnings, self.module) 558 self.assertTrue(hasattr(self.module.warn, '__code__')) 559 560 561class WCmdLineTests(BaseTest): 562 563 def test_improper_input(self): 564 # Uses the private _setoption() function to test the parsing 565 # of command-line warning arguments 566 with original_warnings.catch_warnings(module=self.module): 567 self.assertRaises(self.module._OptionError, 568 self.module._setoption, '1:2:3:4:5:6') 569 self.assertRaises(self.module._OptionError, 570 self.module._setoption, 'bogus::Warning') 571 self.assertRaises(self.module._OptionError, 572 self.module._setoption, 'ignore:2::4:-5') 573 with self.assertRaises(self.module._OptionError): 574 self.module._setoption('ignore::123') 575 with self.assertRaises(self.module._OptionError): 576 self.module._setoption('ignore::123abc') 577 with self.assertRaises(self.module._OptionError): 578 self.module._setoption('ignore::===') 579 with self.assertRaisesRegex(self.module._OptionError, 'Wärning'): 580 self.module._setoption('ignore::Wärning') 581 self.module._setoption('error::Warning::0') 582 self.assertRaises(UserWarning, self.module.warn, 'convert to error') 583 584 def test_import_from_module(self): 585 with original_warnings.catch_warnings(module=self.module): 586 self.module._setoption('ignore::Warning') 587 with self.assertRaises(self.module._OptionError): 588 self.module._setoption('ignore::TestWarning') 589 with self.assertRaises(self.module._OptionError): 590 self.module._setoption('ignore::test.test_warnings.bogus') 591 self.module._setoption('error::test.test_warnings.TestWarning') 592 with self.assertRaises(TestWarning): 593 self.module.warn('test warning', TestWarning) 594 595 596class CWCmdLineTests(WCmdLineTests, unittest.TestCase): 597 module = c_warnings 598 599 600class PyWCmdLineTests(WCmdLineTests, unittest.TestCase): 601 module = py_warnings 602 603 def test_improper_option(self): 604 # Same as above, but check that the message is printed out when 605 # the interpreter is executed. This also checks that options are 606 # actually parsed at all. 607 rc, out, err = assert_python_ok("-Wxxx", "-c", "pass") 608 self.assertIn(b"Invalid -W option ignored: invalid action: 'xxx'", err) 609 610 def test_warnings_bootstrap(self): 611 # Check that the warnings module does get loaded when -W<some option> 612 # is used (see issue #10372 for an example of silent bootstrap failure). 613 rc, out, err = assert_python_ok("-Wi", "-c", 614 "import sys; sys.modules['warnings'].warn('foo', RuntimeWarning)") 615 # '-Wi' was observed 616 self.assertFalse(out.strip()) 617 self.assertNotIn(b'RuntimeWarning', err) 618 619 620class _WarningsTests(BaseTest, unittest.TestCase): 621 622 """Tests specific to the _warnings module.""" 623 624 module = c_warnings 625 626 def test_filter(self): 627 # Everything should function even if 'filters' is not in warnings. 628 with original_warnings.catch_warnings(module=self.module) as w: 629 self.module.filterwarnings("error", "", Warning, "", 0) 630 self.assertRaises(UserWarning, self.module.warn, 631 'convert to error') 632 del self.module.filters 633 self.assertRaises(UserWarning, self.module.warn, 634 'convert to error') 635 636 def test_onceregistry(self): 637 # Replacing or removing the onceregistry should be okay. 638 global __warningregistry__ 639 message = UserWarning('onceregistry test') 640 try: 641 original_registry = self.module.onceregistry 642 __warningregistry__ = {} 643 with original_warnings.catch_warnings(record=True, 644 module=self.module) as w: 645 self.module.resetwarnings() 646 self.module.filterwarnings("once", category=UserWarning) 647 self.module.warn_explicit(message, UserWarning, "file", 42) 648 self.assertEqual(w[-1].message, message) 649 del w[:] 650 self.module.warn_explicit(message, UserWarning, "file", 42) 651 self.assertEqual(len(w), 0) 652 # Test the resetting of onceregistry. 653 self.module.onceregistry = {} 654 __warningregistry__ = {} 655 self.module.warn('onceregistry test') 656 self.assertEqual(w[-1].message.args, message.args) 657 # Removal of onceregistry is okay. 658 del w[:] 659 del self.module.onceregistry 660 __warningregistry__ = {} 661 self.module.warn_explicit(message, UserWarning, "file", 42) 662 self.assertEqual(len(w), 0) 663 finally: 664 self.module.onceregistry = original_registry 665 666 def test_default_action(self): 667 # Replacing or removing defaultaction should be okay. 668 message = UserWarning("defaultaction test") 669 original = self.module.defaultaction 670 try: 671 with original_warnings.catch_warnings(record=True, 672 module=self.module) as w: 673 self.module.resetwarnings() 674 registry = {} 675 self.module.warn_explicit(message, UserWarning, "<test>", 42, 676 registry=registry) 677 self.assertEqual(w[-1].message, message) 678 self.assertEqual(len(w), 1) 679 # One actual registry key plus the "version" key 680 self.assertEqual(len(registry), 2) 681 self.assertIn("version", registry) 682 del w[:] 683 # Test removal. 684 del self.module.defaultaction 685 __warningregistry__ = {} 686 registry = {} 687 self.module.warn_explicit(message, UserWarning, "<test>", 43, 688 registry=registry) 689 self.assertEqual(w[-1].message, message) 690 self.assertEqual(len(w), 1) 691 self.assertEqual(len(registry), 2) 692 del w[:] 693 # Test setting. 694 self.module.defaultaction = "ignore" 695 __warningregistry__ = {} 696 registry = {} 697 self.module.warn_explicit(message, UserWarning, "<test>", 44, 698 registry=registry) 699 self.assertEqual(len(w), 0) 700 finally: 701 self.module.defaultaction = original 702 703 def test_showwarning_missing(self): 704 # Test that showwarning() missing is okay. 705 text = 'del showwarning test' 706 with original_warnings.catch_warnings(module=self.module): 707 self.module.filterwarnings("always", category=UserWarning) 708 del self.module.showwarning 709 with support.captured_output('stderr') as stream: 710 self.module.warn(text) 711 result = stream.getvalue() 712 self.assertIn(text, result) 713 714 def test_showwarnmsg_missing(self): 715 # Test that _showwarnmsg() missing is okay. 716 text = 'del _showwarnmsg test' 717 with original_warnings.catch_warnings(module=self.module): 718 self.module.filterwarnings("always", category=UserWarning) 719 720 show = self.module._showwarnmsg 721 try: 722 del self.module._showwarnmsg 723 with support.captured_output('stderr') as stream: 724 self.module.warn(text) 725 result = stream.getvalue() 726 finally: 727 self.module._showwarnmsg = show 728 self.assertIn(text, result) 729 730 def test_showwarning_not_callable(self): 731 with original_warnings.catch_warnings(module=self.module): 732 self.module.filterwarnings("always", category=UserWarning) 733 self.module.showwarning = print 734 with support.captured_output('stdout'): 735 self.module.warn('Warning!') 736 self.module.showwarning = 23 737 self.assertRaises(TypeError, self.module.warn, "Warning!") 738 739 def test_show_warning_output(self): 740 # With showwarning() missing, make sure that output is okay. 741 text = 'test show_warning' 742 with original_warnings.catch_warnings(module=self.module): 743 self.module.filterwarnings("always", category=UserWarning) 744 del self.module.showwarning 745 with support.captured_output('stderr') as stream: 746 warning_tests.inner(text) 747 result = stream.getvalue() 748 self.assertEqual(result.count('\n'), 2, 749 "Too many newlines in %r" % result) 750 first_line, second_line = result.split('\n', 1) 751 expected_file = os.path.splitext(warning_tests.__file__)[0] + '.py' 752 first_line_parts = first_line.rsplit(':', 3) 753 path, line, warning_class, message = first_line_parts 754 line = int(line) 755 self.assertEqual(expected_file, path) 756 self.assertEqual(warning_class, ' ' + UserWarning.__name__) 757 self.assertEqual(message, ' ' + text) 758 expected_line = ' ' + linecache.getline(path, line).strip() + '\n' 759 assert expected_line 760 self.assertEqual(second_line, expected_line) 761 762 def test_filename_none(self): 763 # issue #12467: race condition if a warning is emitted at shutdown 764 globals_dict = globals() 765 oldfile = globals_dict['__file__'] 766 try: 767 catch = original_warnings.catch_warnings(record=True, 768 module=self.module) 769 with catch as w: 770 self.module.filterwarnings("always", category=UserWarning) 771 globals_dict['__file__'] = None 772 original_warnings.warn('test', UserWarning) 773 self.assertTrue(len(w)) 774 finally: 775 globals_dict['__file__'] = oldfile 776 777 def test_stderr_none(self): 778 rc, stdout, stderr = assert_python_ok("-c", 779 "import sys; sys.stderr = None; " 780 "import warnings; warnings.simplefilter('always'); " 781 "warnings.warn('Warning!')") 782 self.assertEqual(stdout, b'') 783 self.assertNotIn(b'Warning!', stderr) 784 self.assertNotIn(b'Error', stderr) 785 786 def test_issue31285(self): 787 # warn_explicit() should neither raise a SystemError nor cause an 788 # assertion failure, in case the return value of get_source() has a 789 # bad splitlines() method. 790 def get_bad_loader(splitlines_ret_val): 791 class BadLoader: 792 def get_source(self, fullname): 793 class BadSource(str): 794 def splitlines(self): 795 return splitlines_ret_val 796 return BadSource('spam') 797 return BadLoader() 798 799 wmod = self.module 800 with original_warnings.catch_warnings(module=wmod): 801 wmod.filterwarnings('default', category=UserWarning) 802 803 with support.captured_stderr() as stderr: 804 wmod.warn_explicit( 805 'foo', UserWarning, 'bar', 1, 806 module_globals={'__loader__': get_bad_loader(42), 807 '__name__': 'foobar'}) 808 self.assertIn('UserWarning: foo', stderr.getvalue()) 809 810 show = wmod._showwarnmsg 811 try: 812 del wmod._showwarnmsg 813 with support.captured_stderr() as stderr: 814 wmod.warn_explicit( 815 'eggs', UserWarning, 'bar', 1, 816 module_globals={'__loader__': get_bad_loader([42]), 817 '__name__': 'foobar'}) 818 self.assertIn('UserWarning: eggs', stderr.getvalue()) 819 finally: 820 wmod._showwarnmsg = show 821 822 @support.cpython_only 823 def test_issue31411(self): 824 # warn_explicit() shouldn't raise a SystemError in case 825 # warnings.onceregistry isn't a dictionary. 826 wmod = self.module 827 with original_warnings.catch_warnings(module=wmod): 828 wmod.filterwarnings('once') 829 with support.swap_attr(wmod, 'onceregistry', None): 830 with self.assertRaises(TypeError): 831 wmod.warn_explicit('foo', Warning, 'bar', 1, registry=None) 832 833 @support.cpython_only 834 def test_issue31416(self): 835 # warn_explicit() shouldn't cause an assertion failure in case of a 836 # bad warnings.filters or warnings.defaultaction. 837 wmod = self.module 838 with original_warnings.catch_warnings(module=wmod): 839 wmod.filters = [(None, None, Warning, None, 0)] 840 with self.assertRaises(TypeError): 841 wmod.warn_explicit('foo', Warning, 'bar', 1) 842 843 wmod.filters = [] 844 with support.swap_attr(wmod, 'defaultaction', None), \ 845 self.assertRaises(TypeError): 846 wmod.warn_explicit('foo', Warning, 'bar', 1) 847 848 @support.cpython_only 849 def test_issue31566(self): 850 # warn() shouldn't cause an assertion failure in case of a bad 851 # __name__ global. 852 with original_warnings.catch_warnings(module=self.module): 853 self.module.filterwarnings('error', category=UserWarning) 854 with support.swap_item(globals(), '__name__', b'foo'), \ 855 support.swap_item(globals(), '__file__', None): 856 self.assertRaises(UserWarning, self.module.warn, 'bar') 857 858 859class WarningsDisplayTests(BaseTest): 860 861 """Test the displaying of warnings and the ability to overload functions 862 related to displaying warnings.""" 863 864 def test_formatwarning(self): 865 message = "msg" 866 category = Warning 867 file_name = os.path.splitext(warning_tests.__file__)[0] + '.py' 868 line_num = 3 869 file_line = linecache.getline(file_name, line_num).strip() 870 format = "%s:%s: %s: %s\n %s\n" 871 expect = format % (file_name, line_num, category.__name__, message, 872 file_line) 873 self.assertEqual(expect, self.module.formatwarning(message, 874 category, file_name, line_num)) 875 # Test the 'line' argument. 876 file_line += " for the win!" 877 expect = format % (file_name, line_num, category.__name__, message, 878 file_line) 879 self.assertEqual(expect, self.module.formatwarning(message, 880 category, file_name, line_num, file_line)) 881 882 def test_showwarning(self): 883 file_name = os.path.splitext(warning_tests.__file__)[0] + '.py' 884 line_num = 3 885 expected_file_line = linecache.getline(file_name, line_num).strip() 886 message = 'msg' 887 category = Warning 888 file_object = StringIO() 889 expect = self.module.formatwarning(message, category, file_name, 890 line_num) 891 self.module.showwarning(message, category, file_name, line_num, 892 file_object) 893 self.assertEqual(file_object.getvalue(), expect) 894 # Test 'line' argument. 895 expected_file_line += "for the win!" 896 expect = self.module.formatwarning(message, category, file_name, 897 line_num, expected_file_line) 898 file_object = StringIO() 899 self.module.showwarning(message, category, file_name, line_num, 900 file_object, expected_file_line) 901 self.assertEqual(expect, file_object.getvalue()) 902 903 def test_formatwarning_override(self): 904 # bpo-35178: Test that a custom formatwarning function gets the 'line' 905 # argument as a positional argument, and not only as a keyword argument 906 def myformatwarning(message, category, filename, lineno, text): 907 return f'm={message}:c={category}:f={filename}:l={lineno}:t={text}' 908 909 file_name = os.path.splitext(warning_tests.__file__)[0] + '.py' 910 line_num = 3 911 file_line = linecache.getline(file_name, line_num).strip() 912 message = 'msg' 913 category = Warning 914 file_object = StringIO() 915 expected = f'm={message}:c={category}:f={file_name}:l={line_num}' + \ 916 f':t={file_line}' 917 with support.swap_attr(self.module, 'formatwarning', myformatwarning): 918 self.module.showwarning(message, category, file_name, line_num, 919 file_object, file_line) 920 self.assertEqual(file_object.getvalue(), expected) 921 922 923class CWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase): 924 module = c_warnings 925 926class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase): 927 module = py_warnings 928 929 def test_tracemalloc(self): 930 self.addCleanup(support.unlink, support.TESTFN) 931 932 with open(support.TESTFN, 'w') as fp: 933 fp.write(textwrap.dedent(""" 934 def func(): 935 f = open(__file__) 936 # Emit ResourceWarning 937 f = None 938 939 func() 940 """)) 941 942 def run(*args): 943 res = assert_python_ok(*args) 944 stderr = res.err.decode('ascii', 'replace') 945 stderr = '\n'.join(stderr.splitlines()) 946 947 # normalize newlines 948 stderr = re.sub('<.*>', '<...>', stderr) 949 return stderr 950 951 # tracemalloc disabled 952 stderr = run('-Wd', support.TESTFN) 953 expected = textwrap.dedent(''' 954 {fname}:5: ResourceWarning: unclosed file <...> 955 f = None 956 ResourceWarning: Enable tracemalloc to get the object allocation traceback 957 ''') 958 expected = expected.format(fname=support.TESTFN).strip() 959 self.assertEqual(stderr, expected) 960 961 # tracemalloc enabled 962 stderr = run('-Wd', '-X', 'tracemalloc=2', support.TESTFN) 963 expected = textwrap.dedent(''' 964 {fname}:5: ResourceWarning: unclosed file <...> 965 f = None 966 Object allocated at (most recent call last): 967 File "{fname}", lineno 7 968 func() 969 File "{fname}", lineno 3 970 f = open(__file__) 971 ''') 972 expected = expected.format(fname=support.TESTFN).strip() 973 self.assertEqual(stderr, expected) 974 975 976class CatchWarningTests(BaseTest): 977 978 """Test catch_warnings().""" 979 980 def test_catch_warnings_restore(self): 981 wmod = self.module 982 orig_filters = wmod.filters 983 orig_showwarning = wmod.showwarning 984 # Ensure both showwarning and filters are restored when recording 985 with wmod.catch_warnings(module=wmod, record=True): 986 wmod.filters = wmod.showwarning = object() 987 self.assertIs(wmod.filters, orig_filters) 988 self.assertIs(wmod.showwarning, orig_showwarning) 989 # Same test, but with recording disabled 990 with wmod.catch_warnings(module=wmod, record=False): 991 wmod.filters = wmod.showwarning = object() 992 self.assertIs(wmod.filters, orig_filters) 993 self.assertIs(wmod.showwarning, orig_showwarning) 994 995 def test_catch_warnings_recording(self): 996 wmod = self.module 997 # Ensure warnings are recorded when requested 998 with wmod.catch_warnings(module=wmod, record=True) as w: 999 self.assertEqual(w, []) 1000 self.assertIs(type(w), list) 1001 wmod.simplefilter("always") 1002 wmod.warn("foo") 1003 self.assertEqual(str(w[-1].message), "foo") 1004 wmod.warn("bar") 1005 self.assertEqual(str(w[-1].message), "bar") 1006 self.assertEqual(str(w[0].message), "foo") 1007 self.assertEqual(str(w[1].message), "bar") 1008 del w[:] 1009 self.assertEqual(w, []) 1010 # Ensure warnings are not recorded when not requested 1011 orig_showwarning = wmod.showwarning 1012 with wmod.catch_warnings(module=wmod, record=False) as w: 1013 self.assertIsNone(w) 1014 self.assertIs(wmod.showwarning, orig_showwarning) 1015 1016 def test_catch_warnings_reentry_guard(self): 1017 wmod = self.module 1018 # Ensure catch_warnings is protected against incorrect usage 1019 x = wmod.catch_warnings(module=wmod, record=True) 1020 self.assertRaises(RuntimeError, x.__exit__) 1021 with x: 1022 self.assertRaises(RuntimeError, x.__enter__) 1023 # Same test, but with recording disabled 1024 x = wmod.catch_warnings(module=wmod, record=False) 1025 self.assertRaises(RuntimeError, x.__exit__) 1026 with x: 1027 self.assertRaises(RuntimeError, x.__enter__) 1028 1029 def test_catch_warnings_defaults(self): 1030 wmod = self.module 1031 orig_filters = wmod.filters 1032 orig_showwarning = wmod.showwarning 1033 # Ensure default behaviour is not to record warnings 1034 with wmod.catch_warnings(module=wmod) as w: 1035 self.assertIsNone(w) 1036 self.assertIs(wmod.showwarning, orig_showwarning) 1037 self.assertIsNot(wmod.filters, orig_filters) 1038 self.assertIs(wmod.filters, orig_filters) 1039 if wmod is sys.modules['warnings']: 1040 # Ensure the default module is this one 1041 with wmod.catch_warnings() as w: 1042 self.assertIsNone(w) 1043 self.assertIs(wmod.showwarning, orig_showwarning) 1044 self.assertIsNot(wmod.filters, orig_filters) 1045 self.assertIs(wmod.filters, orig_filters) 1046 1047 def test_record_override_showwarning_before(self): 1048 # Issue #28835: If warnings.showwarning() was overridden, make sure 1049 # that catch_warnings(record=True) overrides it again. 1050 text = "This is a warning" 1051 wmod = self.module 1052 my_log = [] 1053 1054 def my_logger(message, category, filename, lineno, file=None, line=None): 1055 nonlocal my_log 1056 my_log.append(message) 1057 1058 # Override warnings.showwarning() before calling catch_warnings() 1059 with support.swap_attr(wmod, 'showwarning', my_logger): 1060 with wmod.catch_warnings(module=wmod, record=True) as log: 1061 self.assertIsNot(wmod.showwarning, my_logger) 1062 1063 wmod.simplefilter("always") 1064 wmod.warn(text) 1065 1066 self.assertIs(wmod.showwarning, my_logger) 1067 1068 self.assertEqual(len(log), 1, log) 1069 self.assertEqual(log[0].message.args[0], text) 1070 self.assertEqual(my_log, []) 1071 1072 def test_record_override_showwarning_inside(self): 1073 # Issue #28835: It is possible to override warnings.showwarning() 1074 # in the catch_warnings(record=True) context manager. 1075 text = "This is a warning" 1076 wmod = self.module 1077 my_log = [] 1078 1079 def my_logger(message, category, filename, lineno, file=None, line=None): 1080 nonlocal my_log 1081 my_log.append(message) 1082 1083 with wmod.catch_warnings(module=wmod, record=True) as log: 1084 wmod.simplefilter("always") 1085 wmod.showwarning = my_logger 1086 wmod.warn(text) 1087 1088 self.assertEqual(len(my_log), 1, my_log) 1089 self.assertEqual(my_log[0].args[0], text) 1090 self.assertEqual(log, []) 1091 1092 def test_check_warnings(self): 1093 # Explicit tests for the test.support convenience wrapper 1094 wmod = self.module 1095 if wmod is not sys.modules['warnings']: 1096 self.skipTest('module to test is not loaded warnings module') 1097 with support.check_warnings(quiet=False) as w: 1098 self.assertEqual(w.warnings, []) 1099 wmod.simplefilter("always") 1100 wmod.warn("foo") 1101 self.assertEqual(str(w.message), "foo") 1102 wmod.warn("bar") 1103 self.assertEqual(str(w.message), "bar") 1104 self.assertEqual(str(w.warnings[0].message), "foo") 1105 self.assertEqual(str(w.warnings[1].message), "bar") 1106 w.reset() 1107 self.assertEqual(w.warnings, []) 1108 1109 with support.check_warnings(): 1110 # defaults to quiet=True without argument 1111 pass 1112 with support.check_warnings(('foo', UserWarning)): 1113 wmod.warn("foo") 1114 1115 with self.assertRaises(AssertionError): 1116 with support.check_warnings(('', RuntimeWarning)): 1117 # defaults to quiet=False with argument 1118 pass 1119 with self.assertRaises(AssertionError): 1120 with support.check_warnings(('foo', RuntimeWarning)): 1121 wmod.warn("foo") 1122 1123class CCatchWarningTests(CatchWarningTests, unittest.TestCase): 1124 module = c_warnings 1125 1126class PyCatchWarningTests(CatchWarningTests, unittest.TestCase): 1127 module = py_warnings 1128 1129 1130class EnvironmentVariableTests(BaseTest): 1131 1132 def test_single_warning(self): 1133 rc, stdout, stderr = assert_python_ok("-c", 1134 "import sys; sys.stdout.write(str(sys.warnoptions))", 1135 PYTHONWARNINGS="ignore::DeprecationWarning", 1136 PYTHONDEVMODE="") 1137 self.assertEqual(stdout, b"['ignore::DeprecationWarning']") 1138 1139 def test_comma_separated_warnings(self): 1140 rc, stdout, stderr = assert_python_ok("-c", 1141 "import sys; sys.stdout.write(str(sys.warnoptions))", 1142 PYTHONWARNINGS="ignore::DeprecationWarning,ignore::UnicodeWarning", 1143 PYTHONDEVMODE="") 1144 self.assertEqual(stdout, 1145 b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']") 1146 1147 def test_envvar_and_command_line(self): 1148 rc, stdout, stderr = assert_python_ok("-Wignore::UnicodeWarning", "-c", 1149 "import sys; sys.stdout.write(str(sys.warnoptions))", 1150 PYTHONWARNINGS="ignore::DeprecationWarning", 1151 PYTHONDEVMODE="") 1152 self.assertEqual(stdout, 1153 b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']") 1154 1155 def test_conflicting_envvar_and_command_line(self): 1156 rc, stdout, stderr = assert_python_failure("-Werror::DeprecationWarning", "-c", 1157 "import sys, warnings; sys.stdout.write(str(sys.warnoptions)); " 1158 "warnings.warn('Message', DeprecationWarning)", 1159 PYTHONWARNINGS="default::DeprecationWarning", 1160 PYTHONDEVMODE="") 1161 self.assertEqual(stdout, 1162 b"['default::DeprecationWarning', 'error::DeprecationWarning']") 1163 self.assertEqual(stderr.splitlines(), 1164 [b"Traceback (most recent call last):", 1165 b" File \"<string>\", line 1, in <module>", 1166 b"DeprecationWarning: Message"]) 1167 1168 def test_default_filter_configuration(self): 1169 pure_python_api = self.module is py_warnings 1170 if Py_DEBUG: 1171 expected_default_filters = [] 1172 else: 1173 if pure_python_api: 1174 main_module_filter = re.compile("__main__") 1175 else: 1176 main_module_filter = "__main__" 1177 expected_default_filters = [ 1178 ('default', None, DeprecationWarning, main_module_filter, 0), 1179 ('ignore', None, DeprecationWarning, None, 0), 1180 ('ignore', None, PendingDeprecationWarning, None, 0), 1181 ('ignore', None, ImportWarning, None, 0), 1182 ('ignore', None, ResourceWarning, None, 0), 1183 ] 1184 expected_output = [str(f).encode() for f in expected_default_filters] 1185 1186 if pure_python_api: 1187 # Disable the warnings acceleration module in the subprocess 1188 code = "import sys; sys.modules.pop('warnings', None); sys.modules['_warnings'] = None; " 1189 else: 1190 code = "" 1191 code += "import warnings; [print(f) for f in warnings.filters]" 1192 1193 rc, stdout, stderr = assert_python_ok("-c", code, __isolated=True) 1194 stdout_lines = [line.strip() for line in stdout.splitlines()] 1195 self.maxDiff = None 1196 self.assertEqual(stdout_lines, expected_output) 1197 1198 1199 @unittest.skipUnless(sys.getfilesystemencoding() != 'ascii', 1200 'requires non-ascii filesystemencoding') 1201 def test_nonascii(self): 1202 PYTHONWARNINGS="ignore:DeprecationWarning" + (support.FS_NONASCII or '') 1203 rc, stdout, stderr = assert_python_ok("-c", 1204 "import sys; sys.stdout.write(str(sys.warnoptions))", 1205 PYTHONIOENCODING="utf-8", 1206 PYTHONWARNINGS=PYTHONWARNINGS, 1207 PYTHONDEVMODE="") 1208 self.assertEqual(stdout, str([PYTHONWARNINGS]).encode()) 1209 1210class CEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase): 1211 module = c_warnings 1212 1213class PyEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase): 1214 module = py_warnings 1215 1216 1217class BootstrapTest(unittest.TestCase): 1218 def test_issue_8766(self): 1219 # "import encodings" emits a warning whereas the warnings is not loaded 1220 # or not completely loaded (warnings imports indirectly encodings by 1221 # importing linecache) yet 1222 with support.temp_cwd() as cwd, support.temp_cwd('encodings'): 1223 # encodings loaded by initfsencoding() 1224 assert_python_ok('-c', 'pass', PYTHONPATH=cwd) 1225 1226 # Use -W to load warnings module at startup 1227 assert_python_ok('-c', 'pass', '-W', 'always', PYTHONPATH=cwd) 1228 1229 1230class FinalizationTest(unittest.TestCase): 1231 @support.requires_type_collecting 1232 def test_finalization(self): 1233 # Issue #19421: warnings.warn() should not crash 1234 # during Python finalization 1235 code = """ 1236import warnings 1237warn = warnings.warn 1238 1239class A: 1240 def __del__(self): 1241 warn("test") 1242 1243a=A() 1244 """ 1245 rc, out, err = assert_python_ok("-c", code) 1246 self.assertEqual(err.decode(), '<string>:7: UserWarning: test') 1247 1248 def test_late_resource_warning(self): 1249 # Issue #21925: Emitting a ResourceWarning late during the Python 1250 # shutdown must be logged. 1251 1252 expected = b"sys:1: ResourceWarning: unclosed file " 1253 1254 # don't import the warnings module 1255 # (_warnings will try to import it) 1256 code = "f = open(%a)" % __file__ 1257 rc, out, err = assert_python_ok("-Wd", "-c", code) 1258 self.assertTrue(err.startswith(expected), ascii(err)) 1259 1260 # import the warnings module 1261 code = "import warnings; f = open(%a)" % __file__ 1262 rc, out, err = assert_python_ok("-Wd", "-c", code) 1263 self.assertTrue(err.startswith(expected), ascii(err)) 1264 1265 1266def setUpModule(): 1267 py_warnings.onceregistry.clear() 1268 c_warnings.onceregistry.clear() 1269 1270tearDownModule = setUpModule 1271 1272if __name__ == "__main__": 1273 unittest.main() 1274