Commit 1f364438 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #23640: int.from_bytes() no longer bypasses constructors for subclasses.

parents 5787ef62 ea36c941
...@@ -314,6 +314,10 @@ class BoolTest(unittest.TestCase): ...@@ -314,6 +314,10 @@ class BoolTest(unittest.TestCase):
return -1 return -1
self.assertRaises(ValueError, bool, Eggs()) 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): def test_sane_len(self):
# this test just tests our assumptions about __len__ # this test just tests our assumptions about __len__
# this will start failing if __len__ changes assertions # this will start failing if __len__ changes assertions
......
...@@ -564,6 +564,18 @@ class TestEnum(unittest.TestCase): ...@@ -564,6 +564,18 @@ class TestEnum(unittest.TestCase):
self.assertEqual([k for k,v in WeekDay.__members__.items() self.assertEqual([k for k,v in WeekDay.__members__.items()
if v.name != k], ['TEUSDAY', ]) 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): def test_pickle_enum(self):
if isinstance(Stooges, Exception): if isinstance(Stooges, Exception):
raise Stooges raise Stooges
......
...@@ -1354,6 +1354,24 @@ class HexFloatTestCase(unittest.TestCase): ...@@ -1354,6 +1354,24 @@ class HexFloatTestCase(unittest.TestCase):
else: else:
self.identical(x, fromHex(toHex(x))) 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__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -1236,6 +1236,23 @@ class LongTest(unittest.TestCase): ...@@ -1236,6 +1236,23 @@ class LongTest(unittest.TestCase):
self.assertRaises(TypeError, myint.from_bytes, 0, 'big') self.assertRaises(TypeError, myint.from_bytes, 0, 'big')
self.assertRaises(TypeError, int.from_bytes, 0, 'big', True) 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): def test_access_to_nonexistent_digit_0(self):
# http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that # http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that
# ob_digit[0] was being incorrectly accessed for instances of a # ob_digit[0] was being incorrectly accessed for instances of a
......
...@@ -10,6 +10,8 @@ Release date: tba ...@@ -10,6 +10,8 @@ Release date: tba
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #23640: int.from_bytes() no longer bypasses constructors for subclasses.
- Issue #27005: Optimized the float.fromhex() class method for exact float. - Issue #27005: Optimized the float.fromhex() class method for exact float.
It is now 2 times faster. It is now 2 times faster.
......
...@@ -5199,27 +5199,9 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -5199,27 +5199,9 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds)
little_endian, is_signed); little_endian, is_signed);
Py_DECREF(bytes); Py_DECREF(bytes);
/* If from_bytes() was used on subclass, allocate new subclass if (type != &PyLong_Type) {
* instance, initialize it with decoded int value and return it. Py_SETREF(long_obj, PyObject_CallFunctionObjArgs((PyObject *)type,
*/ long_obj, NULL));
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;
} }
return long_obj; return long_obj;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment