]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #23640: int.from_bytes() no longer bypasses constructors for subclasses.
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 12 May 2016 07:37:58 +0000 (10:37 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Thu, 12 May 2016 07:37:58 +0000 (10:37 +0300)
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

index 250743949bf57f30f0d5dc4b51f8230b86c458e4..d30a3b9c0f24b2b5a6a9f25f21df886507f2cc91 100644 (file)
@@ -314,6 +314,10 @@ class BoolTest(unittest.TestCase):
                 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
index 4b14e7f013bf8b752b05902c440ba8b7220ca2db..e970a264d71e4c5e42c0a797d55ccc38b2fae63b 100644 (file)
@@ -541,6 +541,18 @@ class TestEnum(unittest.TestCase):
         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
index 48f7a70c6808938b74b6995bcd02e27c4f3e220f..cb1f6db8fc76279a1954af4b233f37c940ed5f79 100644 (file)
@@ -1355,6 +1355,24 @@ class HexFloatTestCase(unittest.TestCase):
             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()
index 62e69a9ed78d14269f0c675265ff823195c4a8be..b2d008b1013594e12b23d8fb82263d4f937a42e2 100644 (file)
@@ -1203,6 +1203,23 @@ class LongTest(unittest.TestCase):
         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
index 723342ced13ac726df3f78764b7cec77d4974a19..199476de2405c0bfde0df7f4bc26b67ca2070d4e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@ Release date: tba
 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.
 
index d821e4bfb67f977e96c1b7149a0c8f97e30384b6..f68d15e615208872616985dd088da770f2708c0a 100644 (file)
@@ -5049,27 +5049,9 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds)
         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;