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:
parent
18c66898b0
commit
8fd3eba050
|
@ -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 *);
|
||||
|
|
|
@ -541,24 +541,58 @@ class BuiltinTest(unittest.TestCase):
|
|||
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 @@ class BuiltinTest(unittest.TestCase):
|
|||
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 [
|
||||
|
|
|
@ -851,29 +851,29 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
|
|||
|
||||
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 @@ class TestDateTime(TestDate):
|
|||
|
||||
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 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase):
|
|||
|
||||
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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 @@ done:
|
|||
/*********** 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 @@ done:
|
|||
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 */
|
||||
|
|
|
@ -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 @@ error:
|
|||
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 @@ done:
|
|||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue