Fixes for shared 2.6 code that implements PEP 3101, advanced string

formatting.

Includes:
 - Modifying tests for basic types to use __format__ methods, instead
   of builtin "format".
 - Adding PyObject_Format.
 - General str/unicode cleanup discovered when backporting to 2.6.
 - Removing datetimemodule.c's time_format, since it was identical
   to date_format.

The files in Objects/stringlib that implement PEP 3101 (stringdefs.h,
unicodedefs.h, formatter.h, string_format.h) are identical in trunk
and py3k.  Any changes from here on should be made to trunk, and
changes will propogate to py3k).
This commit is contained in:
Eric Smith 2008-02-17 19:48:00 +00:00
parent 18c66898b0
commit 8fd3eba050
10 changed files with 330 additions and 256 deletions

View file

@ -611,6 +611,13 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
*/
PyAPI_FUNC(PyObject *) PyObject_Format(PyObject* obj,
PyObject *format_spec);
/*
Takes an arbitrary object and returns the result of
calling obj.__format__(format_spec).
*/
/* Iterators */
PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *);

View file

@ -541,24 +541,58 @@ def __float__(self):
self.assertRaises(TypeError, float, Foo4(42))
def test_format(self):
class A:
def __init__(self, x):
self.x = x
def __format__(self, format_spec):
return str(self.x) + format_spec
# class that returns a bad type from __format__
class B:
def __format__(self, format_spec):
return 1.0
# class that is derived from string, used
# as a format spec
class C(str):
pass
# Test the basic machinery of the format() builtin. Don't test
# the specifics of the various formatters
self.assertEqual(format(3, ''), '3')
self.assertEqual(format(A(3), 'spec'), '3spec')
# Returns some classes to use for various tests. There's
# an old-style version, and a new-style version
def classes_new():
class A(object):
def __init__(self, x):
self.x = x
def __format__(self, format_spec):
return str(self.x) + format_spec
class DerivedFromA(A):
pass
class Simple(object): pass
class DerivedFromSimple(Simple):
def __init__(self, x):
self.x = x
def __format__(self, format_spec):
return str(self.x) + format_spec
class DerivedFromSimple2(DerivedFromSimple): pass
return A, DerivedFromA, DerivedFromSimple, DerivedFromSimple2
# In 3.0, classes_classic has the same meaning as classes_new
def classes_classic():
class A:
def __init__(self, x):
self.x = x
def __format__(self, format_spec):
return str(self.x) + format_spec
class DerivedFromA(A):
pass
class Simple: pass
class DerivedFromSimple(Simple):
def __init__(self, x):
self.x = x
def __format__(self, format_spec):
return str(self.x) + format_spec
class DerivedFromSimple2(DerivedFromSimple): pass
return A, DerivedFromA, DerivedFromSimple, DerivedFromSimple2
def class_test(A, DerivedFromA, DerivedFromSimple, DerivedFromSimple2):
self.assertEqual(format(A(3), 'spec'), '3spec')
self.assertEqual(format(DerivedFromA(4), 'spec'), '4spec')
self.assertEqual(format(DerivedFromSimple(5), 'abc'), '5abc')
self.assertEqual(format(DerivedFromSimple2(10), 'abcdef'),
'10abcdef')
class_test(*classes_new())
class_test(*classes_classic())
def empty_format_spec(value):
# test that:
@ -578,19 +612,28 @@ def empty_format_spec(value):
empty_format_spec(None)
# TypeError because self.__format__ returns the wrong type
self.assertRaises(TypeError, format, B(), "")
class BadFormatResult:
def __format__(self, format_spec):
return 1.0
self.assertRaises(TypeError, format, BadFormatResult(), "")
# TypeError because format_spec is not unicode
# TypeError because format_spec is not unicode or str
self.assertRaises(TypeError, format, object(), 4)
self.assertRaises(TypeError, format, object(), object())
# tests for object.__format__ really belong elsewhere, but
# there's no good place to put them
x = object().__format__('')
self.assert_(x.startswith('<object object at'))
# first argument to object.__format__ must be string
self.assertRaises(TypeError, object().__format__, 3)
self.assertRaises(TypeError, object().__format__, object())
self.assertRaises(TypeError, object().__format__, None)
# make sure we can take a subclass of str as a format spec
self.assertEqual(format(0, C('10')), ' 0')
class DerivedFromStr(str): pass
self.assertEqual(format(0, DerivedFromStr('10')), ' 0')
def test_floatasratio(self):
for f, ratio in [

View file

@ -851,29 +851,29 @@ def test_strftime(self):
def test_format(self):
dt = self.theclass(2007, 9, 10)
self.assertEqual(format(dt, ''), str(dt))
self.assertEqual(dt.__format__(''), str(dt))
# check that a derived class's __str__() gets called
class A(self.theclass):
def __str__(self):
return 'A'
a = A(2007, 9, 10)
self.assertEqual(format(a, ''), 'A')
self.assertEqual(a.__format__(''), 'A')
# check that a derived class's strftime gets called
class B(self.theclass):
def strftime(self, format_spec):
return 'B'
b = B(2007, 9, 10)
self.assertEqual(format(b, ''), str(dt))
self.assertEqual(b.__format__(''), str(dt))
for fmt in ["m:%m d:%d y:%y",
"m:%m d:%d y:%y H:%H M:%M S:%S",
"%z %Z",
]:
self.assertEqual(format(dt, fmt), dt.strftime(fmt))
self.assertEqual(format(a, fmt), dt.strftime(fmt))
self.assertEqual(format(b, fmt), 'B')
self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
self.assertEqual(b.__format__(fmt), 'B')
def test_resolution_info(self):
self.assert_(isinstance(self.theclass.min, self.theclass))
@ -1178,31 +1178,29 @@ def test_isoformat(self):
def test_format(self):
dt = self.theclass(2007, 9, 10, 4, 5, 1, 123)
self.assertEqual(format(dt, ''), str(dt))
self.assertEqual(dt.__format__(''), str(dt))
# check that a derived class's __str__() gets called
class A(self.theclass):
def __str__(self):
return 'A'
a = A(2007, 9, 10, 4, 5, 1, 123)
self.assertEqual(format(a, ''), 'A')
self.assertEqual(a.__format__(''), 'A')
# check that a derived class's strftime gets called
class B(self.theclass):
def strftime(self, format_spec):
return 'B'
b = B(2007, 9, 10, 4, 5, 1, 123)
self.assertEqual(format(b, ''), str(dt))
self.assertEqual(b.__format__(''), str(dt))
for fmt in ["m:%m d:%d y:%y",
"m:%m d:%d y:%y H:%H M:%M S:%S",
"%z %Z",
]:
self.assertEqual(format(dt, fmt), dt.strftime(fmt))
self.assertEqual(format(a, fmt), dt.strftime(fmt))
self.assertEqual(format(b, fmt), 'B')
self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
self.assertEqual(b.__format__(fmt), 'B')
def test_more_ctime(self):
# Test fields that TestDate doesn't touch.
@ -1837,27 +1835,27 @@ def test_strftime(self):
def test_format(self):
t = self.theclass(1, 2, 3, 4)
self.assertEqual(format(t, ''), str(t))
self.assertEqual(t.__format__(''), str(t))
# check that a derived class's __str__() gets called
class A(self.theclass):
def __str__(self):
return 'A'
a = A(1, 2, 3, 4)
self.assertEqual(format(a, ''), 'A')
self.assertEqual(a.__format__(''), 'A')
# check that a derived class's strftime gets called
class B(self.theclass):
def strftime(self, format_spec):
return 'B'
b = B(1, 2, 3, 4)
self.assertEqual(format(b, ''), str(t))
self.assertEqual(b.__format__(''), str(t))
for fmt in ['%H %M %S',
]:
self.assertEqual(format(t, fmt), t.strftime(fmt))
self.assertEqual(format(a, fmt), t.strftime(fmt))
self.assertEqual(format(b, fmt), 'B')
self.assertEqual(t.__format__(fmt), t.strftime(fmt))
self.assertEqual(a.__format__(fmt), t.strftime(fmt))
self.assertEqual(b.__format__(fmt), 'B')
def test_str(self):
self.assertEqual(str(self.theclass(1, 2, 3, 4)), "01:02:03.000004")

View file

@ -3210,21 +3210,6 @@ time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw)
return result;
}
static PyObject *
time_format(PyDateTime_Time *self, PyObject *args)
{
PyObject *format;
if (!PyArg_ParseTuple(args, "U:__format__", &format))
return NULL;
/* if the format is zero length, return str(self) */
if (PyUnicode_GetSize(format) == 0)
return PyObject_Str((PyObject *)self);
return PyObject_CallMethod((PyObject *)self, "strftime", "O", format);
}
/*
* Miscellaneous methods.
*/
@ -3412,7 +3397,7 @@ static PyMethodDef time_methods[] = {
{"strftime", (PyCFunction)time_strftime, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("format -> strftime() style string.")},
{"__format__", (PyCFunction)time_format, METH_VARARGS,
{"__format__", (PyCFunction)date_format, METH_VARARGS,
PyDoc_STR("Formats self with strftime.")},
{"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS,

View file

@ -704,6 +704,57 @@ PyBuffer_FillInfo(Py_buffer *view, void *buf, Py_ssize_t len,
return 0;
}
PyObject *
PyObject_Format(PyObject *obj, PyObject *format_spec)
{
static PyObject * str__format__ = NULL;
PyObject *meth;
PyObject *empty = NULL;
PyObject *result = NULL;
/* Initialize cached value */
if (str__format__ == NULL) {
/* Initialize static variable needed by _PyType_Lookup */
str__format__ = PyUnicode_FromString("__format__");
if (str__format__ == NULL)
goto done;
}
/* If no format_spec is provided, use an empty string */
if (format_spec == NULL) {
empty = PyUnicode_FromUnicode(NULL, 0);
format_spec = empty;
}
/* Make sure the type is initialized. float gets initialized late */
if (Py_TYPE(obj)->tp_dict == NULL)
if (PyType_Ready(Py_TYPE(obj)) < 0)
goto done;
/* Find the (unbound!) __format__ method (a borrowed reference) */
meth = _PyType_Lookup(Py_TYPE(obj), str__format__);
if (meth == NULL) {
PyErr_Format(PyExc_TypeError,
"Type %.100s doesn't define __format__",
Py_TYPE(obj)->tp_name);
goto done;
}
/* And call it, binding it to the value */
result = PyObject_CallFunctionObjArgs(meth, obj, format_spec, NULL);
if (result && !PyUnicode_Check(result)) {
PyErr_SetString(PyExc_TypeError,
"__format__ method did not return string");
Py_DECREF(result);
result = NULL;
goto done;
}
done:
Py_XDECREF(empty);
return result;
}
/* Operations on numbers */
int

View file

@ -195,7 +195,7 @@ parse_internal_render_format_spec(PyObject *format_spec,
return 1;
}
#if defined FORMAT_FLOAT || defined FORMAT_LONG
/************************************************************************/
/*********** common routines for numeric formatting *********************/
/************************************************************************/
@ -288,7 +288,8 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
else {
/* determine which of left, space, or right padding is
needed */
Py_ssize_t padding = format->width - (r->n_lsign + n_digits + r->n_rsign);
Py_ssize_t padding = format->width -
(r->n_lsign + n_digits + r->n_rsign);
if (format->align == '<')
r->n_rpadding = padding;
else if (format->align == '>')
@ -338,6 +339,7 @@ fill_number(STRINGLIB_CHAR *p_buf, const NumberFieldWidths *spec,
}
return p_digits;
}
#endif /* FORMAT_FLOAT || FORMAT_LONG */
/************************************************************************/
/*********** string formatting ******************************************/
@ -434,18 +436,23 @@ format_string_internal(PyObject *value, const InternalFormatSpec *format)
/*********** long formatting ********************************************/
/************************************************************************/
#if defined FORMAT_LONG || defined FORMAT_INT
typedef PyObject*
(*IntOrLongToString)(PyObject *value, int base);
static PyObject *
format_long_internal(PyObject *value, const InternalFormatSpec *format)
format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
IntOrLongToString tostring)
{
PyObject *result = NULL;
int total_leading_chars_to_skip = 0; /* also includes sign, if
present */
PyObject *tmp = NULL;
STRINGLIB_CHAR *pnumeric_chars;
STRINGLIB_CHAR numeric_char;
STRINGLIB_CHAR sign = '\0';
STRINGLIB_CHAR *p;
Py_ssize_t n_digits; /* count of digits need from the computed
string */
Py_ssize_t len;
Py_ssize_t tmp;
Py_ssize_t n_leading_chars;
NumberFieldWidths spec;
long x;
@ -469,6 +476,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format)
/* taken from unicodeobject.c formatchar() */
/* Integer input truncated to a character */
/* XXX: won't work for int */
x = PyLong_AsLong(value);
if (x == -1 && PyErr_Occurred())
goto done;
@ -487,115 +495,101 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format)
goto done;
}
#endif
result = STRINGLIB_NEW(NULL, 1);
if (result == NULL)
goto done;
p = STRINGLIB_STR(result);
p[0] = (Py_UNICODE) x;
n_digits = len = 1;
numeric_char = (STRINGLIB_CHAR)x;
pnumeric_chars = &numeric_char;
n_digits = 1;
}
else {
int base;
int format_leading_chars_to_skip; /* characters added by
PyNumber_ToBase that we
want to skip over.
instead of using them,
we'll compute our
own. */
/* compute the base and how many characters will be added by
int leading_chars_to_skip; /* Number of characters added by
PyNumber_ToBase that we want to
skip over. */
/* Compute the base and how many characters will be added by
PyNumber_ToBase */
switch (format->type) {
case 'b':
base = 2;
format_leading_chars_to_skip = 2; /* 0b */
leading_chars_to_skip = 2; /* 0b */
break;
case 'o':
base = 8;
format_leading_chars_to_skip = 2; /* 0o */
leading_chars_to_skip = 2; /* 0o */
break;
case 'x':
case 'X':
base = 16;
format_leading_chars_to_skip = 2; /* 0x */
leading_chars_to_skip = 2; /* 0x */
break;
default: /* shouldn't be needed, but stops a compiler warning */
case 'd':
base = 10;
format_leading_chars_to_skip = 0;
leading_chars_to_skip = 0;
break;
}
/* do the hard part, converting to a string in a given base */
result = PyNumber_ToBase(value, base);
if (result == NULL)
/* Do the hard part, converting to a string in a given base */
tmp = tostring(value, base);
if (tmp == NULL)
goto done;
n_digits = STRINGLIB_LEN(result);
len = n_digits;
p = STRINGLIB_STR(result);
pnumeric_chars = STRINGLIB_STR(tmp);
n_digits = STRINGLIB_LEN(tmp);
/* if X, convert to uppercase */
if (format->type == 'X')
for (tmp = 0; tmp < len; tmp++)
p[tmp] = STRINGLIB_TOUPPER(p[tmp]);
/* Remember not to modify what pnumeric_chars points to. it
might be interned. Only modify it after we copy it into a
newly allocated output buffer. */
/* is a sign character present in the output? if so, remember it
/* Is a sign character present in the output? If so, remember it
and skip it */
sign = p[0];
sign = pnumeric_chars[0];
if (sign == '-') {
total_leading_chars_to_skip += 1;
n_digits--;
++leading_chars_to_skip;
}
/* skip over the leading digits (0x, 0b, etc.) */
assert(n_digits >= format_leading_chars_to_skip + 1);
n_digits -= format_leading_chars_to_skip;
total_leading_chars_to_skip += format_leading_chars_to_skip;
/* Skip over the leading chars (0x, 0b, etc.) */
n_digits -= leading_chars_to_skip;
pnumeric_chars += leading_chars_to_skip;
}
/* Calculate the widths of the various leading and trailing parts */
calc_number_widths(&spec, sign, n_digits, format);
/* if the buffer is getting bigger, realloc it. if it's getting
smaller, don't realloc because we need to move the results
around first. realloc after we've done that */
/* Allocate a new string to hold the result */
result = STRINGLIB_NEW(NULL, spec.n_total);
if (!result)
goto done;
p = STRINGLIB_STR(result);
if (spec.n_total > len) {
if (STRINGLIB_RESIZE(&result, spec.n_total) < 0)
goto done;
/* recalc, because string might have moved */
p = STRINGLIB_STR(result);
/* Fill in the digit parts */
n_leading_chars = spec.n_lpadding + spec.n_lsign + spec.n_spadding;
memmove(p + n_leading_chars,
pnumeric_chars,
n_digits * sizeof(STRINGLIB_CHAR));
/* if X, convert to uppercase */
if (format->type == 'X') {
Py_ssize_t t;
for (t = 0; t < n_digits; t++)
p[t + n_leading_chars] = STRINGLIB_TOUPPER(p[t + n_leading_chars]);
}
/* copy the characters into position first, since we're going to
overwrite some of that space */
/* we need to move if the number of left padding in the output is
different from the number of characters we need to skip */
if ((spec.n_lpadding + spec.n_lsign + spec.n_spadding) !=
total_leading_chars_to_skip) {
memmove(p + (spec.n_lpadding + spec.n_lsign + spec.n_spadding),
p + total_leading_chars_to_skip,
n_digits * sizeof(STRINGLIB_CHAR));
}
/* now fill in the non-digit parts */
/* Fill in the non-digit parts */
fill_number(p, &spec, n_digits,
format->fill_char == '\0' ? ' ' : format->fill_char);
/* if we're getting smaller, realloc now */
if (spec.n_total < len) {
if (STRINGLIB_RESIZE(&result, spec.n_total) < 0)
goto done;
}
done:
Py_XDECREF(tmp);
return result;
}
#endif /* defined FORMAT_LONG || defined FORMAT_INT */
/************************************************************************/
/*********** float formatting *******************************************/
/************************************************************************/
#ifdef FORMAT_FLOAT
#if STRINGLIB_IS_UNICODE
/* taken from unicodeobject.c */
static Py_ssize_t
strtounicode(Py_UNICODE *buffer, const char *charbuffer)
@ -607,6 +601,7 @@ strtounicode(Py_UNICODE *buffer, const char *charbuffer)
return len;
}
#endif
/* the callback function to call to do the actual float formatting.
it matches the definition of PyOS_ascii_formatd */
@ -694,7 +689,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value,
/* cast "type", because if we're in unicode we need to pass a
8-bit char. this is safe, because we've restricted what "type"
can be */
PyOS_snprintf(fmt, sizeof(fmt), "%%.%" PY_FORMAT_SIZE_T "d%c", precision, (char)type);
PyOS_snprintf(fmt, sizeof(fmt), "%%.%" PY_FORMAT_SIZE_T "d%c", precision,
(char)type);
/* call the passed in function to do the actual formatting */
snprintf(charbuf, sizeof(charbuf), fmt, x);
@ -739,7 +735,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value,
format->fill_char == '\0' ? ' ' : format->fill_char);
/* fill in the digit parts */
memmove(STRINGLIB_STR(result) + (spec.n_lpadding + spec.n_lsign + spec.n_spadding),
memmove(STRINGLIB_STR(result) +
(spec.n_lpadding + spec.n_lsign + spec.n_spadding),
p,
n_digits * sizeof(STRINGLIB_CHAR));
@ -755,20 +752,43 @@ format_float_internal(PyObject *value, const InternalFormatSpec *format)
else
return _format_float(format->type, value, format, PyOS_ascii_formatd);
}
#endif /* FORMAT_FLOAT */
/************************************************************************/
/*********** built in formatters ****************************************/
/************************************************************************/
#ifdef FORMAT_STRING
PyObject *
FORMAT_STRING(PyObject* value, PyObject* args)
{
PyObject *format_spec;
PyObject *result = NULL;
#if PY_VERSION_HEX < 0x03000000
PyObject *tmp = NULL;
#endif
InternalFormatSpec format;
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", &format_spec))
/* If 2.x, we accept either str or unicode, and try to convert it
to the right type. In 3.x, we insist on only unicode */
#if PY_VERSION_HEX >= 0x03000000
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__",
&format_spec))
goto done;
#else
/* 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 = STRINGLIB_TOSTR(format_spec);
if (tmp == NULL)
goto done;
format_spec = tmp;
#endif
/* check for the special case of zero length format spec, make
it equivalent to str(value) */
@ -777,6 +797,7 @@ FORMAT_STRING(PyObject* value, PyObject* args)
goto done;
}
/* parse the format_spec */
if (!parse_internal_render_format_spec(format_spec, &format, 's'))
goto done;
@ -795,18 +816,24 @@ FORMAT_STRING(PyObject* value, PyObject* args)
}
done:
#if PY_VERSION_HEX < 0x03000000
Py_XDECREF(tmp);
#endif
return result;
}
#endif /* FORMAT_STRING */
PyObject *
FORMAT_LONG(PyObject* value, PyObject* args)
#if defined FORMAT_LONG || defined FORMAT_INT
static PyObject*
format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring)
{
PyObject *format_spec;
PyObject *result = NULL;
PyObject *tmp = NULL;
InternalFormatSpec format;
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", &format_spec))
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__",
&format_spec))
goto done;
/* check for the special case of zero length format spec, make
@ -828,8 +855,9 @@ FORMAT_LONG(PyObject* value, PyObject* args)
case 'o':
case 'x':
case 'X':
/* no type conversion needed, already an int. do the formatting */
result = format_long_internal(value, &format);
/* no type conversion needed, already an int (or long). do
the formatting */
result = format_int_or_long_internal(value, &format, tostring);
break;
case 'e':
@ -858,7 +886,52 @@ FORMAT_LONG(PyObject* value, PyObject* args)
Py_XDECREF(tmp);
return result;
}
#endif /* FORMAT_LONG || defined FORMAT_INT */
#ifdef FORMAT_LONG
/* Need to define long_format as a function that will convert a long
to a string. In 3.0, _PyLong_Format has the correct signature. In
2.x, we need to fudge a few parameters */
#if PY_VERSION_HEX >= 0x03000000
#define long_format _PyLong_Format
#else
static PyObject*
long_format(PyObject* value, int base)
{
/* Convert to base, don't add trailing 'L', and use the new octal
format. We already know this is a long object */
assert(PyLong_Check(value));
/* convert to base, don't add 'L', and use the new octal format */
return _PyLong_Format(value, base, 0, 1);
}
#endif
PyObject *
FORMAT_LONG(PyObject* value, PyObject* args)
{
return format_int_or_long(value, args, long_format);
}
#endif /* FORMAT_LONG */
#ifdef FORMAT_INT
/* this is only used for 2.x, not 3.0 */
static PyObject*
int_format(PyObject* value, int base)
{
/* Convert to base, and use the new octal format. We already
know this is an int object */
assert(PyInt_Check(value));
return _PyInt_Format((PyIntObject*)value, base, 1);
}
PyObject *
FORMAT_INT(PyObject* value, PyObject* args)
{
return format_int_or_long(value, args, int_format);
}
#endif /* FORMAT_INT */
#ifdef FORMAT_FLOAT
PyObject *
FORMAT_FLOAT(PyObject *value, PyObject *args)
{
@ -904,3 +977,4 @@ FORMAT_FLOAT(PyObject *value, PyObject *args)
done:
return result;
}
#endif /* FORMAT_FLOAT */

View file

@ -6,6 +6,11 @@
*/
/* Defines for Python 2.6 compatability */
#if PY_VERSION_HEX < 0x03000000
#define PyLong_FromSsize_t _PyLong_FromSsize_t
#endif
/* Defines for more efficiently reallocating the string buffer */
#define INITIAL_SIZE_INCREMENT 100
#define SIZE_MULTIPLIER 2
@ -470,66 +475,6 @@ get_field_object(SubString *input, PyObject *args, PyObject *kwargs)
field object and field specification string generated by
get_field_and_spec, and renders the field into the output string.
format() does the actual calling of the objects __format__ method.
*/
/* returns fieldobj.__format__(format_spec) */
static PyObject *
format(PyObject *fieldobj, SubString *format_spec)
{
static PyObject *format_str = NULL;
PyObject *meth;
PyObject *spec = NULL;
PyObject *result = NULL;
/* Initialize cached value */
if (format_str == NULL) {
/* Initialize static variable needed by _PyType_Lookup */
format_str = PyUnicode_FromString("__format__");
if (format_str == NULL)
return NULL;
}
/* Make sure the type is initialized. float gets initialized late */
if (Py_TYPE(fieldobj)->tp_dict == NULL)
if (PyType_Ready(Py_TYPE(fieldobj)) < 0)
return NULL;
/* we need to create an object out of the pointers we have */
spec = SubString_new_object_or_empty(format_spec);
if (spec == NULL)
goto done;
/* Find the (unbound!) __format__ method (a borrowed reference) */
meth = _PyType_Lookup(Py_TYPE(fieldobj), format_str);
if (meth == NULL) {
PyErr_Format(PyExc_TypeError,
"Type %.100s doesn't define __format__",
Py_TYPE(fieldobj)->tp_name);
goto done;
}
/* And call it, binding it to the value */
result = PyObject_CallFunctionObjArgs(meth, fieldobj, spec, NULL);
if (result == NULL)
goto done;
if (!STRINGLIB_CHECK(result)) {
PyErr_SetString(PyExc_TypeError,
"__format__ method did not return "
STRINGLIB_TYPE_NAME);
Py_DECREF(result);
result = NULL;
goto done;
}
done:
Py_XDECREF(spec);
return result;
}
/*
render_field calls fieldobj.__format__(format_spec) method, and
appends to the output.
*/
@ -537,14 +482,21 @@ static int
render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output)
{
int ok = 0;
PyObject *result = format(fieldobj, format_spec);
PyObject *result = NULL;
/* we need to create an object out of the pointers we have */
PyObject *format_spec_object = SubString_new_object_or_empty(format_spec);
if (format_spec_object == NULL)
goto done;
result = PyObject_Format(fieldobj, format_spec_object);
if (result == NULL)
goto done;
ok = output_data(output,
STRINGLIB_STR(result), STRINGLIB_LEN(result));
done:
Py_DECREF(format_spec_object);
Py_XDECREF(result);
return ok;
}
@ -770,7 +722,7 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion)
case 'r':
return PyObject_Repr(obj);
case 's':
return PyObject_Str(obj);
return STRINGLIB_TOSTR(obj);
default:
PyErr_Format(PyExc_ValueError,
"Unknown converion specifier %c",
@ -845,7 +797,7 @@ output_markup(SubString *field_name, SubString *format_spec,
}
/*
do_markup is the top-level loop for the format() function. It
do_markup is the top-level loop for the format() method. It
searches through the format string for escapes to markup codes, and
calls other functions to move non-markup text to the output,
and to perform the markup to the output.
@ -958,7 +910,7 @@ do_string_format(PyObject *self, PyObject *args, PyObject *kwargs)
typedef struct {
PyObject_HEAD
PyUnicodeObject *str;
STRINGLIB_OBJECT *str;
MarkupIterator it_markup;
} formatteriterobject;
@ -984,7 +936,7 @@ formatteriter_next(formatteriterobject *it)
SubString literal;
SubString field_name;
SubString format_spec;
Py_UNICODE conversion;
STRINGLIB_CHAR conversion;
int format_spec_needs_expanding;
int result = MarkupIterator_next(&it->it_markup, &literal, &field_name,
&format_spec, &conversion,
@ -1028,7 +980,7 @@ formatteriter_next(formatteriterobject *it)
Py_INCREF(conversion_str);
}
else
conversion_str = PyUnicode_FromUnicode(&conversion, 1);
conversion_str = STRINGLIB_NEW(&conversion, 1);
if (conversion_str == NULL)
goto done;
@ -1047,7 +999,7 @@ static PyMethodDef formatteriter_methods[] = {
{NULL, NULL} /* sentinel */
};
PyTypeObject PyFormatterIter_Type = {
static PyTypeObject PyFormatterIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"formatteriterator", /* tp_name */
sizeof(formatteriterobject), /* tp_basicsize */
@ -1085,7 +1037,7 @@ PyTypeObject PyFormatterIter_Type = {
describing the parsed elements. It's a wrapper around
stringlib/string_format.h's MarkupIterator */
static PyObject *
formatter_parser(PyUnicodeObject *self)
formatter_parser(STRINGLIB_OBJECT *self)
{
formatteriterobject *it;
@ -1099,8 +1051,8 @@ formatter_parser(PyUnicodeObject *self)
/* initialize the contained MarkupIterator */
MarkupIterator_init(&it->it_markup,
PyUnicode_AS_UNICODE(self),
PyUnicode_GET_SIZE(self));
STRINGLIB_STR(self),
STRINGLIB_LEN(self));
return (PyObject *)it;
}
@ -1118,7 +1070,7 @@ formatter_parser(PyUnicodeObject *self)
typedef struct {
PyObject_HEAD
PyUnicodeObject *str;
STRINGLIB_OBJECT *str;
FieldNameIterator it_field;
} fieldnameiterobject;
@ -1220,7 +1172,7 @@ static PyTypeObject PyFieldNameIter_Type = {
field_name_split. The iterator it returns is a
FieldNameIterator */
static PyObject *
formatter_field_name_split(PyUnicodeObject *self)
formatter_field_name_split(STRINGLIB_OBJECT *self)
{
SubString first;
Py_ssize_t first_idx;

View file

@ -6,12 +6,15 @@
compiled as unicode. */
#define STRINGLIB_IS_UNICODE 0
#define STRINGLIB_OBJECT PyStringObject
#define STRINGLIB_CHAR char
#define STRINGLIB_TYPE_NAME "string"
#define STRINGLIB_PARSE_CODE "S"
#define STRINGLIB_EMPTY string_empty
#define STRINGLIB_EMPTY nullstring
#define STRINGLIB_ISDECIMAL(x) ((x >= '0') && (x <= '9'))
#define STRINGLIB_TODECIMAL(x) (STRINGLIB_ISDECIMAL(x) ? (x - '0') : -1)
#define STRINGLIB_TOUPPER toupper
#define STRINGLIB_TOLOWER tolower
#define STRINGLIB_FILL memset
#define STRINGLIB_STR PyString_AS_STRING
#define STRINGLIB_LEN PyString_GET_SIZE

View file

@ -6,6 +6,7 @@
compiled as unicode. */
#define STRINGLIB_IS_UNICODE 1
#define STRINGLIB_OBJECT PyUnicodeObject
#define STRINGLIB_CHAR Py_UNICODE
#define STRINGLIB_TYPE_NAME "unicode"
#define STRINGLIB_PARSE_CODE "U"
@ -20,7 +21,12 @@
#define STRINGLIB_NEW PyUnicode_FromUnicode
#define STRINGLIB_RESIZE PyUnicode_Resize
#define STRINGLIB_CHECK PyUnicode_Check
#if PY_VERSION_HEX < 0x03000000
#define STRINGLIB_TOSTR PyObject_Unicode
#else
#define STRINGLIB_TOSTR PyObject_Str
#endif
#define STRINGLIB_WANT_CONTAINS_OBJ 1

View file

@ -304,58 +304,13 @@ If the predicate is None, 'lambda x: bool(x)' is assumed.\n\
static PyObject *
builtin_format(PyObject *self, PyObject *args)
{
static PyObject * format_str = NULL;
PyObject *value;
PyObject *spec = NULL;
PyObject *meth;
PyObject *empty = NULL;
PyObject *result = NULL;
PyObject *format_spec = NULL;
/* Initialize cached value */
if (format_str == NULL) {
/* Initialize static variable needed by _PyType_Lookup */
format_str = PyUnicode_FromString("__format__");
if (format_str == NULL)
goto done;
}
if (!PyArg_ParseTuple(args, "O|U:format", &value, &format_spec))
return NULL;
if (!PyArg_ParseTuple(args, "O|U:format", &value, &spec))
goto done;
/* initialize the default value */
if (spec == NULL) {
empty = PyUnicode_FromUnicode(NULL, 0);
spec = empty;
}
/* Make sure the type is initialized. float gets initialized late */
if (Py_TYPE(value)->tp_dict == NULL)
if (PyType_Ready(Py_TYPE(value)) < 0)
goto done;
/* Find the (unbound!) __format__ method (a borrowed reference) */
meth = _PyType_Lookup(Py_TYPE(value), format_str);
if (meth == NULL) {
PyErr_Format(PyExc_TypeError,
"Type %.100s doesn't define __format__",
Py_TYPE(value)->tp_name);
goto done;
}
/* And call it, binding it to the value */
result = PyObject_CallFunctionObjArgs(meth, value, spec, NULL);
if (result && !PyUnicode_Check(result)) {
PyErr_SetString(PyExc_TypeError,
"__format__ method did not return string");
Py_DECREF(result);
result = NULL;
goto done;
}
done:
Py_XDECREF(empty);
return result;
return PyObject_Format(value, format_spec);
}
PyDoc_STRVAR(format_doc,