|
1 | 1 | import unittest |
2 | 2 | import sys |
| 3 | +import contextlib |
3 | 4 | from test.test_support import check_py3k_warnings, CleanImport, run_unittest |
4 | 5 | from test.script_helper import assert_python_ok |
5 | 6 | import warnings |
@@ -36,6 +37,24 @@ def reset_module_registry(module): |
36 | 37 |
|
37 | 38 | class TestPy3KWarnings(unittest.TestCase): |
38 | 39 |
|
| 40 | + @contextlib.contextmanager |
| 41 | + def check_py3k_warnings_with_fix(self): |
| 42 | + frame = sys._getframe(2) |
| 43 | + registry = frame.f_globals.get('__warningregistry__') |
| 44 | + if registry: |
| 45 | + registry.clear() |
| 46 | + with warnings.catch_warnings(record=True) as w: |
| 47 | + # PyErr_WarnExplicit_WithFix uses this runtime hook directly. |
| 48 | + showwarningwithfix = warnings.showwarningwithfix |
| 49 | + def record_warning_with_fix(*args, **kwargs): |
| 50 | + w.append(warnings.WarningMessageWithFix(*args, **kwargs)) |
| 51 | + warnings.showwarningwithfix = record_warning_with_fix |
| 52 | + warnings.simplefilter("always") |
| 53 | + try: |
| 54 | + yield test_support.WarningsRecorder(w) |
| 55 | + finally: |
| 56 | + warnings.showwarningwithfix = showwarningwithfix |
| 57 | + |
39 | 58 | def assertWarning(self, _, warning, expected_message): |
40 | 59 | self.assertEqual(str(warning.message), expected_message) |
41 | 60 |
|
@@ -425,30 +444,137 @@ def test_b32encode_warns(self): |
425 | 444 | expected = "base64.b32encode returns str in Python 2 (bytes in 3.x)" |
426 | 445 | base64.b32encode(b'test') |
427 | 446 | check_py3k_warnings(expected, UserWarning) |
428 | | - |
| 447 | + |
429 | 448 | def test_b16encode_warns(self): |
430 | 449 | expected = "base64.b16encode returns str in Python 2 (bytes in 3.x)" |
431 | 450 | base64.b16encode(b'test') |
432 | 451 | check_py3k_warnings(expected, UserWarning) |
433 | 452 |
|
434 | | - def assertExecLocalWritebackWarning(self, recorder, local_name): |
| 453 | + def assertMROWarning(self, recorder, expected_message): |
435 | 454 | self.assertEqual(len(recorder.warnings), 1) |
436 | 455 | msg = str(recorder.warnings[0].message) |
437 | | - self.assertTrue(msg.startswith( |
438 | | - "exec() modified local '%s'" % local_name)) |
| 456 | + self.assertEqual(msg, expected_message) |
439 | 457 | recorder.reset() |
| 458 | + |
| 459 | + def test_classic_mro_resolution_change_warning(self): |
| 460 | + with self.check_py3k_warnings_with_fix() as w: |
| 461 | + class A: |
| 462 | + def do_this(self): |
| 463 | + return "A" |
| 464 | + |
| 465 | + class B(A): |
| 466 | + pass |
| 467 | + |
| 468 | + class C(A): |
| 469 | + def do_this(self): |
| 470 | + return "C" |
| 471 | + |
| 472 | + class D(B, C): |
| 473 | + pass |
| 474 | + |
| 475 | + self.assertEqual(D().do_this(), "A") |
| 476 | + self.assertMROWarning( |
| 477 | + w, |
| 478 | + "classic multiple inheritance for class 'D' will resolve " |
| 479 | + "attribute 'do_this' from 'A' in 2.x but from 'C' in 3.x " |
| 480 | + "due to C3 MRO") |
| 481 | + |
| 482 | + def test_classic_mro_single_inheritance_no_warning(self): |
| 483 | + with self.check_py3k_warnings_with_fix() as w: |
| 484 | + class A: |
| 485 | + def only_here(self): |
| 486 | + return "A" |
| 487 | + |
| 488 | + class B(A): |
| 489 | + pass |
| 490 | + |
| 491 | + self.assertEqual(B().only_here(), "A") |
| 492 | + self.assertEqual(len(w.warnings), 0) |
| 493 | + |
| 494 | + def test_classic_mro_no_conflicting_name_no_warning(self): |
| 495 | + with self.check_py3k_warnings_with_fix() as w: |
| 496 | + class A: |
| 497 | + pass |
| 498 | + |
| 499 | + class B(A): |
| 500 | + def left(self): |
| 501 | + return "left" |
| 502 | + |
| 503 | + class C(A): |
| 504 | + def right(self): |
| 505 | + return "right" |
| 506 | + |
| 507 | + class D(B, C): |
| 508 | + pass |
| 509 | + |
| 510 | + self.assertEqual(D().left(), "left") |
| 511 | + self.assertEqual(D().right(), "right") |
| 512 | + self.assertEqual(len(w.warnings), 0) |
| 513 | + |
| 514 | + def test_classic_mro_provider_unchanged_no_warning(self): |
| 515 | + with self.check_py3k_warnings_with_fix() as w: |
| 516 | + class A: |
| 517 | + def only_here(self): |
| 518 | + return "A" |
| 519 | + |
| 520 | + class B(A): |
| 521 | + pass |
| 522 | + |
| 523 | + class C(A): |
| 524 | + pass |
440 | 525 |
|
441 | | - def test_exec_local_writeback_warning(self): |
442 | | - rc, out, err = assert_python_ok( |
443 | | - "-3", |
444 | | - "-c", |
445 | | - "def f(code):\n" |
446 | | - " b = 42\n" |
447 | | - " exec code\n" |
448 | | - " return b\n" |
449 | | - "f('b = 99')\n") |
450 | | - self.assertEqual(rc, 0) |
451 | | - self.assertIn("exec() modified local 'b' which is read later", err) |
| 526 | + class D(B, C): |
| 527 | + pass |
| 528 | + |
| 529 | + self.assertEqual(D().only_here(), "A") |
| 530 | + self.assertEqual(len(w.warnings), 0) |
| 531 | + |
| 532 | + def test_classic_mro_c3_conflict_warning(self): |
| 533 | + with self.check_py3k_warnings_with_fix() as w: |
| 534 | + class A: |
| 535 | + pass |
| 536 | + |
| 537 | + class B: |
| 538 | + pass |
| 539 | + |
| 540 | + class X(A, B): |
| 541 | + pass |
| 542 | + |
| 543 | + class Y(B, A): |
| 544 | + pass |
| 545 | + |
| 546 | + class Z(X, Y): |
| 547 | + pass |
| 548 | + |
| 549 | + self.assertMROWarning( |
| 550 | + w, |
| 551 | + "classic multiple inheritance hierarchy for class 'Z' has no " |
| 552 | + "consistent C3 MRO and will fail in 3.x") |
| 553 | + |
| 554 | + def test_classic_mro_bases_update_warning(self): |
| 555 | + with self.check_py3k_warnings_with_fix() as w: |
| 556 | + class A: |
| 557 | + def do_this(self): |
| 558 | + return "A" |
| 559 | + |
| 560 | + class B(A): |
| 561 | + pass |
| 562 | + |
| 563 | + class C(A): |
| 564 | + def do_this(self): |
| 565 | + return "C" |
| 566 | + |
| 567 | + class D(B): |
| 568 | + pass |
| 569 | + |
| 570 | + self.assertEqual(len(w.warnings), 0) |
| 571 | + D.__bases__ = (B, C) |
| 572 | + self.assertEqual(D().do_this(), "A") |
| 573 | + self.assertMROWarning( |
| 574 | + w, |
| 575 | + "classic multiple inheritance for class 'D' will resolve " |
| 576 | + "attribute 'do_this' from 'A' in 2.x but from 'C' in 3.x " |
| 577 | + "due to C3 MRO") |
452 | 578 |
|
453 | 579 |
|
454 | 580 | class TestStdlibRemovals(unittest.TestCase): |
|
0 commit comments