Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cf52c07

Browse files
committed
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.
1 parent ba7d95e commit cf52c07

5 files changed

Lines changed: 42 additions & 17 deletions

File tree

Include/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
371371
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
372372
PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
373373
PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
374+
PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *);
374375
PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
375376
#ifdef Py_USING_UNICODE
376377
PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *);

Lib/test/test_unicode.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ def test_formatting(self):
388388
self.assertEqual('%i %*.*s' % (10, 5,3,u'abc',), u'10 abc')
389389
self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103 abc')
390390
self.assertEqual('%c' % u'a', u'a')
391+
class Wrapper:
392+
def __str__(self):
393+
return u'\u1234'
394+
self.assertEqual('%s' % Wrapper(), u'\u1234')
391395

392396
def test_constructor(self):
393397
# unicode(obj) tests (this maps to PyObject_Unicode() at C level)

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ Core and builtins
118118
positions. It once again reports a syntax error if a future
119119
statement occurs after anything other than a doc string.
120120

121+
- Change the %s format specifier for str objects so that it returns a
122+
unicode instance if the argument is not an instance of basestring and
123+
calling __str__ on the argument returns a unicode instance.
124+
121125
Extension Modules
122126
-----------------
123127

Objects/object.c

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -331,22 +331,48 @@ PyObject_Repr(PyObject *v)
331331
}
332332

333333
PyObject *
334-
PyObject_Str(PyObject *v)
334+
_PyObject_Str(PyObject *v)
335335
{
336336
PyObject *res;
337-
337+
int type_ok;
338338
if (v == NULL)
339339
return PyString_FromString("<NULL>");
340340
if (PyString_CheckExact(v)) {
341341
Py_INCREF(v);
342342
return v;
343343
}
344+
#ifdef Py_USING_UNICODE
345+
if (PyUnicode_CheckExact(v)) {
346+
Py_INCREF(v);
347+
return v;
348+
}
349+
#endif
344350
if (v->ob_type->tp_str == NULL)
345351
return PyObject_Repr(v);
346352

347353
res = (*v->ob_type->tp_str)(v);
348354
if (res == NULL)
349355
return NULL;
356+
type_ok = PyString_Check(res);
357+
#ifdef Py_USING_UNICODE
358+
type_ok = type_ok || PyUnicode_Check(res);
359+
#endif
360+
if (!type_ok) {
361+
PyErr_Format(PyExc_TypeError,
362+
"__str__ returned non-string (type %.200s)",
363+
res->ob_type->tp_name);
364+
Py_DECREF(res);
365+
return NULL;
366+
}
367+
return res;
368+
}
369+
370+
PyObject *
371+
PyObject_Str(PyObject *v)
372+
{
373+
PyObject *res = _PyObject_Str(v);
374+
if (res == NULL)
375+
return NULL;
350376
#ifdef Py_USING_UNICODE
351377
if (PyUnicode_Check(res)) {
352378
PyObject* str;
@@ -358,13 +384,7 @@ PyObject_Str(PyObject *v)
358384
return NULL;
359385
}
360386
#endif
361-
if (!PyString_Check(res)) {
362-
PyErr_Format(PyExc_TypeError,
363-
"__str__ returned non-string (type %.200s)",
364-
res->ob_type->tp_name);
365-
Py_DECREF(res);
366-
return NULL;
367-
}
387+
assert(PyString_Check(res));
368388
return res;
369389
}
370390

Objects/stringobject.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3853,7 +3853,6 @@ formatchar(char *buf, size_t buflen, PyObject *v)
38533853
return 1;
38543854
}
38553855

3856-
38573856
/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
38583857
38593858
FORMATBUFLEN is the length of the buffer in which the floats, ints, &
@@ -4079,24 +4078,21 @@ PyString_Format(PyObject *format, PyObject *args)
40794078
break;
40804079
case 's':
40814080
#ifdef Py_USING_UNICODE
4082-
if (PyUnicode_Check(v)) {
4081+
temp = _PyObject_Str(v);
4082+
if (temp != NULL && PyUnicode_Check(temp)) {
4083+
Py_DECREF(temp);
40834084
fmt = fmt_start;
40844085
argidx = argidx_start;
40854086
goto unicode;
40864087
}
40874088
#endif
40884089
/* Fall through */
40894090
case 'r':
4090-
if (c == 's')
4091-
temp = PyObject_Str(v);
4092-
else
4091+
if (c == 'r')
40934092
temp = PyObject_Repr(v);
40944093
if (temp == NULL)
40954094
goto error;
40964095
if (!PyString_Check(temp)) {
4097-
/* XXX Note: this should never happen,
4098-
since PyObject_Repr() and
4099-
PyObject_Str() assure this */
41004096
PyErr_SetString(PyExc_TypeError,
41014097
"%s argument has non-string str()");
41024098
Py_DECREF(temp);

0 commit comments

Comments
 (0)