mirror of
				https://github.com/python/cpython.git
				synced 2025-10-25 18:54:53 +00:00 
			
		
		
		
	 9302e331c7
			
		
	
	
		9302e331c7
		
			
		
	
	
	
	
		
			
			* gh-94808: Add test for HasAttrString * Harmonize to Python C code style guidelines * Add check to verify no exception thrown
		
			
				
	
	
		
			745 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			745 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| "Test the functionality of Python classes implementing operators."
 | |
| 
 | |
| import unittest
 | |
| 
 | |
| 
 | |
| testmeths = [
 | |
| 
 | |
| # Binary operations
 | |
|     "add",
 | |
|     "radd",
 | |
|     "sub",
 | |
|     "rsub",
 | |
|     "mul",
 | |
|     "rmul",
 | |
|     "matmul",
 | |
|     "rmatmul",
 | |
|     "truediv",
 | |
|     "rtruediv",
 | |
|     "floordiv",
 | |
|     "rfloordiv",
 | |
|     "mod",
 | |
|     "rmod",
 | |
|     "divmod",
 | |
|     "rdivmod",
 | |
|     "pow",
 | |
|     "rpow",
 | |
|     "rshift",
 | |
|     "rrshift",
 | |
|     "lshift",
 | |
|     "rlshift",
 | |
|     "and",
 | |
|     "rand",
 | |
|     "or",
 | |
|     "ror",
 | |
|     "xor",
 | |
|     "rxor",
 | |
| 
 | |
| # List/dict operations
 | |
|     "contains",
 | |
|     "getitem",
 | |
|     "setitem",
 | |
|     "delitem",
 | |
| 
 | |
| # Unary operations
 | |
|     "neg",
 | |
|     "pos",
 | |
|     "abs",
 | |
| 
 | |
| # generic operations
 | |
|     "init",
 | |
|     ]
 | |
| 
 | |
| # These need to return something other than None
 | |
| #    "hash",
 | |
| #    "str",
 | |
| #    "repr",
 | |
| #    "int",
 | |
| #    "float",
 | |
| 
 | |
| # These are separate because they can influence the test of other methods.
 | |
| #    "getattr",
 | |
| #    "setattr",
 | |
| #    "delattr",
 | |
| 
 | |
| callLst = []
 | |
| def trackCall(f):
 | |
|     def track(*args, **kwargs):
 | |
|         callLst.append((f.__name__, args))
 | |
|         return f(*args, **kwargs)
 | |
|     return track
 | |
| 
 | |
| statictests = """
 | |
| @trackCall
 | |
| def __hash__(self, *args):
 | |
|     return hash(id(self))
 | |
| 
 | |
| @trackCall
 | |
| def __str__(self, *args):
 | |
|     return "AllTests"
 | |
| 
 | |
| @trackCall
 | |
| def __repr__(self, *args):
 | |
|     return "AllTests"
 | |
| 
 | |
| @trackCall
 | |
| def __int__(self, *args):
 | |
|     return 1
 | |
| 
 | |
| @trackCall
 | |
| def __index__(self, *args):
 | |
|     return 1
 | |
| 
 | |
| @trackCall
 | |
| def __float__(self, *args):
 | |
|     return 1.0
 | |
| 
 | |
| @trackCall
 | |
| def __eq__(self, *args):
 | |
|     return True
 | |
| 
 | |
| @trackCall
 | |
| def __ne__(self, *args):
 | |
|     return False
 | |
| 
 | |
| @trackCall
 | |
| def __lt__(self, *args):
 | |
|     return False
 | |
| 
 | |
| @trackCall
 | |
| def __le__(self, *args):
 | |
|     return True
 | |
| 
 | |
| @trackCall
 | |
| def __gt__(self, *args):
 | |
|     return False
 | |
| 
 | |
| @trackCall
 | |
| def __ge__(self, *args):
 | |
|     return True
 | |
| """
 | |
| 
 | |
| # Synthesize all the other AllTests methods from the names in testmeths.
 | |
| 
 | |
| method_template = """\
 | |
| @trackCall
 | |
| def __%s__(self, *args):
 | |
|     pass
 | |
| """
 | |
| 
 | |
| d = {}
 | |
| exec(statictests, globals(), d)
 | |
| for method in testmeths:
 | |
|     exec(method_template % method, globals(), d)
 | |
| AllTests = type("AllTests", (object,), d)
 | |
| del d, statictests, method, method_template
 | |
| 
 | |
| class ClassTests(unittest.TestCase):
 | |
|     def setUp(self):
 | |
|         callLst[:] = []
 | |
| 
 | |
|     def assertCallStack(self, expected_calls):
 | |
|         actualCallList = callLst[:]  # need to copy because the comparison below will add
 | |
|                                      # additional calls to callLst
 | |
|         if expected_calls != actualCallList:
 | |
|             self.fail("Expected call list:\n  %s\ndoes not match actual call list\n  %s" %
 | |
|                       (expected_calls, actualCallList))
 | |
| 
 | |
|     def testInit(self):
 | |
|         foo = AllTests()
 | |
|         self.assertCallStack([("__init__", (foo,))])
 | |
| 
 | |
|     def testBinaryOps(self):
 | |
|         testme = AllTests()
 | |
|         # Binary operations
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme + 1
 | |
|         self.assertCallStack([("__add__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 + testme
 | |
|         self.assertCallStack([("__radd__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme - 1
 | |
|         self.assertCallStack([("__sub__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 - testme
 | |
|         self.assertCallStack([("__rsub__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme * 1
 | |
|         self.assertCallStack([("__mul__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 * testme
 | |
|         self.assertCallStack([("__rmul__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme @ 1
 | |
|         self.assertCallStack([("__matmul__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 @ testme
 | |
|         self.assertCallStack([("__rmatmul__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme / 1
 | |
|         self.assertCallStack([("__truediv__", (testme, 1))])
 | |
| 
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 / testme
 | |
|         self.assertCallStack([("__rtruediv__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme // 1
 | |
|         self.assertCallStack([("__floordiv__", (testme, 1))])
 | |
| 
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 // testme
 | |
|         self.assertCallStack([("__rfloordiv__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme % 1
 | |
|         self.assertCallStack([("__mod__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 % testme
 | |
|         self.assertCallStack([("__rmod__", (testme, 1))])
 | |
| 
 | |
| 
 | |
|         callLst[:] = []
 | |
|         divmod(testme,1)
 | |
|         self.assertCallStack([("__divmod__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         divmod(1, testme)
 | |
|         self.assertCallStack([("__rdivmod__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme ** 1
 | |
|         self.assertCallStack([("__pow__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 ** testme
 | |
|         self.assertCallStack([("__rpow__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme >> 1
 | |
|         self.assertCallStack([("__rshift__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 >> testme
 | |
|         self.assertCallStack([("__rrshift__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme << 1
 | |
|         self.assertCallStack([("__lshift__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 << testme
 | |
|         self.assertCallStack([("__rlshift__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme & 1
 | |
|         self.assertCallStack([("__and__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 & testme
 | |
|         self.assertCallStack([("__rand__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme | 1
 | |
|         self.assertCallStack([("__or__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 | testme
 | |
|         self.assertCallStack([("__ror__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme ^ 1
 | |
|         self.assertCallStack([("__xor__", (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 ^ testme
 | |
|         self.assertCallStack([("__rxor__", (testme, 1))])
 | |
| 
 | |
|     def testListAndDictOps(self):
 | |
|         testme = AllTests()
 | |
| 
 | |
|         # List/dict operations
 | |
| 
 | |
|         class Empty: pass
 | |
| 
 | |
|         try:
 | |
|             1 in Empty()
 | |
|             self.fail('failed, should have raised TypeError')
 | |
|         except TypeError:
 | |
|             pass
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 in testme
 | |
|         self.assertCallStack([('__contains__', (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme[1]
 | |
|         self.assertCallStack([('__getitem__', (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme[1] = 1
 | |
|         self.assertCallStack([('__setitem__', (testme, 1, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         del testme[1]
 | |
|         self.assertCallStack([('__delitem__', (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme[:42]
 | |
|         self.assertCallStack([('__getitem__', (testme, slice(None, 42)))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme[:42] = "The Answer"
 | |
|         self.assertCallStack([('__setitem__', (testme, slice(None, 42),
 | |
|                                                "The Answer"))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         del testme[:42]
 | |
|         self.assertCallStack([('__delitem__', (testme, slice(None, 42)))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme[2:1024:10]
 | |
|         self.assertCallStack([('__getitem__', (testme, slice(2, 1024, 10)))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme[2:1024:10] = "A lot"
 | |
|         self.assertCallStack([('__setitem__', (testme, slice(2, 1024, 10),
 | |
|                                                                     "A lot"))])
 | |
|         callLst[:] = []
 | |
|         del testme[2:1024:10]
 | |
|         self.assertCallStack([('__delitem__', (testme, slice(2, 1024, 10)))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme[:42, ..., :24:, 24, 100]
 | |
|         self.assertCallStack([('__getitem__', (testme, (slice(None, 42, None),
 | |
|                                                         Ellipsis,
 | |
|                                                         slice(None, 24, None),
 | |
|                                                         24, 100)))])
 | |
|         callLst[:] = []
 | |
|         testme[:42, ..., :24:, 24, 100] = "Strange"
 | |
|         self.assertCallStack([('__setitem__', (testme, (slice(None, 42, None),
 | |
|                                                         Ellipsis,
 | |
|                                                         slice(None, 24, None),
 | |
|                                                         24, 100), "Strange"))])
 | |
|         callLst[:] = []
 | |
|         del testme[:42, ..., :24:, 24, 100]
 | |
|         self.assertCallStack([('__delitem__', (testme, (slice(None, 42, None),
 | |
|                                                         Ellipsis,
 | |
|                                                         slice(None, 24, None),
 | |
|                                                         24, 100)))])
 | |
| 
 | |
|     def testUnaryOps(self):
 | |
|         testme = AllTests()
 | |
| 
 | |
|         callLst[:] = []
 | |
|         -testme
 | |
|         self.assertCallStack([('__neg__', (testme,))])
 | |
|         callLst[:] = []
 | |
|         +testme
 | |
|         self.assertCallStack([('__pos__', (testme,))])
 | |
|         callLst[:] = []
 | |
|         abs(testme)
 | |
|         self.assertCallStack([('__abs__', (testme,))])
 | |
|         callLst[:] = []
 | |
|         int(testme)
 | |
|         self.assertCallStack([('__int__', (testme,))])
 | |
|         callLst[:] = []
 | |
|         float(testme)
 | |
|         self.assertCallStack([('__float__', (testme,))])
 | |
|         callLst[:] = []
 | |
|         oct(testme)
 | |
|         self.assertCallStack([('__index__', (testme,))])
 | |
|         callLst[:] = []
 | |
|         hex(testme)
 | |
|         self.assertCallStack([('__index__', (testme,))])
 | |
| 
 | |
| 
 | |
|     def testMisc(self):
 | |
|         testme = AllTests()
 | |
| 
 | |
|         callLst[:] = []
 | |
|         hash(testme)
 | |
|         self.assertCallStack([('__hash__', (testme,))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         repr(testme)
 | |
|         self.assertCallStack([('__repr__', (testme,))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         str(testme)
 | |
|         self.assertCallStack([('__str__', (testme,))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme == 1
 | |
|         self.assertCallStack([('__eq__', (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme < 1
 | |
|         self.assertCallStack([('__lt__', (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme > 1
 | |
|         self.assertCallStack([('__gt__', (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme != 1
 | |
|         self.assertCallStack([('__ne__', (testme, 1))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 == testme
 | |
|         self.assertCallStack([('__eq__', (1, testme))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 < testme
 | |
|         self.assertCallStack([('__gt__', (1, testme))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 > testme
 | |
|         self.assertCallStack([('__lt__', (1, testme))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         1 != testme
 | |
|         self.assertCallStack([('__ne__', (1, testme))])
 | |
| 
 | |
| 
 | |
|     def testGetSetAndDel(self):
 | |
|         # Interfering tests
 | |
|         class ExtraTests(AllTests):
 | |
|             @trackCall
 | |
|             def __getattr__(self, *args):
 | |
|                 return "SomeVal"
 | |
| 
 | |
|             @trackCall
 | |
|             def __setattr__(self, *args):
 | |
|                 pass
 | |
| 
 | |
|             @trackCall
 | |
|             def __delattr__(self, *args):
 | |
|                 pass
 | |
| 
 | |
|         testme = ExtraTests()
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme.spam
 | |
|         self.assertCallStack([('__getattr__', (testme, "spam"))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         testme.eggs = "spam, spam, spam and ham"
 | |
|         self.assertCallStack([('__setattr__', (testme, "eggs",
 | |
|                                                "spam, spam, spam and ham"))])
 | |
| 
 | |
|         callLst[:] = []
 | |
|         del testme.cardinal
 | |
|         self.assertCallStack([('__delattr__', (testme, "cardinal"))])
 | |
| 
 | |
|     def testHasAttrString(self):
 | |
|         import sys
 | |
|         from test.support import import_helper
 | |
|         _testcapi = import_helper.import_module('_testcapi')
 | |
| 
 | |
|         class A:
 | |
|             def __init__(self):
 | |
|                 self.attr = 1
 | |
| 
 | |
|         a = A()
 | |
|         self.assertEqual(_testcapi.hasattr_string(a, "attr"), True)
 | |
|         self.assertEqual(_testcapi.hasattr_string(a, "noattr"), False)
 | |
|         self.assertEqual(sys.exc_info(), (None, None, None))
 | |
| 
 | |
|     def testDel(self):
 | |
|         x = []
 | |
| 
 | |
|         class DelTest:
 | |
|             def __del__(self):
 | |
|                 x.append("crab people, crab people")
 | |
|         testme = DelTest()
 | |
|         del testme
 | |
|         import gc
 | |
|         gc.collect()
 | |
|         self.assertEqual(["crab people, crab people"], x)
 | |
| 
 | |
|     def testBadTypeReturned(self):
 | |
|         # return values of some method are type-checked
 | |
|         class BadTypeClass:
 | |
|             def __int__(self):
 | |
|                 return None
 | |
|             __float__ = __int__
 | |
|             __complex__ = __int__
 | |
|             __str__ = __int__
 | |
|             __repr__ = __int__
 | |
|             __bytes__ = __int__
 | |
|             __bool__ = __int__
 | |
|             __index__ = __int__
 | |
|         def index(x):
 | |
|             return [][x]
 | |
| 
 | |
|         for f in [float, complex, str, repr, bytes, bin, oct, hex, bool, index]:
 | |
|             self.assertRaises(TypeError, f, BadTypeClass())
 | |
| 
 | |
|     def testHashStuff(self):
 | |
|         # Test correct errors from hash() on objects with comparisons but
 | |
|         #  no __hash__
 | |
| 
 | |
|         class C0:
 | |
|             pass
 | |
| 
 | |
|         hash(C0()) # This should work; the next two should raise TypeError
 | |
| 
 | |
|         class C2:
 | |
|             def __eq__(self, other): return 1
 | |
| 
 | |
|         self.assertRaises(TypeError, hash, C2())
 | |
| 
 | |
| 
 | |
|     def testSFBug532646(self):
 | |
|         # Test for SF bug 532646
 | |
| 
 | |
|         class A:
 | |
|             pass
 | |
|         A.__call__ = A()
 | |
|         a = A()
 | |
| 
 | |
|         try:
 | |
|             a() # This should not segfault
 | |
|         except RecursionError:
 | |
|             pass
 | |
|         else:
 | |
|             self.fail("Failed to raise RecursionError")
 | |
| 
 | |
|     def testForExceptionsRaisedInInstanceGetattr2(self):
 | |
|         # Tests for exceptions raised in instance_getattr2().
 | |
| 
 | |
|         def booh(self):
 | |
|             raise AttributeError("booh")
 | |
| 
 | |
|         class A:
 | |
|             a = property(booh)
 | |
|         try:
 | |
|             A().a # Raised AttributeError: A instance has no attribute 'a'
 | |
|         except AttributeError as x:
 | |
|             if str(x) != "booh":
 | |
|                 self.fail("attribute error for A().a got masked: %s" % x)
 | |
| 
 | |
|         class E:
 | |
|             __eq__ = property(booh)
 | |
|         E() == E() # In debug mode, caused a C-level assert() to fail
 | |
| 
 | |
|         class I:
 | |
|             __init__ = property(booh)
 | |
|         try:
 | |
|             # In debug mode, printed XXX undetected error and
 | |
|             #  raises AttributeError
 | |
|             I()
 | |
|         except AttributeError:
 | |
|             pass
 | |
|         else:
 | |
|             self.fail("attribute error for I.__init__ got masked")
 | |
| 
 | |
|     def assertNotOrderable(self, a, b):
 | |
|         with self.assertRaises(TypeError):
 | |
|             a < b
 | |
|         with self.assertRaises(TypeError):
 | |
|             a > b
 | |
|         with self.assertRaises(TypeError):
 | |
|             a <= b
 | |
|         with self.assertRaises(TypeError):
 | |
|             a >= b
 | |
| 
 | |
|     def testHashComparisonOfMethods(self):
 | |
|         # Test comparison and hash of methods
 | |
|         class A:
 | |
|             def __init__(self, x):
 | |
|                 self.x = x
 | |
|             def f(self):
 | |
|                 pass
 | |
|             def g(self):
 | |
|                 pass
 | |
|             def __eq__(self, other):
 | |
|                 return True
 | |
|             def __hash__(self):
 | |
|                 raise TypeError
 | |
|         class B(A):
 | |
|             pass
 | |
| 
 | |
|         a1 = A(1)
 | |
|         a2 = A(1)
 | |
|         self.assertTrue(a1.f == a1.f)
 | |
|         self.assertFalse(a1.f != a1.f)
 | |
|         self.assertFalse(a1.f == a2.f)
 | |
|         self.assertTrue(a1.f != a2.f)
 | |
|         self.assertFalse(a1.f == a1.g)
 | |
|         self.assertTrue(a1.f != a1.g)
 | |
|         self.assertNotOrderable(a1.f, a1.f)
 | |
|         self.assertEqual(hash(a1.f), hash(a1.f))
 | |
| 
 | |
|         self.assertFalse(A.f == a1.f)
 | |
|         self.assertTrue(A.f != a1.f)
 | |
|         self.assertFalse(A.f == A.g)
 | |
|         self.assertTrue(A.f != A.g)
 | |
|         self.assertTrue(B.f == A.f)
 | |
|         self.assertFalse(B.f != A.f)
 | |
|         self.assertNotOrderable(A.f, A.f)
 | |
|         self.assertEqual(hash(B.f), hash(A.f))
 | |
| 
 | |
|         # the following triggers a SystemError in 2.4
 | |
|         a = A(hash(A.f)^(-1))
 | |
|         hash(a.f)
 | |
| 
 | |
|     def testSetattrWrapperNameIntern(self):
 | |
|         # Issue #25794: __setattr__ should intern the attribute name
 | |
|         class A:
 | |
|             pass
 | |
| 
 | |
|         def add(self, other):
 | |
|             return 'summa'
 | |
| 
 | |
|         name = str(b'__add__', 'ascii')  # shouldn't be optimized
 | |
|         self.assertIsNot(name, '__add__')  # not interned
 | |
|         type.__setattr__(A, name, add)
 | |
|         self.assertEqual(A() + 1, 'summa')
 | |
| 
 | |
|         name2 = str(b'__add__', 'ascii')
 | |
|         self.assertIsNot(name2, '__add__')
 | |
|         self.assertIsNot(name2, name)
 | |
|         type.__delattr__(A, name2)
 | |
|         with self.assertRaises(TypeError):
 | |
|             A() + 1
 | |
| 
 | |
|     def testSetattrNonStringName(self):
 | |
|         class A:
 | |
|             pass
 | |
| 
 | |
|         with self.assertRaises(TypeError):
 | |
|             type.__setattr__(A, b'x', None)
 | |
| 
 | |
|     def testTypeAttributeAccessErrorMessages(self):
 | |
|         class A:
 | |
|             pass
 | |
| 
 | |
|         error_msg = "type object 'A' has no attribute 'x'"
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             A.x
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             del A.x
 | |
| 
 | |
|     def testObjectAttributeAccessErrorMessages(self):
 | |
|         class A:
 | |
|             pass
 | |
|         class B:
 | |
|             y = 0
 | |
|             __slots__ = ('z',)
 | |
| 
 | |
|         error_msg = "'A' object has no attribute 'x'"
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             A().x
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             del A().x
 | |
| 
 | |
|         error_msg = "'B' object has no attribute 'x'"
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             B().x
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             del B().x
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             B().x = 0
 | |
| 
 | |
|         error_msg = "'B' object attribute 'y' is read-only"
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             del B().y
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             B().y = 0
 | |
| 
 | |
|         error_msg = 'z'
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             B().z
 | |
|         with self.assertRaisesRegex(AttributeError, error_msg):
 | |
|             del B().z
 | |
| 
 | |
|     def testConstructorErrorMessages(self):
 | |
|         # bpo-31506: Improves the error message logic for object_new & object_init
 | |
| 
 | |
|         # Class without any method overrides
 | |
|         class C:
 | |
|             pass
 | |
| 
 | |
|         error_msg = r'C.__init__\(\) takes exactly one argument \(the instance to initialize\)'
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, r'C\(\) takes no arguments'):
 | |
|             C(42)
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, r'C\(\) takes no arguments'):
 | |
|             C.__new__(C, 42)
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, error_msg):
 | |
|             C().__init__(42)
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, r'C\(\) takes no arguments'):
 | |
|             object.__new__(C, 42)
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, error_msg):
 | |
|             object.__init__(C(), 42)
 | |
| 
 | |
|         # Class with both `__init__` & `__new__` method overridden
 | |
|         class D:
 | |
|             def __new__(cls, *args, **kwargs):
 | |
|                 super().__new__(cls, *args, **kwargs)
 | |
|             def __init__(self, *args, **kwargs):
 | |
|                 super().__init__(*args, **kwargs)
 | |
| 
 | |
|         error_msg =  r'object.__new__\(\) takes exactly one argument \(the type to instantiate\)'
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, error_msg):
 | |
|             D(42)
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, error_msg):
 | |
|             D.__new__(D, 42)
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, error_msg):
 | |
|             object.__new__(D, 42)
 | |
| 
 | |
|         # Class that only overrides __init__
 | |
|         class E:
 | |
|             def __init__(self, *args, **kwargs):
 | |
|                 super().__init__(*args, **kwargs)
 | |
| 
 | |
|         error_msg = r'object.__init__\(\) takes exactly one argument \(the instance to initialize\)'
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, error_msg):
 | |
|             E().__init__(42)
 | |
| 
 | |
|         with self.assertRaisesRegex(TypeError, error_msg):
 | |
|             object.__init__(E(), 42)
 | |
| 
 | |
|     def testClassWithExtCall(self):
 | |
|         class Meta(int):
 | |
|             def __init__(*args, **kwargs):
 | |
|                 pass
 | |
| 
 | |
|             def __new__(cls, name, bases, attrs, **kwargs):
 | |
|                 return bases, kwargs
 | |
| 
 | |
|         d = {'metaclass': Meta}
 | |
| 
 | |
|         class A(**d): pass
 | |
|         self.assertEqual(A, ((), {}))
 | |
|         class A(0, 1, 2, 3, 4, 5, 6, 7, **d): pass
 | |
|         self.assertEqual(A, (tuple(range(8)), {}))
 | |
|         class A(0, *range(1, 8), **d, foo='bar'): pass
 | |
|         self.assertEqual(A, (tuple(range(8)), {'foo': 'bar'}))
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     unittest.main()
 |