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.
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 4e8ffe5..103d1a3 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -545,6 +545,37 @@
             self.assertEqual(float(unicode("  3.14  ")), 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):
         import sys
         self.assert_(getattr(sys, 'stdout') is sys.stdout)
@@ -650,6 +681,39 @@
 
         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):
         self.assertRaises(TypeError, intern)
         s = "never interned before"
@@ -810,6 +874,39 @@
         self.assertRaises(ValueError, long, '53', 40)
         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):
         self.assertEqual(
             map(None, 'hello world'),
diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py
index 15f4b65..70e91c1 100644
--- a/Lib/test/test_complex.py
+++ b/Lib/test/test_complex.py
@@ -273,6 +273,28 @@
         self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j)
         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):
         for x in xrange(-30, 30):
             self.assertEqual(hash(x), hash(complex(x, 0)))
diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py
index 82632f1..45942a6 100644
--- a/Lib/test/test_str.py
+++ b/Lib/test/test_str.py
@@ -19,6 +19,69 @@
         string_tests.MixinStrUnicodeUserStringTest.test_formatting(self)
         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():
     test_support.run_unittest(StrTest)
 
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index 69244f0..80242d5 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -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,69 @@
         y = x.encode("raw-unicode-escape").decode("raw-unicode-escape")
         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():
     test_support.run_unittest(UnicodeTest)
 
diff --git a/Misc/NEWS b/Misc/NEWS
index 3c6b6c1..8d70fce 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,14 @@
 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
   NULL, now raise an AttributeError when attempting to set or delete the
   attribute.  Previously a TypeError was raised, but this was inconsistent
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 875c880..d28006a 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -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);
 }
 
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 539c4a9..55f43cb 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -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;
 }
 
diff --git a/Objects/intobject.c b/Objects/intobject.c
index 763ed53..0ead74b 100644
--- a/Objects/intobject.c
+++ b/Objects/intobject.c
@@ -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;
 }
 
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 11a7024..e4fc553 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -2861,7 +2861,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;
 }
 
diff --git a/Objects/object.c b/Objects/object.c
index d86d74f..975c967 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -373,6 +373,8 @@
 PyObject_Unicode(PyObject *v)
 {
 	PyObject *res;
+	PyObject *func;
+	static PyObject *unicodestr;
 
 	if (v == NULL)
 		res = PyString_FromString("<NULL>");
@@ -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;
 	}
-	if (PyString_Check(v)) {
-		Py_INCREF(v);
-	    	res = v;
-    	}
+	func = PyObject_GetAttr(v, unicodestr);
+	if (func != NULL) {
+		res = PyEval_CallObject(func, (PyObject *)NULL);
+		Py_DECREF(func);
+	}
 	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;
+		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));
 		}
-		func = PyObject_GetAttr(v, unicodestr);
-		if (func != NULL) {
-		    	res = PyEval_CallObject(func, (PyObject *)NULL);
-			Py_DECREF(func);
+		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;
 }