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