Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8d30ad7

Browse files
Issue python#24731: Fixed crash on converting objects with special methods
__str__, __trunc__, and __float__ returning instances of subclasses of str, long, and float to subclasses of str, long, and float correspondingly.
1 parent 80767a3 commit 8d30ad7

9 files changed

Lines changed: 66 additions & 6 deletions

File tree

Lib/test/test_float.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
test_dir = os.path.dirname(__file__) or os.curdir
2828
format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
2929

30+
class FloatSubclass(float):
31+
pass
32+
33+
class OtherFloatSubclass(float):
34+
pass
35+
3036
class GeneralFloatCases(unittest.TestCase):
3137

3238
def test_float(self):
@@ -200,6 +206,15 @@ def __float__(self):
200206
return ""
201207
self.assertRaises(TypeError, time.sleep, Foo5())
202208

209+
# Issue #24731
210+
class F:
211+
def __float__(self):
212+
return OtherFloatSubclass(42.)
213+
self.assertAlmostEqual(float(F()), 42.)
214+
self.assertIs(type(float(F())), OtherFloatSubclass)
215+
self.assertAlmostEqual(FloatSubclass(F()), 42.)
216+
self.assertIs(type(FloatSubclass(F())), FloatSubclass)
217+
203218
def test_is_integer(self):
204219
self.assertFalse((1.1).is_integer())
205220
self.assertTrue((1.).is_integer())

Lib/test/test_int.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
(unichr(0x200), ValueError),
4646
]
4747

48+
class IntSubclass(int):
49+
pass
50+
4851
class IntLongCommonTests(object):
4952

5053
"""Mixin of test cases to share between both test_int and test_long."""
@@ -477,6 +480,18 @@ def __trunc__(self):
477480
self.fail("Failed to raise TypeError with %s" %
478481
((base, trunc_result_base),))
479482

483+
class TruncReturnsIntSubclass(base):
484+
def __trunc__(self):
485+
return True
486+
good_int = TruncReturnsIntSubclass()
487+
n = int(good_int)
488+
self.assertEqual(n, 1)
489+
self.assertIs(type(n), bool)
490+
n = IntSubclass(good_int)
491+
self.assertEqual(n, 1)
492+
self.assertIs(type(n), IntSubclass)
493+
494+
480495
def test_main():
481496
run_unittest(IntTestCases)
482497

Lib/test/test_long.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ def __str__(self):
7979
(unichr(0x200), ValueError),
8080
]
8181

82+
class LongSubclass(long):
83+
pass
84+
85+
class OtherLongSubclass(long):
86+
pass
87+
8288
class LongTest(test_int.IntLongCommonTests, unittest.TestCase):
8389

8490
ntype = long
@@ -539,6 +545,17 @@ def __trunc__(self):
539545
self.fail("Failed to raise TypeError with %s" %
540546
((base, trunc_result_base),))
541547

548+
class TruncReturnsLongSubclass(base):
549+
def __long__(self):
550+
return OtherLongSubclass(42L)
551+
good_int = TruncReturnsLongSubclass()
552+
n = long(good_int)
553+
self.assertEqual(n, 42L)
554+
self.assertIs(type(n), OtherLongSubclass)
555+
n = LongSubclass(good_int)
556+
self.assertEqual(n, 42L)
557+
self.assertIs(type(n), LongSubclass)
558+
542559
def test_misc(self):
543560

544561
# check the extremes in int<->long conversion

Lib/test/test_str.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
from test import test_support, string_tests
55

66

7+
class StrSubclass(str):
8+
pass
9+
710
class StrTest(
811
string_tests.CommonTest,
912
string_tests.MixinStrUnicodeUserStringTest,
@@ -107,6 +110,9 @@ def __unicode__(self):
107110
self.assertEqual(str(Foo6("bar")), "foos")
108111
self.assertEqual(str(Foo7("bar")), "foos")
109112
self.assertEqual(str(Foo8("foo")), "foofoo")
113+
self.assertIs(type(str(Foo8("foo"))), Foo8)
114+
self.assertEqual(StrSubclass(Foo8("foo")), "foofoo")
115+
self.assertIs(type(StrSubclass(Foo8("foo"))), StrSubclass)
110116
self.assertEqual(str(Foo9("foo")), "string")
111117
self.assertEqual(unicode(Foo9("foo")), u"not unicode")
112118

Lib/test/test_unicode.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ def decode2(input, errors="strict"):
3333
return None
3434
codecs.register(search_function)
3535

36+
class UnicodeSubclass(unicode):
37+
pass
38+
3639
class UnicodeTest(
3740
string_tests.CommonTest,
3841
string_tests.MixinStrUnicodeUserStringTest,
@@ -685,9 +688,6 @@ def test_constructor(self):
685688
u'unicode remains unicode'
686689
)
687690

688-
class UnicodeSubclass(unicode):
689-
pass
690-
691691
self.assertEqual(
692692
unicode(UnicodeSubclass('unicode subclass becomes unicode')),
693693
u'unicode subclass becomes unicode'
@@ -1269,6 +1269,9 @@ def __unicode__(self):
12691269
self.assertEqual(unicode(Foo6("bar")), u"foou")
12701270
self.assertEqual(unicode(Foo7("bar")), u"foou")
12711271
self.assertEqual(unicode(Foo8("foo")), u"foofoo")
1272+
self.assertIs(type(unicode(Foo8("foo"))), Foo8)
1273+
self.assertEqual(UnicodeSubclass(Foo8("foo")), u"foofoo")
1274+
self.assertIs(type(UnicodeSubclass(Foo8("foo"))), UnicodeSubclass)
12721275
self.assertEqual(str(Foo9("foo")), "string")
12731276
self.assertEqual(unicode(Foo9("foo")), u"not unicode")
12741277

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Python 2.7.12?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #24731: Fixed crash on converting objects with special methods
14+
__str__, __trunc__, and __float__ returning instances of subclasses of
15+
str, long, and float to subclasses of str, long, and float correspondingly.
16+
1317
Library
1418
-------
1519

Objects/floatobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1839,7 +1839,7 @@ float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
18391839
tmp = float_new(&PyFloat_Type, args, kwds);
18401840
if (tmp == NULL)
18411841
return NULL;
1842-
assert(PyFloat_CheckExact(tmp));
1842+
assert(PyFloat_Check(tmp));
18431843
newobj = type->tp_alloc(type, 0);
18441844
if (newobj == NULL) {
18451845
Py_DECREF(tmp);

Objects/longobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4068,7 +4068,7 @@ long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
40684068
tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds);
40694069
if (tmp == NULL)
40704070
return NULL;
4071-
assert(PyLong_CheckExact(tmp));
4071+
assert(PyLong_Check(tmp));
40724072
n = Py_SIZE(tmp);
40734073
if (n < 0)
40744074
n = -n;

Objects/stringobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3719,7 +3719,7 @@ str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
37193719
tmp = string_new(&PyString_Type, args, kwds);
37203720
if (tmp == NULL)
37213721
return NULL;
3722-
assert(PyString_CheckExact(tmp));
3722+
assert(PyString_Check(tmp));
37233723
n = PyString_GET_SIZE(tmp);
37243724
pnew = type->tp_alloc(type, n);
37253725
if (pnew != NULL) {

0 commit comments

Comments
 (0)