| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731 |
- "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 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()
|