mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Cover all the Mapping Protocol, almost all the Sequence Protocol (except PySequence_Fast) and a part of the Object Protocol. Move existing tests to Lib/test/test_capi/test_abstract.py and Modules/_testcapi/abstract.c. Add also tests for PyDict C API.
		
			
				
	
	
		
			776 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			776 lines
		
	
	
	
		
			21 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.object_hasattrstring(a, b"attr"), 1)
 | 
						|
        self.assertEqual(_testcapi.object_hasattrstring(a, b"noattr"), 0)
 | 
						|
        self.assertIsNone(sys.exception())
 | 
						|
 | 
						|
    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',)
 | 
						|
        class C:
 | 
						|
            __slots__ = ("y",)
 | 
						|
 | 
						|
            def __setattr__(self, name, value) -> None:
 | 
						|
                if name == "z":
 | 
						|
                    super().__setattr__("y", 1)
 | 
						|
                else:
 | 
						|
                    super().__setattr__(name, value)
 | 
						|
 | 
						|
        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,
 | 
						|
            "'B' object has no attribute 'x' and no __dict__ for setting new attributes"
 | 
						|
        ):
 | 
						|
            B().x = 0
 | 
						|
        with self.assertRaisesRegex(
 | 
						|
            AttributeError,
 | 
						|
            "'C' object has no attribute 'x'"
 | 
						|
        ):
 | 
						|
            C().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'}))
 | 
						|
 | 
						|
    def testClassCallRecursionLimit(self):
 | 
						|
        class C:
 | 
						|
            def __init__(self):
 | 
						|
                self.c = C()
 | 
						|
 | 
						|
        with self.assertRaises(RecursionError):
 | 
						|
            C()
 | 
						|
 | 
						|
        def add_one_level():
 | 
						|
            #Each call to C() consumes 2 levels, so offset by 1.
 | 
						|
            C()
 | 
						|
 | 
						|
        with self.assertRaises(RecursionError):
 | 
						|
            add_one_level()
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    unittest.main()
 |