Commit 13d73fc6 authored by Marius Wachtler's avatar Marius Wachtler

Add suport for str.format(C) where C is a custom class without a __format__ method

parent 035b313f
......@@ -364,3 +364,31 @@ PyObject *string_join(PyStringObject *self, PyObject *orig)
Py_DECREF(seq);
return res;
}
PyObject* string__format__(PyObject* self, PyObject* args)
{
PyObject *format_spec;
PyObject *result = NULL;
PyObject *tmp = NULL;
/* If 2.x, convert format_spec to the same type as value */
/* This is to allow things like u''.format('') */
if (!PyArg_ParseTuple(args, "O:__format__", &format_spec))
goto done;
if (!(PyString_Check(format_spec) || PyUnicode_Check(format_spec))) {
PyErr_Format(PyExc_TypeError, "__format__ arg must be str "
"or unicode, not %s", Py_TYPE(format_spec)->tp_name);
goto done;
}
tmp = PyObject_Str(format_spec);
if (tmp == NULL)
goto done;
format_spec = tmp;
result = _PyBytes_FormatAdvanced(self,
PyString_AS_STRING(format_spec),
PyString_GET_SIZE(format_spec));
done:
Py_XDECREF(tmp);
return result;
}
......@@ -44,6 +44,7 @@ extern "C" PyObject* string_index(PyStringObject* self, PyObject* args) noexcept
extern "C" PyObject* string_rindex(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_rfind(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_splitlines(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string__format__(PyObject* self, PyObject* args) noexcept;
// from cpython's stringobject.c:
#define LEFTSTRIP 0
......@@ -2653,6 +2654,7 @@ static PyMethodDef string_methods[] = {
{ "expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS, NULL },
{ "splitlines", (PyCFunction)string_splitlines, METH_VARARGS, NULL },
{ "zfill", (PyCFunction)string_zfill, METH_VARARGS, NULL },
{ "__format__", (PyCFunction)string__format__, METH_VARARGS, NULL },
};
void setupStr() {
......
......@@ -1997,6 +1997,63 @@ static PyObject* object_reduce_ex(PyObject* self, PyObject* args) noexcept {
return _common_reduce(self, proto);
}
/*
from PEP 3101, this code implements:
class object:
def __format__(self, format_spec):
if isinstance(format_spec, str):
return format(str(self), format_spec)
elif isinstance(format_spec, unicode):
return format(unicode(self), format_spec)
*/
static PyObject* object_format(PyObject* self, PyObject* args) noexcept {
PyObject* format_spec;
PyObject* self_as_str = NULL;
PyObject* result = NULL;
Py_ssize_t format_len;
if (!PyArg_ParseTuple(args, "O:__format__", &format_spec))
return NULL;
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(format_spec)) {
format_len = PyUnicode_GET_SIZE(format_spec);
self_as_str = PyObject_Unicode(self);
} else if (PyString_Check(format_spec)) {
#else
if (PyString_Check(format_spec)) {
#endif
format_len = PyString_GET_SIZE(format_spec);
self_as_str = PyObject_Str(self);
} else {
PyErr_SetString(PyExc_TypeError, "argument to __format__ must be unicode or str");
return NULL;
}
if (self_as_str != NULL) {
/* Issue 7994: If we're converting to a string, we
should reject format specifications */
if (format_len > 0) {
if (PyErr_WarnEx(PyExc_PendingDeprecationWarning, "object.__format__ with a non-empty format "
"string is deprecated",
1) < 0) {
goto done;
}
/* Eventually this will become an error:
PyErr_Format(PyExc_TypeError,
"non-empty format string passed to object.__format__");
goto done;
*/
}
result = PyObject_Format(self_as_str, format_spec);
}
done:
Py_XDECREF(self_as_str);
return result;
}
static Box* objectClass(Box* obj, void* context) {
assert(obj->cls != instance_cls); // should override __class__ in classobj
return obj->cls;
......@@ -2041,6 +2098,7 @@ static void objectSetClass(Box* obj, Box* val, void* context) {
static PyMethodDef object_methods[] = {
{ "__reduce_ex__", object_reduce_ex, METH_VARARGS, NULL }, //
{ "__reduce__", object_reduce, METH_VARARGS, NULL }, //
{ "__format__", object_format, METH_VARARGS, PyDoc_STR("default object formatter") },
};
static Box* typeName(Box* b, void*) {
......
......@@ -168,3 +168,8 @@ it = iter("hello world")
print list(it)
print "'{0}' '{1}'".format("Hello " * 3, "Hello " * -3)
class C(object):
def __str__(self):
return "my class"
print "{0}".format(C())
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