]> granicus.if.org Git - python/commitdiff
Change the %s format specifier for str objects so that it returns a
authorNeil Schemenauer <nascheme@enme.ucalgary.ca>
Fri, 12 Aug 2005 17:34:58 +0000 (17:34 +0000)
committerNeil Schemenauer <nascheme@enme.ucalgary.ca>
Fri, 12 Aug 2005 17:34:58 +0000 (17:34 +0000)
unicode instance if the argument is not an instance of basestring and
calling __str__ on the argument returns a unicode instance.

Include/object.h
Lib/test/test_unicode.py
Misc/NEWS
Objects/object.c
Objects/stringobject.c

index fd7c235cd40e6eac220c9a770f686b1c3b9fb61e..15fee9693d726761e93bdb447fffca9f051f676e 100644 (file)
@@ -371,6 +371,7 @@ PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
 PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
 PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
+PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
 #ifdef Py_USING_UNICODE
 PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *);
index 80242d519921d66513e2cb393905ab99c05e1636..d85f171dbb5b0870364b0792cffa45448a0082e8 100644 (file)
@@ -388,6 +388,10 @@ class UnicodeTest(
         self.assertEqual('%i %*.*s' % (10, 5,3,u'abc',), u'10   abc')
         self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103   abc')
         self.assertEqual('%c' % u'a', u'a')
+        class Wrapper:
+            def __str__(self):
+                return u'\u1234'
+        self.assertEqual('%s' % Wrapper(), u'\u1234')
 
     def test_constructor(self):
         # unicode(obj) tests (this maps to PyObject_Unicode() at C level)
index a1f15abf7de6f588cfc179befbd2f3ec0b0b92ec..ecbbd97e96abdee7d260ea9d5726fc734e2ffe8b 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -118,6 +118,10 @@ Core and builtins
   positions.  It once again reports a syntax error if a future
   statement occurs after anything other than a doc string.
 
+- Change the %s format specifier for str objects so that it returns a
+  unicode instance if the argument is not an instance of basestring and
+  calling __str__ on the argument returns a unicode instance.
+
 Extension Modules
 -----------------
 
index 975c967cca7d220c1463bf59a73840407a6c4e15..189569785039698d670ba0bbfff80c0aebdaccd8 100644 (file)
@@ -331,22 +331,48 @@ PyObject_Repr(PyObject *v)
 }
 
 PyObject *
-PyObject_Str(PyObject *v)
+_PyObject_Str(PyObject *v)
 {
        PyObject *res;
-
+       int type_ok;
        if (v == NULL)
                return PyString_FromString("<NULL>");
        if (PyString_CheckExact(v)) {
                Py_INCREF(v);
                return v;
        }
+#ifdef Py_USING_UNICODE
+       if (PyUnicode_CheckExact(v)) {
+               Py_INCREF(v);
+               return v;
+       }
+#endif
        if (v->ob_type->tp_str == NULL)
                return PyObject_Repr(v);
 
        res = (*v->ob_type->tp_str)(v);
        if (res == NULL)
                return NULL;
+       type_ok = PyString_Check(res);
+#ifdef Py_USING_UNICODE
+       type_ok = type_ok || PyUnicode_Check(res);
+#endif
+       if (!type_ok) {
+               PyErr_Format(PyExc_TypeError,
+                            "__str__ returned non-string (type %.200s)",
+                            res->ob_type->tp_name);
+               Py_DECREF(res);
+               return NULL;
+       }
+       return res;
+}
+
+PyObject *
+PyObject_Str(PyObject *v)
+{
+       PyObject *res = _PyObject_Str(v);
+       if (res == NULL)
+               return NULL;
 #ifdef Py_USING_UNICODE
        if (PyUnicode_Check(res)) {
                PyObject* str;
@@ -358,13 +384,7 @@ PyObject_Str(PyObject *v)
                        return NULL;
        }
 #endif
-       if (!PyString_Check(res)) {
-               PyErr_Format(PyExc_TypeError,
-                            "__str__ returned non-string (type %.200s)",
-                            res->ob_type->tp_name);
-               Py_DECREF(res);
-               return NULL;
-       }
+       assert(PyString_Check(res));
        return res;
 }
 
index 8a9dc529f8b0138733c241b0caa09771a89eb9ab..9bcae0ff2c7a1c8b5b226930f95237f7bda3abb1 100644 (file)
@@ -3853,7 +3853,6 @@ formatchar(char *buf, size_t buflen, PyObject *v)
        return 1;
 }
 
-
 /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
 
    FORMATBUFLEN is the length of the buffer in which the floats, ints, &
@@ -4079,7 +4078,9 @@ PyString_Format(PyObject *format, PyObject *args)
                                break;
                        case 's':
 #ifdef Py_USING_UNICODE
-                               if (PyUnicode_Check(v)) {
+                               temp = _PyObject_Str(v);
+                               if (temp != NULL && PyUnicode_Check(temp)) {
+                                       Py_DECREF(temp);
                                        fmt = fmt_start;
                                        argidx = argidx_start;
                                        goto unicode;
@@ -4087,16 +4088,11 @@ PyString_Format(PyObject *format, PyObject *args)
 #endif
                                /* Fall through */
                        case 'r':
-                               if (c == 's')
-                                       temp = PyObject_Str(v);
-                               else
+                               if (c == 'r')
                                        temp = PyObject_Repr(v);
                                if (temp == NULL)
                                        goto error;
                                if (!PyString_Check(temp)) {
-                                       /* XXX Note: this should never happen,
-                                          since PyObject_Repr() and
-                                          PyObject_Str() assure this */
                                        PyErr_SetString(PyExc_TypeError,
                                          "%s argument has non-string str()");
                                        Py_DECREF(temp);