Commit cf52c078 authored by Neil Schemenauer's avatar Neil Schemenauer

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.
parent ba7d95e2
...@@ -371,6 +371,7 @@ PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *); ...@@ -371,6 +371,7 @@ PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
PyAPI_FUNC(void) _PyObject_Dump(PyObject *); PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *);
PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *); PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
#ifdef Py_USING_UNICODE #ifdef Py_USING_UNICODE
PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *); PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *);
......
...@@ -388,6 +388,10 @@ class UnicodeTest( ...@@ -388,6 +388,10 @@ class UnicodeTest(
self.assertEqual('%i %*.*s' % (10, 5,3,u'abc',), u'10 abc') 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('%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')
class Wrapper:
def __str__(self):
return u'\u1234'
self.assertEqual('%s' % Wrapper(), u'\u1234')
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)
......
...@@ -118,6 +118,10 @@ Core and builtins ...@@ -118,6 +118,10 @@ Core and builtins
positions. It once again reports a syntax error if a future positions. It once again reports a syntax error if a future
statement occurs after anything other than a doc string. 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 Extension Modules
----------------- -----------------
......
...@@ -331,22 +331,48 @@ PyObject_Repr(PyObject *v) ...@@ -331,22 +331,48 @@ PyObject_Repr(PyObject *v)
} }
PyObject * PyObject *
PyObject_Str(PyObject *v) _PyObject_Str(PyObject *v)
{ {
PyObject *res; PyObject *res;
int type_ok;
if (v == NULL) if (v == NULL)
return PyString_FromString("<NULL>"); return PyString_FromString("<NULL>");
if (PyString_CheckExact(v)) { if (PyString_CheckExact(v)) {
Py_INCREF(v); Py_INCREF(v);
return v; return v;
} }
#ifdef Py_USING_UNICODE
if (PyUnicode_CheckExact(v)) {
Py_INCREF(v);
return v;
}
#endif
if (v->ob_type->tp_str == NULL) if (v->ob_type->tp_str == NULL)
return PyObject_Repr(v); return PyObject_Repr(v);
res = (*v->ob_type->tp_str)(v); res = (*v->ob_type->tp_str)(v);
if (res == NULL) if (res == NULL)
return 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 #ifdef Py_USING_UNICODE
if (PyUnicode_Check(res)) { if (PyUnicode_Check(res)) {
PyObject* str; PyObject* str;
...@@ -358,13 +384,7 @@ PyObject_Str(PyObject *v) ...@@ -358,13 +384,7 @@ PyObject_Str(PyObject *v)
return NULL; return NULL;
} }
#endif #endif
if (!PyString_Check(res)) { assert(PyString_Check(res));
PyErr_Format(PyExc_TypeError,
"__str__ returned non-string (type %.200s)",
res->ob_type->tp_name);
Py_DECREF(res);
return NULL;
}
return res; return res;
} }
......
...@@ -3853,7 +3853,6 @@ formatchar(char *buf, size_t buflen, PyObject *v) ...@@ -3853,7 +3853,6 @@ formatchar(char *buf, size_t buflen, PyObject *v)
return 1; return 1;
} }
/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
FORMATBUFLEN is the length of the buffer in which the floats, ints, & FORMATBUFLEN is the length of the buffer in which the floats, ints, &
...@@ -4079,7 +4078,9 @@ PyString_Format(PyObject *format, PyObject *args) ...@@ -4079,7 +4078,9 @@ PyString_Format(PyObject *format, PyObject *args)
break; break;
case 's': case 's':
#ifdef Py_USING_UNICODE #ifdef Py_USING_UNICODE
if (PyUnicode_Check(v)) { temp = _PyObject_Str(v);
if (temp != NULL && PyUnicode_Check(temp)) {
Py_DECREF(temp);
fmt = fmt_start; fmt = fmt_start;
argidx = argidx_start; argidx = argidx_start;
goto unicode; goto unicode;
...@@ -4087,16 +4088,11 @@ PyString_Format(PyObject *format, PyObject *args) ...@@ -4087,16 +4088,11 @@ PyString_Format(PyObject *format, PyObject *args)
#endif #endif
/* Fall through */ /* Fall through */
case 'r': case 'r':
if (c == 's') if (c == 'r')
temp = PyObject_Str(v);
else
temp = PyObject_Repr(v); temp = PyObject_Repr(v);
if (temp == NULL) if (temp == NULL)
goto error; goto error;
if (!PyString_Check(temp)) { if (!PyString_Check(temp)) {
/* XXX Note: this should never happen,
since PyObject_Repr() and
PyObject_Str() assure this */
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"%s argument has non-string str()"); "%s argument has non-string str()");
Py_DECREF(temp); Py_DECREF(temp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment