summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Smith <eric@trueblade.com>2008-02-17 19:48:00 (GMT)
committerEric Smith <eric@trueblade.com>2008-02-17 19:48:00 (GMT)
commit8fd3eba0501a77eec463179f529f56025ff4b40b (patch)
treed459220bd52a30ce3de89b89ed1db077e7b5d4a4
parent18c66898b0a14761786161c07d89d65c8f088601 (diff)
downloadcpython-8fd3eba0501a77eec463179f529f56025ff4b40b.zip
cpython-8fd3eba0501a77eec463179f529f56025ff4b40b.tar.gz
cpython-8fd3eba0501a77eec463179f529f56025ff4b40b.tar.bz2
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).
-rw-r--r--Include/abstract.h7
-rw-r--r--Lib/test/test_builtin.py79
-rw-r--r--Lib/test/test_datetime.py38
-rw-r--r--Modules/datetimemodule.c17
-rw-r--r--Objects/abstract.c51
-rw-r--r--Objects/stringlib/formatter.h228
-rw-r--r--Objects/stringlib/string_format.h96
-rw-r--r--Objects/stringlib/stringdefs.h5
-rw-r--r--Objects/stringlib/unicodedefs.h6
-rw-r--r--Python/bltinmodule.c57
10 files changed, 329 insertions, 255 deletions
diff --git a/Include/abstract.h b/Include/abstract.h
index a496817..9a1003b 100644
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -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 *);
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 762afad..42c55cc 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -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
+ # Test the basic machinery of the format() builtin. Don't test
+ # the specifics of the various formatters
+ self.assertEqual(format(3, ''), '3')
- # class that returns a bad type from __format__
- class B:
- def __format__(self, format_spec):
- return 1.0
+ # 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 that is derived from string, used
- # as a format spec
- class C(str):
- 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
- self.assertEqual(format(3, ''), '3')
- self.assertEqual(format(A(3), 'spec'), '3spec')
+ 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 [
diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py
index 7c08f9e..8ac7160 100644
--- a/Lib/test/test_datetime.py
+++ b/Lib/test/test_datetime.py
@@ -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")
diff --git a/Modules/datetimemodule.c b/Modules/datetimemodule.c
index b91a082..27c404f 100644
--- a/Modules/datetimemodule.c
+++ b/Modules/datetimemodule.c
@@ -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,
diff --git a/Objects/abstract.c b/Objects/abstract.c
index bb6c301..655a52a 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -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
diff --git a/Objects/stringlib/formatter.h b/Objects/stringlib/formatter.h
index 2ff7290..39da6b3 100644
--- a/Objects/stringlib/formatter.h
+++ b/Objects/stringlib/formatter.h
@@ -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));
- /* 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));
+ /* 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]);
}
- /* 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 */
diff --git a/Objects/stringlib/string_format.h b/Objects/stringlib/string_format.h
index 2c4510f..70f8f13 100644
--- a/Objects/stringlib/string_format.h
+++ b/Objects/stringlib/string_format.h
@@ -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;
diff --git a/Objects/stringlib/stringdefs.h b/Objects/stringlib/stringdefs.h
index a4be17f..1e0df0f 100644
--- a/Objects/stringlib/stringdefs.h
+++ b/Objects/stringlib/stringdefs.h
@@ -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
diff --git a/Objects/stringlib/unicodedefs.h b/Objects/stringlib/unicodedefs.h
index 64777be..f402a98 100644
--- a/Objects/stringlib/unicodedefs.h
+++ b/Objects/stringlib/unicodedefs.h
@@ -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
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 964fb32..70237bf 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -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;
-
- /* 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, &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;
+ PyObject *format_spec = NULL;
+
+ if (!PyArg_ParseTuple(args, "O|U:format", &value, &format_spec))
+ return NULL;
+
+ return PyObject_Format(value, format_spec);
}
PyDoc_STRVAR(format_doc,