diff options
Diffstat (limited to 'Lib/test/test_descr.py')
-rw-r--r-- | Lib/test/test_descr.py | 160 |
1 files changed, 132 insertions, 28 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index ce9626c..d096390 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -21,6 +21,7 @@ class OperatorsTest(unittest.TestCase): 'add': '+', 'sub': '-', 'mul': '*', + 'matmul': '@', 'truediv': '/', 'floordiv': '//', 'divmod': 'divmod', @@ -1019,6 +1020,67 @@ order (MRO) for bases """ self.assertEqual(x.foo, 1) self.assertEqual(x.__dict__, {'foo': 1}) + def test_object_class_assignment_between_heaptypes_and_nonheaptypes(self): + class SubType(types.ModuleType): + a = 1 + + m = types.ModuleType("m") + self.assertTrue(m.__class__ is types.ModuleType) + self.assertFalse(hasattr(m, "a")) + + m.__class__ = SubType + self.assertTrue(m.__class__ is SubType) + self.assertTrue(hasattr(m, "a")) + + m.__class__ = types.ModuleType + self.assertTrue(m.__class__ is types.ModuleType) + self.assertFalse(hasattr(m, "a")) + + # Make sure that builtin immutable objects don't support __class__ + # assignment, because the object instances may be interned. + # We set __slots__ = () to ensure that the subclasses are + # memory-layout compatible, and thus otherwise reasonable candidates + # for __class__ assignment. + + # The following types have immutable instances, but are not + # subclassable and thus don't need to be checked: + # NoneType, bool + + class MyInt(int): + __slots__ = () + with self.assertRaises(TypeError): + (1).__class__ = MyInt + + class MyFloat(float): + __slots__ = () + with self.assertRaises(TypeError): + (1.0).__class__ = MyFloat + + class MyComplex(complex): + __slots__ = () + with self.assertRaises(TypeError): + (1 + 2j).__class__ = MyComplex + + class MyStr(str): + __slots__ = () + with self.assertRaises(TypeError): + "a".__class__ = MyStr + + class MyBytes(bytes): + __slots__ = () + with self.assertRaises(TypeError): + b"a".__class__ = MyBytes + + class MyTuple(tuple): + __slots__ = () + with self.assertRaises(TypeError): + ().__class__ = MyTuple + + class MyFrozenSet(frozenset): + __slots__ = () + with self.assertRaises(TypeError): + frozenset().__class__ = MyFrozenSet + def test_slots(self): # Testing __slots__... class C0(object): @@ -2005,7 +2067,7 @@ order (MRO) for bases """ self.assertIs(raw.fset, C.__dict__['setx']) self.assertIs(raw.fdel, C.__dict__['delx']) - for attr in "__doc__", "fget", "fset", "fdel": + for attr in "fget", "fset", "fdel": try: setattr(raw, attr, 42) except AttributeError as msg: @@ -2016,6 +2078,9 @@ order (MRO) for bases """ self.fail("expected AttributeError from trying to set readonly %r " "attr on a property" % attr) + raw.__doc__ = 42 + self.assertEqual(raw.__doc__, 42) + class D(object): __getitem__ = property(lambda s: 1/0) @@ -3003,8 +3068,6 @@ order (MRO) for bases """ cant(object(), list) cant(list(), object) class Int(int): __slots__ = [] - cant(2, Int) - cant(Int(), int) cant(True, int) cant(2, bool) o = object() @@ -3324,7 +3387,7 @@ order (MRO) for bases """ A.__call__ = A() try: A()() - except RuntimeError: + except RecursionError: pass else: self.fail("Recursion limit should have been reached for __call__()") @@ -4184,6 +4247,7 @@ order (MRO) for bases """ ('__add__', 'x + y', 'x += y'), ('__sub__', 'x - y', 'x -= y'), ('__mul__', 'x * y', 'x *= y'), + ('__matmul__', 'x @ y', 'x @= y'), ('__truediv__', 'x / y', 'x /= y'), ('__floordiv__', 'x // y', 'x //= y'), ('__mod__', 'x % y', 'x %= y'), @@ -4329,8 +4393,8 @@ order (MRO) for bases """ pass Foo.__repr__ = Foo.__str__ foo = Foo() - self.assertRaises(RuntimeError, str, foo) - self.assertRaises(RuntimeError, repr, foo) + self.assertRaises(RecursionError, str, foo) + self.assertRaises(RecursionError, repr, foo) def test_mixing_slot_wrappers(self): class X(dict): @@ -4445,6 +4509,61 @@ order (MRO) for bases """ self.assertIn("__dict__", Base.__dict__) self.assertNotIn("__dict__", Sub.__dict__) + def test_bound_method_repr(self): + class Foo: + def method(self): + pass + self.assertRegex(repr(Foo().method), + r"<bound method .*Foo\.method of <.*Foo object at .*>>") + + + class Base: + def method(self): + pass + class Derived1(Base): + pass + class Derived2(Base): + def method(self): + pass + base = Base() + derived1 = Derived1() + derived2 = Derived2() + super_d2 = super(Derived2, derived2) + self.assertRegex(repr(base.method), + r"<bound method .*Base\.method of <.*Base object at .*>>") + self.assertRegex(repr(derived1.method), + r"<bound method .*Base\.method of <.*Derived1 object at .*>>") + self.assertRegex(repr(derived2.method), + r"<bound method .*Derived2\.method of <.*Derived2 object at .*>>") + self.assertRegex(repr(super_d2.method), + r"<bound method .*Base\.method of <.*Derived2 object at .*>>") + + class Foo: + @classmethod + def method(cls): + pass + foo = Foo() + self.assertRegex(repr(foo.method), # access via instance + r"<bound method .*Foo\.method of <class '.*Foo'>>") + self.assertRegex(repr(Foo.method), # access via the class + r"<bound method .*Foo\.method of <class '.*Foo'>>") + + + class MyCallable: + def __call__(self, arg): + pass + func = MyCallable() # func has no __name__ or __qualname__ attributes + instance = object() + method = types.MethodType(func, instance) + self.assertRegex(repr(method), + r"<bound method \? of <object object at .*>>") + func.__name__ = "name" + self.assertRegex(repr(method), + r"<bound method name of <object object at .*>>") + func.__qualname__ = "qualname" + self.assertRegex(repr(method), + r"<bound method qualname of <object object at .*>>") + class DictProxyTests(unittest.TestCase): def setUp(self): @@ -4559,26 +4678,15 @@ class PicklingTests(unittest.TestCase): def _check_reduce(self, proto, obj, args=(), kwargs={}, state=None, listitems=None, dictitems=None): - if proto >= 4: + if proto >= 2: reduce_value = obj.__reduce_ex__(proto) - self.assertEqual(reduce_value[:3], - (copyreg.__newobj_ex__, - (type(obj), args, kwargs), - state)) - if listitems is not None: - self.assertListEqual(list(reduce_value[3]), listitems) - else: - self.assertIsNone(reduce_value[3]) - if dictitems is not None: - self.assertDictEqual(dict(reduce_value[4]), dictitems) + if kwargs: + self.assertEqual(reduce_value[0], copyreg.__newobj_ex__) + self.assertEqual(reduce_value[1], (type(obj), args, kwargs)) else: - self.assertIsNone(reduce_value[4]) - elif proto >= 2: - reduce_value = obj.__reduce_ex__(proto) - self.assertEqual(reduce_value[:3], - (copyreg.__newobj__, - (type(obj),) + args, - state)) + self.assertEqual(reduce_value[0], copyreg.__newobj__) + self.assertEqual(reduce_value[1], (type(obj),) + args) + self.assertEqual(reduce_value[2], state) if listitems is not None: self.assertListEqual(list(reduce_value[3]), listitems) else: @@ -4973,10 +5081,6 @@ class PicklingTests(unittest.TestCase): with self.subTest(cls=cls): kwargs = getattr(cls, 'KWARGS', {}) obj = cls(*cls.ARGS, **kwargs) - # XXX: We need to modify the copy module to support PEP 3154's - # reduce protocol 4. - if hasattr(cls, '__getnewargs_ex__'): - continue objcopy = deepcopy(obj) self._assert_is_copy(obj, objcopy) # For test classes that supports this, make sure we didn't go |