Index: Lib/test/test_builtin.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_builtin.py,v retrieving revision 1.39 diff -u -r1.39 test_builtin.py --- Lib/test/test_builtin.py 16 Jan 2005 00:21:28 -0000 1.39 +++ Lib/test/test_builtin.py 25 Jan 2005 21:39:10 -0000 @@ -509,6 +509,36 @@ self.assertEqual(float(unicode(" 3.14 ")), 3.14) self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) + def test_floatconversion(self): + 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): import sys self.assert_(getattr(sys, 'stdout') is sys.stdout) @@ -614,6 +644,38 @@ self.assertEqual(int('0123', 0), 83) + def test_intconversion(self): + 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): self.assertRaises(TypeError, intern) s = "never interned before" @@ -774,6 +836,38 @@ self.assertRaises(ValueError, long, '53', 40) self.assertRaises(TypeError, long, 1, 12) + def test_longconversion(self): + 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): self.assertEqual( map(None, 'hello world'), Index: Lib/test/test_complex.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_complex.py,v retrieving revision 1.15 diff -u -r1.15 test_complex.py --- Lib/test/test_complex.py 22 Aug 2004 21:09:14 -0000 1.15 +++ Lib/test/test_complex.py 25 Jan 2005 21:39:11 -0000 @@ -273,6 +273,24 @@ self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j) self.assertRaises(TypeError, complex, float2(None)) + class complex0(complex): + def __complex__(self): + return 42j + + class complex1(complex): + def __new__(self, value=0j): + return complex.__new__(self, 2*value) + def __complex__(self): + return self + + class complex2(complex): + 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): for x in xrange(-30, 30): self.assertEqual(hash(x), hash(complex(x, 0))) Index: Lib/test/test_str.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_str.py,v retrieving revision 1.4 diff -u -r1.4 test_str.py --- Lib/test/test_str.py 26 Aug 2004 16:53:04 -0000 1.4 +++ Lib/test/test_str.py 25 Jan 2005 21:39:11 -0000 @@ -19,6 +19,68 @@ string_tests.MixinStrUnicodeUserStringTest.test_formatting(self) self.assertRaises(OverflowError, '%c'.__mod__, 0x1234) + def test_conversion(self): + 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(): test_support.run_unittest(StrTest) Index: Lib/test/test_unicode.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_unicode.py,v retrieving revision 1.93 diff -u -r1.93 test_unicode.py --- Lib/test/test_unicode.py 26 Aug 2004 16:53:04 -0000 1.93 +++ Lib/test/test_unicode.py 25 Jan 2005 21:39:12 -0000 @@ -389,7 +389,6 @@ self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103 abc') self.assertEqual('%c' % u'a', u'a') - def test_constructor(self): # unicode(obj) tests (this maps to PyObject_Unicode() at C level) @@ -725,6 +724,68 @@ y = x.encode("raw-unicode-escape").decode("raw-unicode-escape") self.assertEqual(x, y) + def test_conversion(self): + 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(): test_support.run_unittest(UnicodeTest) Index: Objects/abstract.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v retrieving revision 2.135 diff -u -r2.135 abstract.c --- Objects/abstract.c 18 Dec 2004 19:00:59 -0000 2.135 +++ Objects/abstract.c 25 Jan 2005 21:39:13 -0000 @@ -951,7 +951,19 @@ Py_INCREF(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; return PyInt_FromLong(io->ob_ival); } @@ -964,18 +976,6 @@ PyUnicode_GET_SIZE(o), 10); #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)) return int_from_string((char*)buffer, buffer_len); @@ -1010,11 +1010,19 @@ if (o == NULL) return null_error(); - if (PyLong_CheckExact(o)) { - Py_INCREF(o); - return o; + m = o->ob_type->tp_as_number; + if (m && m->nb_long) { /* This should include subclasses of 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 (PyLong_Check(o)) + if (PyLong_Check(o)) /* A long subclass without nb_long */ return _PyLong_Copy((PyLongObject *)o); if (PyString_Check(o)) /* need to do extra error checking that PyLong_FromString() @@ -1030,18 +1038,6 @@ PyUnicode_GET_SIZE(o), 10); #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)) return long_from_string(buffer, buffer_len); @@ -1055,28 +1051,22 @@ if (o == NULL) return null_error(); - if (PyFloat_CheckExact(o)) { - Py_INCREF(o); - return o; + m = o->ob_type->tp_as_number; + if (m && m->nb_float) { /* This should include subclasses of 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; } - if (PyFloat_Check(o)) { + if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */ PyFloatObject *po = (PyFloatObject *)o; 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); } Index: Objects/floatobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/floatobject.c,v retrieving revision 2.134 diff -u -r2.134 floatobject.c --- Objects/floatobject.c 23 Sep 2004 19:22:41 -0000 2.134 +++ Objects/floatobject.c 25 Jan 2005 21:39:14 -0000 @@ -926,7 +926,10 @@ static PyObject * float_float(PyObject *v) { - Py_INCREF(v); + if (PyFloat_CheckExact(v)) + Py_INCREF(v); + else + v = PyFloat_FromDouble(((PyFloatObject *)v)->ob_fval); return v; } Index: Objects/intobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/intobject.c,v retrieving revision 2.113 diff -u -r2.113 intobject.c --- Objects/intobject.c 25 Aug 2004 02:14:08 -0000 2.113 +++ Objects/intobject.c 25 Jan 2005 21:39:14 -0000 @@ -826,7 +826,10 @@ static PyObject * 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; } Index: Objects/longobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/longobject.c,v retrieving revision 1.165 diff -u -r1.165 longobject.c --- Objects/longobject.c 20 Sep 2004 06:14:54 -0000 1.165 +++ Objects/longobject.c 25 Jan 2005 21:39:15 -0000 @@ -2840,7 +2840,10 @@ static PyObject * long_long(PyObject *v) { - Py_INCREF(v); + if (PyLong_CheckExact(v)) + Py_INCREF(v); + else + v = _PyLong_Copy((PyLongObject *)v); return v; } Index: Objects/object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.225 diff -u -r2.225 object.c --- Objects/object.c 23 Dec 2004 22:13:13 -0000 2.225 +++ Objects/object.c 25 Jan 2005 21:39:16 -0000 @@ -373,6 +373,8 @@ PyObject_Unicode(PyObject *v) { PyObject *res; + PyObject *func; + static PyObject *unicodestr; if (v == NULL) res = PyString_FromString(""); @@ -380,35 +382,32 @@ Py_INCREF(v); return v; } - if (PyUnicode_Check(v)) { - /* For a Unicode subtype that's not a Unicode object, - return a true Unicode object with the same data. */ - return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(v), - PyUnicode_GET_SIZE(v)); + /* XXX As soon as we have a tp_unicode slot, we should + check this before trying the __unicode__ + method. */ + if (unicodestr == NULL) { + 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 { - PyObject *func; - static PyObject *unicodestr; - /* XXX As soon as we have a tp_unicode slot, we should - check this before trying the __unicode__ - method. */ - if (unicodestr == NULL) { - 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); + PyErr_Clear(); + if (PyUnicode_Check(v)) { + /* For a Unicode subtype that's didn't overwrite __unicode__, + return a true Unicode object with the same data. */ + return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(v), + PyUnicode_GET_SIZE(v)); + } + if (PyString_CheckExact(v)) { + Py_INCREF(v); + res = v; } else { - PyErr_Clear(); if (v->ob_type->tp_str != NULL) res = (*v->ob_type->tp_str)(v); else @@ -424,7 +423,7 @@ if (str) res = str; else - return NULL; + return NULL; } return res; }