changeset: 101304:0af15b8ef3b2 branch: 3.5 parent: 101300:d60040b3bb8c user: Serhiy Storchaka date: Thu May 12 10:37:58 2016 +0300 files: Lib/test/test_bool.py Lib/test/test_enum.py Lib/test/test_float.py Lib/test/test_long.py Misc/NEWS Objects/longobject.c description: Issue #23640: int.from_bytes() no longer bypasses constructors for subclasses. diff -r d60040b3bb8c -r 0af15b8ef3b2 Lib/test/test_bool.py --- a/Lib/test/test_bool.py Wed May 11 22:25:05 2016 +0300 +++ b/Lib/test/test_bool.py Thu May 12 10:37:58 2016 +0300 @@ -314,6 +314,10 @@ return -1 self.assertRaises(ValueError, bool, Eggs()) + def test_from_bytes(self): + self.assertIs(bool.from_bytes(b'\x00'*8, 'big'), False) + self.assertIs(bool.from_bytes(b'abcd', 'little'), True) + def test_sane_len(self): # this test just tests our assumptions about __len__ # this will start failing if __len__ changes assertions diff -r d60040b3bb8c -r 0af15b8ef3b2 Lib/test/test_enum.py --- a/Lib/test/test_enum.py Wed May 11 22:25:05 2016 +0300 +++ b/Lib/test/test_enum.py Thu May 12 10:37:58 2016 +0300 @@ -541,6 +541,18 @@ self.assertEqual([k for k,v in WeekDay.__members__.items() if v.name != k], ['TEUSDAY', ]) + def test_intenum_from_bytes(self): + self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE) + with self.assertRaises(ValueError): + IntStooges.from_bytes(b'\x00\x05', 'big') + + def test_floatenum_fromhex(self): + h = float.hex(FloatStooges.MOE.value) + self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE) + h = float.hex(FloatStooges.MOE.value + 0.01) + with self.assertRaises(ValueError): + FloatStooges.fromhex(h) + def test_pickle_enum(self): if isinstance(Stooges, Exception): raise Stooges diff -r d60040b3bb8c -r 0af15b8ef3b2 Lib/test/test_float.py --- a/Lib/test/test_float.py Wed May 11 22:25:05 2016 +0300 +++ b/Lib/test/test_float.py Thu May 12 10:37:58 2016 +0300 @@ -1355,6 +1355,24 @@ else: self.identical(x, fromHex(toHex(x))) + def test_subclass(self): + class F(float): + def __new__(cls, value): + return float.__new__(cls, value + 1) + + f = F.fromhex((1.5).hex()) + self.assertIs(type(f), F) + self.assertEqual(f, 2.5) + + class F2(float): + def __init__(self, value): + self.foo = 'bar' + + f = F2.fromhex((1.5).hex()) + self.assertIs(type(f), F2) + self.assertEqual(f, 1.5) + self.assertEqual(getattr(f, 'foo', 'none'), 'bar') + if __name__ == '__main__': unittest.main() diff -r d60040b3bb8c -r 0af15b8ef3b2 Lib/test/test_long.py --- a/Lib/test/test_long.py Wed May 11 22:25:05 2016 +0300 +++ b/Lib/test/test_long.py Thu May 12 10:37:58 2016 +0300 @@ -1203,6 +1203,23 @@ self.assertRaises(TypeError, myint.from_bytes, 0, 'big') self.assertRaises(TypeError, int.from_bytes, 0, 'big', True) + class myint2(int): + def __new__(cls, value): + return int.__new__(cls, value + 1) + + i = myint2.from_bytes(b'\x01', 'big') + self.assertIs(type(i), myint2) + self.assertEqual(i, 2) + + class myint3(int): + def __init__(self, value): + self.foo = 'bar' + + i = myint3.from_bytes(b'\x01', 'big') + self.assertIs(type(i), myint3) + self.assertEqual(i, 1) + self.assertEqual(getattr(i, 'foo', 'none'), 'bar') + def test_access_to_nonexistent_digit_0(self): # http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that # ob_digit[0] was being incorrectly accessed for instances of a diff -r d60040b3bb8c -r 0af15b8ef3b2 Misc/NEWS --- a/Misc/NEWS Wed May 11 22:25:05 2016 +0300 +++ b/Misc/NEWS Thu May 12 10:37:58 2016 +0300 @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #23640: int.from_bytes() no longer bypasses constructors for subclasses. + - Issue #26811: gc.get_objects() no longer contains a broken tuple with NULL pointer. diff -r d60040b3bb8c -r 0af15b8ef3b2 Objects/longobject.c --- a/Objects/longobject.c Wed May 11 22:25:05 2016 +0300 +++ b/Objects/longobject.c Thu May 12 10:37:58 2016 +0300 @@ -5049,27 +5049,9 @@ little_endian, is_signed); Py_DECREF(bytes); - /* If from_bytes() was used on subclass, allocate new subclass - * instance, initialize it with decoded int value and return it. - */ - if (type != &PyLong_Type && PyType_IsSubtype(type, &PyLong_Type)) { - PyLongObject *newobj; - int i; - Py_ssize_t n = Py_ABS(Py_SIZE(long_obj)); - - newobj = (PyLongObject *)type->tp_alloc(type, n); - if (newobj == NULL) { - Py_DECREF(long_obj); - return NULL; - } - assert(PyLong_Check(newobj)); - Py_SIZE(newobj) = Py_SIZE(long_obj); - for (i = 0; i < n; i++) { - newobj->ob_digit[i] = - ((PyLongObject *)long_obj)->ob_digit[i]; - } - Py_DECREF(long_obj); - return (PyObject *)newobj; + if (type != &PyLong_Type) { + Py_SETREF(long_obj, PyObject_CallFunctionObjArgs((PyObject *)type, + long_obj, NULL)); } return long_obj;