Skip to content

Commit cb6e349

Browse files
author
Eddy Xu
committed
add warning to mro inhereitance class attribute issues
1 parent b3587e1 commit cb6e349

2 files changed

Lines changed: 627 additions & 2 deletions

File tree

Lib/test/test_py3kwarn.py

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import unittest
22
import sys
3+
import contextlib
34
from test.test_support import check_py3k_warnings, CleanImport, run_unittest
45
import warnings
56
import base64
@@ -35,6 +36,24 @@ def reset_module_registry(module):
3536

3637
class TestPy3KWarnings(unittest.TestCase):
3738

39+
@contextlib.contextmanager
40+
def check_py3k_warnings_with_fix(self):
41+
frame = sys._getframe(2)
42+
registry = frame.f_globals.get('__warningregistry__')
43+
if registry:
44+
registry.clear()
45+
with warnings.catch_warnings(record=True) as w:
46+
# PyErr_WarnExplicit_WithFix uses this runtime hook directly.
47+
showwarningwithfix = warnings.showwarningwithfix
48+
def record_warning_with_fix(*args, **kwargs):
49+
w.append(warnings.WarningMessageWithFix(*args, **kwargs))
50+
warnings.showwarningwithfix = record_warning_with_fix
51+
warnings.simplefilter("always")
52+
try:
53+
yield test_support.WarningsRecorder(w)
54+
finally:
55+
warnings.showwarningwithfix = showwarningwithfix
56+
3857
def assertWarning(self, _, warning, expected_message):
3958
self.assertEqual(str(warning.message), expected_message)
4059

@@ -424,12 +443,138 @@ def test_b32encode_warns(self):
424443
expected = "base64.b32encode returns str in Python 2 (bytes in 3.x)"
425444
base64.b32encode(b'test')
426445
check_py3k_warnings(expected, UserWarning)
427-
446+
428447
def test_b16encode_warns(self):
429448
expected = "base64.b16encode returns str in Python 2 (bytes in 3.x)"
430449
base64.b16encode(b'test')
431450
check_py3k_warnings(expected, UserWarning)
432451

452+
def assertMROWarning(self, recorder, expected_message):
453+
self.assertEqual(len(recorder.warnings), 1)
454+
msg = str(recorder.warnings[0].message)
455+
self.assertEqual(msg, expected_message)
456+
recorder.reset()
457+
458+
def test_classic_mro_resolution_change_warning(self):
459+
with self.check_py3k_warnings_with_fix() as w:
460+
class A:
461+
def do_this(self):
462+
return "A"
463+
464+
class B(A):
465+
pass
466+
467+
class C(A):
468+
def do_this(self):
469+
return "C"
470+
471+
class D(B, C):
472+
pass
473+
474+
self.assertEqual(D().do_this(), "A")
475+
self.assertMROWarning(
476+
w,
477+
"classic multiple inheritance for class 'D' will resolve "
478+
"attribute 'do_this' from 'A' in 2.x but from 'C' in 3.x "
479+
"due to C3 MRO")
480+
481+
def test_classic_mro_single_inheritance_no_warning(self):
482+
with self.check_py3k_warnings_with_fix() as w:
483+
class A:
484+
def only_here(self):
485+
return "A"
486+
487+
class B(A):
488+
pass
489+
490+
self.assertEqual(B().only_here(), "A")
491+
self.assertEqual(len(w.warnings), 0)
492+
493+
def test_classic_mro_no_conflicting_name_no_warning(self):
494+
with self.check_py3k_warnings_with_fix() as w:
495+
class A:
496+
pass
497+
498+
class B(A):
499+
def left(self):
500+
return "left"
501+
502+
class C(A):
503+
def right(self):
504+
return "right"
505+
506+
class D(B, C):
507+
pass
508+
509+
self.assertEqual(D().left(), "left")
510+
self.assertEqual(D().right(), "right")
511+
self.assertEqual(len(w.warnings), 0)
512+
513+
def test_classic_mro_provider_unchanged_no_warning(self):
514+
with self.check_py3k_warnings_with_fix() as w:
515+
class A:
516+
def only_here(self):
517+
return "A"
518+
519+
class B(A):
520+
pass
521+
522+
class C(A):
523+
pass
524+
525+
class D(B, C):
526+
pass
527+
528+
self.assertEqual(D().only_here(), "A")
529+
self.assertEqual(len(w.warnings), 0)
530+
531+
def test_classic_mro_c3_conflict_warning(self):
532+
with self.check_py3k_warnings_with_fix() as w:
533+
class A:
534+
pass
535+
536+
class B:
537+
pass
538+
539+
class X(A, B):
540+
pass
541+
542+
class Y(B, A):
543+
pass
544+
545+
class Z(X, Y):
546+
pass
547+
548+
self.assertMROWarning(
549+
w,
550+
"classic multiple inheritance hierarchy for class 'Z' has no "
551+
"consistent C3 MRO and will fail in 3.x")
552+
553+
def test_classic_mro_bases_update_warning(self):
554+
with self.check_py3k_warnings_with_fix() as w:
555+
class A:
556+
def do_this(self):
557+
return "A"
558+
559+
class B(A):
560+
pass
561+
562+
class C(A):
563+
def do_this(self):
564+
return "C"
565+
566+
class D(B):
567+
pass
568+
569+
self.assertEqual(len(w.warnings), 0)
570+
D.__bases__ = (B, C)
571+
self.assertEqual(D().do_this(), "A")
572+
self.assertMROWarning(
573+
w,
574+
"classic multiple inheritance for class 'D' will resolve "
575+
"attribute 'do_this' from 'A' in 2.x but from 'C' in 3.x "
576+
"due to C3 MRO")
577+
433578

434579
class TestStdlibRemovals(unittest.TestCase):
435580

0 commit comments

Comments
 (0)