summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-05-12 07:37:58 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2016-05-12 07:37:58 (GMT)
commitea36c941a1b2ad6582a35bc42aa70da9600d2841 (patch)
treee915477a42189e490044a15d786a18382064bc1f
parent9de7efe5ab40c19775dcc9ca88adf58d906fc53d (diff)
downloadcpython-ea36c941a1b2ad6582a35bc42aa70da9600d2841.zip
cpython-ea36c941a1b2ad6582a35bc42aa70da9600d2841.tar.gz
cpython-ea36c941a1b2ad6582a35bc42aa70da9600d2841.tar.bz2
Issue #23640: int.from_bytes() no longer bypasses constructors for subclasses.
-rw-r--r--Lib/test/test_bool.py4
-rw-r--r--Lib/test/test_enum.py12
-rw-r--r--Lib/test/test_float.py18
-rw-r--r--Lib/test/test_long.py17
-rw-r--r--Misc/NEWS2
-rw-r--r--Objects/longobject.c24
6 files changed, 56 insertions, 21 deletions
diff --git a/Lib/test/test_bool.py b/Lib/test/test_bool.py
index 2507439..d30a3b9 100644
--- a/Lib/test/test_bool.py
+++ b/Lib/test/test_bool.py
@@ -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
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index 4b14e7f..e970a26 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -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
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
index 48f7a70..cb1f6db 100644
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -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()
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index 62e69a9..b2d008b 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -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
diff --git a/Misc/NEWS b/Misc/NEWS
index 723342c..199476d 100644
--- 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.
diff --git a/Objects/longobject.c b/Objects/longobject.c
index d821e4b..f68d15e 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -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;