mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Make subclasses of int, long, complex, float, and unicode perform type
conversion using the proper magic slot (e.g., __int__()). Also move conversion code out of PyNumber_*() functions in the C API into the nb_* function. Applied patch #1109424. Thanks Walter Doewald.
This commit is contained in:
parent
d7c795e729
commit
c3647ac93e
10 changed files with 326 additions and 76 deletions
|
@ -545,6 +545,37 @@ class BuiltinTest(unittest.TestCase):
|
||||||
self.assertEqual(float(unicode(" 3.14 ")), 3.14)
|
self.assertEqual(float(unicode(" 3.14 ")), 3.14)
|
||||||
self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14)
|
self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14)
|
||||||
|
|
||||||
|
def test_floatconversion(self):
|
||||||
|
# Make sure that calls to __float__() work properly
|
||||||
|
class Foo0:
|
||||||
|
def __float__(self):
|
||||||
|
return 42.
|
||||||
|
|
||||||
|
class Foo1(object):
|
||||||
|
def __float__(self):
|
||||||
|
return 42.
|
||||||
|
|
||||||
|
class Foo2(float):
|
||||||
|
def __float__(self):
|
||||||
|
return 42.
|
||||||
|
|
||||||
|
class Foo3(float):
|
||||||
|
def __new__(cls, value=0.):
|
||||||
|
return float.__new__(cls, 2*value)
|
||||||
|
|
||||||
|
def __float__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
class Foo4(float):
|
||||||
|
def __float__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
self.assertAlmostEqual(float(Foo0()), 42.)
|
||||||
|
self.assertAlmostEqual(float(Foo1()), 42.)
|
||||||
|
self.assertAlmostEqual(float(Foo2()), 42.)
|
||||||
|
self.assertAlmostEqual(float(Foo3(21)), 42.)
|
||||||
|
self.assertRaises(TypeError, float, Foo4(42))
|
||||||
|
|
||||||
def test_getattr(self):
|
def test_getattr(self):
|
||||||
import sys
|
import sys
|
||||||
self.assert_(getattr(sys, 'stdout') is sys.stdout)
|
self.assert_(getattr(sys, 'stdout') is sys.stdout)
|
||||||
|
@ -650,6 +681,39 @@ class BuiltinTest(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEqual(int('0123', 0), 83)
|
self.assertEqual(int('0123', 0), 83)
|
||||||
|
|
||||||
|
def test_intconversion(self):
|
||||||
|
# Test __int__()
|
||||||
|
class Foo0:
|
||||||
|
def __int__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
class Foo1(object):
|
||||||
|
def __int__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
class Foo2(int):
|
||||||
|
def __int__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
class Foo3(int):
|
||||||
|
def __int__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
class Foo4(int):
|
||||||
|
def __int__(self):
|
||||||
|
return 42L
|
||||||
|
|
||||||
|
class Foo5(int):
|
||||||
|
def __int__(self):
|
||||||
|
return 42.
|
||||||
|
|
||||||
|
self.assertEqual(int(Foo0()), 42)
|
||||||
|
self.assertEqual(int(Foo1()), 42)
|
||||||
|
self.assertEqual(int(Foo2()), 42)
|
||||||
|
self.assertEqual(int(Foo3()), 0)
|
||||||
|
self.assertEqual(int(Foo4()), 42L)
|
||||||
|
self.assertRaises(TypeError, int, Foo5())
|
||||||
|
|
||||||
def test_intern(self):
|
def test_intern(self):
|
||||||
self.assertRaises(TypeError, intern)
|
self.assertRaises(TypeError, intern)
|
||||||
s = "never interned before"
|
s = "never interned before"
|
||||||
|
@ -810,6 +874,39 @@ class BuiltinTest(unittest.TestCase):
|
||||||
self.assertRaises(ValueError, long, '53', 40)
|
self.assertRaises(ValueError, long, '53', 40)
|
||||||
self.assertRaises(TypeError, long, 1, 12)
|
self.assertRaises(TypeError, long, 1, 12)
|
||||||
|
|
||||||
|
def test_longconversion(self):
|
||||||
|
# Test __long__()
|
||||||
|
class Foo0:
|
||||||
|
def __long__(self):
|
||||||
|
return 42L
|
||||||
|
|
||||||
|
class Foo1(object):
|
||||||
|
def __long__(self):
|
||||||
|
return 42L
|
||||||
|
|
||||||
|
class Foo2(long):
|
||||||
|
def __long__(self):
|
||||||
|
return 42L
|
||||||
|
|
||||||
|
class Foo3(long):
|
||||||
|
def __long__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
class Foo4(long):
|
||||||
|
def __long__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
class Foo5(long):
|
||||||
|
def __long__(self):
|
||||||
|
return 42.
|
||||||
|
|
||||||
|
self.assertEqual(long(Foo0()), 42L)
|
||||||
|
self.assertEqual(long(Foo1()), 42L)
|
||||||
|
self.assertEqual(long(Foo2()), 42L)
|
||||||
|
self.assertEqual(long(Foo3()), 0)
|
||||||
|
self.assertEqual(long(Foo4()), 42)
|
||||||
|
self.assertRaises(TypeError, long, Foo5())
|
||||||
|
|
||||||
def test_map(self):
|
def test_map(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
map(None, 'hello world'),
|
map(None, 'hello world'),
|
||||||
|
|
|
@ -273,6 +273,28 @@ class ComplexTest(unittest.TestCase):
|
||||||
self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j)
|
self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j)
|
||||||
self.assertRaises(TypeError, complex, float2(None))
|
self.assertRaises(TypeError, complex, float2(None))
|
||||||
|
|
||||||
|
class complex0(complex):
|
||||||
|
"""Test usage of __complex__() when inheriting from 'complex'"""
|
||||||
|
def __complex__(self):
|
||||||
|
return 42j
|
||||||
|
|
||||||
|
class complex1(complex):
|
||||||
|
"""Test usage of __complex__() with a __new__() method"""
|
||||||
|
def __new__(self, value=0j):
|
||||||
|
return complex.__new__(self, 2*value)
|
||||||
|
def __complex__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
class complex2(complex):
|
||||||
|
"""Make sure that __complex__() calls fail if anything other than a
|
||||||
|
complex is returned"""
|
||||||
|
def __complex__(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.assertAlmostEqual(complex(complex0(1j)), 42j)
|
||||||
|
self.assertAlmostEqual(complex(complex1(1j)), 2j)
|
||||||
|
self.assertRaises(TypeError, complex, complex2(1j))
|
||||||
|
|
||||||
def test_hash(self):
|
def test_hash(self):
|
||||||
for x in xrange(-30, 30):
|
for x in xrange(-30, 30):
|
||||||
self.assertEqual(hash(x), hash(complex(x, 0)))
|
self.assertEqual(hash(x), hash(complex(x, 0)))
|
||||||
|
|
|
@ -19,6 +19,69 @@ class StrTest(
|
||||||
string_tests.MixinStrUnicodeUserStringTest.test_formatting(self)
|
string_tests.MixinStrUnicodeUserStringTest.test_formatting(self)
|
||||||
self.assertRaises(OverflowError, '%c'.__mod__, 0x1234)
|
self.assertRaises(OverflowError, '%c'.__mod__, 0x1234)
|
||||||
|
|
||||||
|
def test_conversion(self):
|
||||||
|
# Make sure __str__() behaves properly
|
||||||
|
class Foo0:
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"foo"
|
||||||
|
|
||||||
|
class Foo1:
|
||||||
|
def __str__(self):
|
||||||
|
return "foo"
|
||||||
|
|
||||||
|
class Foo2(object):
|
||||||
|
def __str__(self):
|
||||||
|
return "foo"
|
||||||
|
|
||||||
|
class Foo3(object):
|
||||||
|
def __str__(self):
|
||||||
|
return u"foo"
|
||||||
|
|
||||||
|
class Foo4(unicode):
|
||||||
|
def __str__(self):
|
||||||
|
return u"foo"
|
||||||
|
|
||||||
|
class Foo5(str):
|
||||||
|
def __str__(self):
|
||||||
|
return u"foo"
|
||||||
|
|
||||||
|
class Foo6(str):
|
||||||
|
def __str__(self):
|
||||||
|
return "foos"
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"foou"
|
||||||
|
|
||||||
|
class Foo7(unicode):
|
||||||
|
def __str__(self):
|
||||||
|
return "foos"
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"foou"
|
||||||
|
|
||||||
|
class Foo8(str):
|
||||||
|
def __new__(cls, content=""):
|
||||||
|
return str.__new__(cls, 2*content)
|
||||||
|
def __str__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
class Foo9(str):
|
||||||
|
def __str__(self):
|
||||||
|
return "string"
|
||||||
|
def __unicode__(self):
|
||||||
|
return "not unicode"
|
||||||
|
|
||||||
|
self.assert_(str(Foo0()).startswith("<")) # this is different from __unicode__
|
||||||
|
self.assertEqual(str(Foo1()), "foo")
|
||||||
|
self.assertEqual(str(Foo2()), "foo")
|
||||||
|
self.assertEqual(str(Foo3()), "foo")
|
||||||
|
self.assertEqual(str(Foo4("bar")), "foo")
|
||||||
|
self.assertEqual(str(Foo5("bar")), "foo")
|
||||||
|
self.assertEqual(str(Foo6("bar")), "foos")
|
||||||
|
self.assertEqual(str(Foo7("bar")), "foos")
|
||||||
|
self.assertEqual(str(Foo8("foo")), "foofoo")
|
||||||
|
self.assertEqual(str(Foo9("foo")), "string")
|
||||||
|
self.assertEqual(unicode(Foo9("foo")), u"not unicode")
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test_support.run_unittest(StrTest)
|
test_support.run_unittest(StrTest)
|
||||||
|
|
||||||
|
|
|
@ -389,7 +389,6 @@ class UnicodeTest(
|
||||||
self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103 abc')
|
self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103 abc')
|
||||||
self.assertEqual('%c' % u'a', u'a')
|
self.assertEqual('%c' % u'a', u'a')
|
||||||
|
|
||||||
|
|
||||||
def test_constructor(self):
|
def test_constructor(self):
|
||||||
# unicode(obj) tests (this maps to PyObject_Unicode() at C level)
|
# unicode(obj) tests (this maps to PyObject_Unicode() at C level)
|
||||||
|
|
||||||
|
@ -725,6 +724,69 @@ class UnicodeTest(
|
||||||
y = x.encode("raw-unicode-escape").decode("raw-unicode-escape")
|
y = x.encode("raw-unicode-escape").decode("raw-unicode-escape")
|
||||||
self.assertEqual(x, y)
|
self.assertEqual(x, y)
|
||||||
|
|
||||||
|
def test_conversion(self):
|
||||||
|
# Make sure __unicode__() works properly
|
||||||
|
class Foo0:
|
||||||
|
def __str__(self):
|
||||||
|
return "foo"
|
||||||
|
|
||||||
|
class Foo1:
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"foo"
|
||||||
|
|
||||||
|
class Foo2(object):
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"foo"
|
||||||
|
|
||||||
|
class Foo3(object):
|
||||||
|
def __unicode__(self):
|
||||||
|
return "foo"
|
||||||
|
|
||||||
|
class Foo4(str):
|
||||||
|
def __unicode__(self):
|
||||||
|
return "foo"
|
||||||
|
|
||||||
|
class Foo5(unicode):
|
||||||
|
def __unicode__(self):
|
||||||
|
return "foo"
|
||||||
|
|
||||||
|
class Foo6(str):
|
||||||
|
def __str__(self):
|
||||||
|
return "foos"
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"foou"
|
||||||
|
|
||||||
|
class Foo7(unicode):
|
||||||
|
def __str__(self):
|
||||||
|
return "foos"
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"foou"
|
||||||
|
|
||||||
|
class Foo8(unicode):
|
||||||
|
def __new__(cls, content=""):
|
||||||
|
return unicode.__new__(cls, 2*content)
|
||||||
|
def __unicode__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
class Foo9(unicode):
|
||||||
|
def __str__(self):
|
||||||
|
return "string"
|
||||||
|
def __unicode__(self):
|
||||||
|
return "not unicode"
|
||||||
|
|
||||||
|
self.assertEqual(unicode(Foo0()), u"foo")
|
||||||
|
self.assertEqual(unicode(Foo1()), u"foo")
|
||||||
|
self.assertEqual(unicode(Foo2()), u"foo")
|
||||||
|
self.assertEqual(unicode(Foo3()), u"foo")
|
||||||
|
self.assertEqual(unicode(Foo4("bar")), u"foo")
|
||||||
|
self.assertEqual(unicode(Foo5("bar")), u"foo")
|
||||||
|
self.assertEqual(unicode(Foo6("bar")), u"foou")
|
||||||
|
self.assertEqual(unicode(Foo7("bar")), u"foou")
|
||||||
|
self.assertEqual(unicode(Foo8("foo")), u"foofoo")
|
||||||
|
self.assertEqual(str(Foo9("foo")), "string")
|
||||||
|
self.assertEqual(unicode(Foo9("foo")), u"not unicode")
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test_support.run_unittest(UnicodeTest)
|
test_support.run_unittest(UnicodeTest)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,14 @@ What's New in Python 2.5 alpha 1?
|
||||||
Core and builtins
|
Core and builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- patch #1109424: int, long, float, complex, and unicode now check for the
|
||||||
|
proper magic slot for type conversions when subclassed. Previously the
|
||||||
|
magic slot was ignored during conversion. Semantics now match the way
|
||||||
|
subclasses of str always behaved. int/long/float, conversion of an instance
|
||||||
|
to the base class has been moved the prroper nb_* magic slot and out of
|
||||||
|
PyNumber_*().
|
||||||
|
Thanks Walter Dörwald.
|
||||||
|
|
||||||
- Descriptors defined in C with a PyGetSetDef structure, where the setter is
|
- Descriptors defined in C with a PyGetSetDef structure, where the setter is
|
||||||
NULL, now raise an AttributeError when attempting to set or delete the
|
NULL, now raise an AttributeError when attempting to set or delete the
|
||||||
attribute. Previously a TypeError was raised, but this was inconsistent
|
attribute. Previously a TypeError was raised, but this was inconsistent
|
||||||
|
|
|
@ -951,7 +951,19 @@ PyNumber_Int(PyObject *o)
|
||||||
Py_INCREF(o);
|
Py_INCREF(o);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
if (PyInt_Check(o)) {
|
m = o->ob_type->tp_as_number;
|
||||||
|
if (m && m->nb_int) { /* This should include subclasses of int */
|
||||||
|
PyObject *res = m->nb_int(o);
|
||||||
|
if (res && (!PyInt_Check(res) && !PyLong_Check(res))) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"__int__ returned non-int (type %.200s)",
|
||||||
|
res->ob_type->tp_name);
|
||||||
|
Py_DECREF(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (PyInt_Check(o)) { /* A int subclass without nb_int */
|
||||||
PyIntObject *io = (PyIntObject*)o;
|
PyIntObject *io = (PyIntObject*)o;
|
||||||
return PyInt_FromLong(io->ob_ival);
|
return PyInt_FromLong(io->ob_ival);
|
||||||
}
|
}
|
||||||
|
@ -964,18 +976,6 @@ PyNumber_Int(PyObject *o)
|
||||||
PyUnicode_GET_SIZE(o),
|
PyUnicode_GET_SIZE(o),
|
||||||
10);
|
10);
|
||||||
#endif
|
#endif
|
||||||
m = o->ob_type->tp_as_number;
|
|
||||||
if (m && m->nb_int) {
|
|
||||||
PyObject *res = m->nb_int(o);
|
|
||||||
if (res && (!PyInt_Check(res) && !PyLong_Check(res))) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"__int__ returned non-int (type %.200s)",
|
|
||||||
res->ob_type->tp_name);
|
|
||||||
Py_DECREF(res);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
|
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
|
||||||
return int_from_string((char*)buffer, buffer_len);
|
return int_from_string((char*)buffer, buffer_len);
|
||||||
|
|
||||||
|
@ -1010,11 +1010,19 @@ PyNumber_Long(PyObject *o)
|
||||||
|
|
||||||
if (o == NULL)
|
if (o == NULL)
|
||||||
return null_error();
|
return null_error();
|
||||||
if (PyLong_CheckExact(o)) {
|
m = o->ob_type->tp_as_number;
|
||||||
Py_INCREF(o);
|
if (m && m->nb_long) { /* This should include subclasses of long */
|
||||||
return o;
|
PyObject *res = m->nb_long(o);
|
||||||
|
if (res && (!PyInt_Check(res) && !PyLong_Check(res))) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"__long__ returned non-long (type %.200s)",
|
||||||
|
res->ob_type->tp_name);
|
||||||
|
Py_DECREF(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
if (PyLong_Check(o))
|
if (PyLong_Check(o)) /* A long subclass without nb_long */
|
||||||
return _PyLong_Copy((PyLongObject *)o);
|
return _PyLong_Copy((PyLongObject *)o);
|
||||||
if (PyString_Check(o))
|
if (PyString_Check(o))
|
||||||
/* need to do extra error checking that PyLong_FromString()
|
/* need to do extra error checking that PyLong_FromString()
|
||||||
|
@ -1030,18 +1038,6 @@ PyNumber_Long(PyObject *o)
|
||||||
PyUnicode_GET_SIZE(o),
|
PyUnicode_GET_SIZE(o),
|
||||||
10);
|
10);
|
||||||
#endif
|
#endif
|
||||||
m = o->ob_type->tp_as_number;
|
|
||||||
if (m && m->nb_long) {
|
|
||||||
PyObject *res = m->nb_long(o);
|
|
||||||
if (res && (!PyInt_Check(res) && !PyLong_Check(res))) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"__long__ returned non-long (type %.200s)",
|
|
||||||
res->ob_type->tp_name);
|
|
||||||
Py_DECREF(res);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
|
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
|
||||||
return long_from_string(buffer, buffer_len);
|
return long_from_string(buffer, buffer_len);
|
||||||
|
|
||||||
|
@ -1055,28 +1051,22 @@ PyNumber_Float(PyObject *o)
|
||||||
|
|
||||||
if (o == NULL)
|
if (o == NULL)
|
||||||
return null_error();
|
return null_error();
|
||||||
if (PyFloat_CheckExact(o)) {
|
m = o->ob_type->tp_as_number;
|
||||||
Py_INCREF(o);
|
if (m && m->nb_float) { /* This should include subclasses of float */
|
||||||
return o;
|
PyObject *res = m->nb_float(o);
|
||||||
|
if (res && !PyFloat_Check(res)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"__float__ returned non-float (type %.200s)",
|
||||||
|
res->ob_type->tp_name);
|
||||||
|
Py_DECREF(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
if (PyFloat_Check(o)) {
|
if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */
|
||||||
PyFloatObject *po = (PyFloatObject *)o;
|
PyFloatObject *po = (PyFloatObject *)o;
|
||||||
return PyFloat_FromDouble(po->ob_fval);
|
return PyFloat_FromDouble(po->ob_fval);
|
||||||
}
|
}
|
||||||
if (!PyString_Check(o)) {
|
|
||||||
m = o->ob_type->tp_as_number;
|
|
||||||
if (m && m->nb_float) {
|
|
||||||
PyObject *res = m->nb_float(o);
|
|
||||||
if (res && !PyFloat_Check(res)) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"__float__ returned non-float (type %.200s)",
|
|
||||||
res->ob_type->tp_name);
|
|
||||||
Py_DECREF(res);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PyFloat_FromString(o, NULL);
|
return PyFloat_FromString(o, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -926,7 +926,10 @@ float_int(PyObject *v)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
float_float(PyObject *v)
|
float_float(PyObject *v)
|
||||||
{
|
{
|
||||||
Py_INCREF(v);
|
if (PyFloat_CheckExact(v))
|
||||||
|
Py_INCREF(v);
|
||||||
|
else
|
||||||
|
v = PyFloat_FromDouble(((PyFloatObject *)v)->ob_fval);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -826,7 +826,10 @@ int_coerce(PyObject **pv, PyObject **pw)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
int_int(PyIntObject *v)
|
int_int(PyIntObject *v)
|
||||||
{
|
{
|
||||||
Py_INCREF(v);
|
if (PyInt_CheckExact(v))
|
||||||
|
Py_INCREF(v);
|
||||||
|
else
|
||||||
|
v = (PyIntObject *)PyInt_FromLong(v->ob_ival);
|
||||||
return (PyObject *)v;
|
return (PyObject *)v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2861,7 +2861,10 @@ long_coerce(PyObject **pv, PyObject **pw)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
long_long(PyObject *v)
|
long_long(PyObject *v)
|
||||||
{
|
{
|
||||||
Py_INCREF(v);
|
if (PyLong_CheckExact(v))
|
||||||
|
Py_INCREF(v);
|
||||||
|
else
|
||||||
|
v = _PyLong_Copy((PyLongObject *)v);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -373,6 +373,8 @@ PyObject *
|
||||||
PyObject_Unicode(PyObject *v)
|
PyObject_Unicode(PyObject *v)
|
||||||
{
|
{
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
|
PyObject *func;
|
||||||
|
static PyObject *unicodestr;
|
||||||
|
|
||||||
if (v == NULL)
|
if (v == NULL)
|
||||||
res = PyString_FromString("<NULL>");
|
res = PyString_FromString("<NULL>");
|
||||||
|
@ -380,35 +382,32 @@ PyObject_Unicode(PyObject *v)
|
||||||
Py_INCREF(v);
|
Py_INCREF(v);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
if (PyUnicode_Check(v)) {
|
/* XXX As soon as we have a tp_unicode slot, we should
|
||||||
/* For a Unicode subtype that's not a Unicode object,
|
check this before trying the __unicode__
|
||||||
return a true Unicode object with the same data. */
|
method. */
|
||||||
return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(v),
|
if (unicodestr == NULL) {
|
||||||
PyUnicode_GET_SIZE(v));
|
unicodestr= PyString_InternFromString("__unicode__");
|
||||||
|
if (unicodestr == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
func = PyObject_GetAttr(v, unicodestr);
|
||||||
|
if (func != NULL) {
|
||||||
|
res = PyEval_CallObject(func, (PyObject *)NULL);
|
||||||
|
Py_DECREF(func);
|
||||||
}
|
}
|
||||||
if (PyString_Check(v)) {
|
|
||||||
Py_INCREF(v);
|
|
||||||
res = v;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
PyObject *func;
|
PyErr_Clear();
|
||||||
static PyObject *unicodestr;
|
if (PyUnicode_Check(v)) {
|
||||||
/* XXX As soon as we have a tp_unicode slot, we should
|
/* For a Unicode subtype that's didn't overwrite __unicode__,
|
||||||
check this before trying the __unicode__
|
return a true Unicode object with the same data. */
|
||||||
method. */
|
return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(v),
|
||||||
if (unicodestr == NULL) {
|
PyUnicode_GET_SIZE(v));
|
||||||
unicodestr= PyString_InternFromString(
|
|
||||||
"__unicode__");
|
|
||||||
if (unicodestr == NULL)
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
func = PyObject_GetAttr(v, unicodestr);
|
if (PyString_CheckExact(v)) {
|
||||||
if (func != NULL) {
|
Py_INCREF(v);
|
||||||
res = PyEval_CallObject(func, (PyObject *)NULL);
|
res = v;
|
||||||
Py_DECREF(func);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyErr_Clear();
|
|
||||||
if (v->ob_type->tp_str != NULL)
|
if (v->ob_type->tp_str != NULL)
|
||||||
res = (*v->ob_type->tp_str)(v);
|
res = (*v->ob_type->tp_str)(v);
|
||||||
else
|
else
|
||||||
|
@ -424,7 +423,7 @@ PyObject_Unicode(PyObject *v)
|
||||||
if (str)
|
if (str)
|
||||||
res = str;
|
res = str;
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue