Commit 8fd3eba0 authored by Eric Smith's avatar Eric Smith

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).
parent 18c66898
...@@ -611,6 +611,13 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ ...@@ -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 */ /* Iterators */
PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *); PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *);
......
...@@ -541,24 +541,58 @@ class BuiltinTest(unittest.TestCase): ...@@ -541,24 +541,58 @@ class BuiltinTest(unittest.TestCase):
self.assertRaises(TypeError, float, Foo4(42)) self.assertRaises(TypeError, float, Foo4(42))
def test_format(self): def test_format(self):
class A: # Test the basic machinery of the format() builtin. Don't test
def __init__(self, x): # the specifics of the various formatters
self.x = x self.assertEqual(format(3, ''), '3')
def __format__(self, format_spec):
return str(self.x) + format_spec
# class that returns a bad type from __format__ # Returns some classes to use for various tests. There's
class B: # an old-style version, and a new-style version
def __format__(self, format_spec): def classes_new():
return 1.0 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 class Simple(object): pass
# as a format spec class DerivedFromSimple(Simple):
class C(str): def __init__(self, x):
pass 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') class Simple: pass
self.assertEqual(format(A(3), 'spec'), '3spec') 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): def empty_format_spec(value):
# test that: # test that:
...@@ -578,19 +612,28 @@ class BuiltinTest(unittest.TestCase): ...@@ -578,19 +612,28 @@ class BuiltinTest(unittest.TestCase):
empty_format_spec(None) empty_format_spec(None)
# TypeError because self.__format__ returns the wrong type # 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(), 4)
self.assertRaises(TypeError, format, object(), object()) 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 # first argument to object.__format__ must be string
self.assertRaises(TypeError, object().__format__, 3) self.assertRaises(TypeError, object().__format__, 3)
self.assertRaises(TypeError, object().__format__, object()) self.assertRaises(TypeError, object().__format__, object())
self.assertRaises(TypeError, object().__format__, None) self.assertRaises(TypeError, object().__format__, None)
# make sure we can take a subclass of str as a format spec # 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): def test_floatasratio(self):
for f, ratio in [ for f, ratio in [
......
...@@ -851,29 +851,29 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): ...@@ -851,29 +851,29 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
def test_format(self): def test_format(self):
dt = self.theclass(2007, 9, 10) 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 # check that a derived class's __str__() gets called
class A(self.theclass): class A(self.theclass):
def __str__(self): def __str__(self):
return 'A' return 'A'
a = A(2007, 9, 10) a = A(2007, 9, 10)
self.assertEqual(format(a, ''), 'A') self.assertEqual(a.__format__(''), 'A')
# check that a derived class's strftime gets called # check that a derived class's strftime gets called
class B(self.theclass): class B(self.theclass):
def strftime(self, format_spec): def strftime(self, format_spec):
return 'B' return 'B'
b = B(2007, 9, 10) 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", for fmt in ["m:%m d:%d y:%y",
"m:%m d:%d y:%y H:%H M:%M S:%S", "m:%m d:%d y:%y H:%H M:%M S:%S",
"%z %Z", "%z %Z",
]: ]:
self.assertEqual(format(dt, fmt), dt.strftime(fmt)) self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
self.assertEqual(format(a, fmt), dt.strftime(fmt)) self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
self.assertEqual(format(b, fmt), 'B') self.assertEqual(b.__format__(fmt), 'B')
def test_resolution_info(self): def test_resolution_info(self):
self.assert_(isinstance(self.theclass.min, self.theclass)) self.assert_(isinstance(self.theclass.min, self.theclass))
...@@ -1178,31 +1178,29 @@ class TestDateTime(TestDate): ...@@ -1178,31 +1178,29 @@ class TestDateTime(TestDate):
def test_format(self): def test_format(self):
dt = self.theclass(2007, 9, 10, 4, 5, 1, 123) 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 # check that a derived class's __str__() gets called
class A(self.theclass): class A(self.theclass):
def __str__(self): def __str__(self):
return 'A' return 'A'
a = A(2007, 9, 10, 4, 5, 1, 123) 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 # check that a derived class's strftime gets called
class B(self.theclass): class B(self.theclass):
def strftime(self, format_spec): def strftime(self, format_spec):
return 'B' return 'B'
b = B(2007, 9, 10, 4, 5, 1, 123) 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", for fmt in ["m:%m d:%d y:%y",
"m:%m d:%d y:%y H:%H M:%M S:%S", "m:%m d:%d y:%y H:%H M:%M S:%S",
"%z %Z", "%z %Z",
]: ]:
self.assertEqual(format(dt, fmt), dt.strftime(fmt)) self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
self.assertEqual(format(a, fmt), dt.strftime(fmt)) self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
self.assertEqual(format(b, fmt), 'B') self.assertEqual(b.__format__(fmt), 'B')
def test_more_ctime(self): def test_more_ctime(self):
# Test fields that TestDate doesn't touch. # Test fields that TestDate doesn't touch.
...@@ -1837,27 +1835,27 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase): ...@@ -1837,27 +1835,27 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase):
def test_format(self): def test_format(self):
t = self.theclass(1, 2, 3, 4) 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 # check that a derived class's __str__() gets called
class A(self.theclass): class A(self.theclass):
def __str__(self): def __str__(self):
return 'A' return 'A'
a = A(1, 2, 3, 4) 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 # check that a derived class's strftime gets called
class B(self.theclass): class B(self.theclass):
def strftime(self, format_spec): def strftime(self, format_spec):
return 'B' return 'B'
b = B(1, 2, 3, 4) b = B(1, 2, 3, 4)
self.assertEqual(format(b, ''), str(t)) self.assertEqual(b.__format__(''), str(t))
for fmt in ['%H %M %S', for fmt in ['%H %M %S',
]: ]:
self.assertEqual(format(t, fmt), t.strftime(fmt)) self.assertEqual(t.__format__(fmt), t.strftime(fmt))
self.assertEqual(format(a, fmt), t.strftime(fmt)) self.assertEqual(a.__format__(fmt), t.strftime(fmt))
self.assertEqual(format(b, fmt), 'B') self.assertEqual(b.__format__(fmt), 'B')
def test_str(self): def test_str(self):
self.assertEqual(str(self.theclass(1, 2, 3, 4)), "01:02:03.000004") 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) ...@@ -3210,21 +3210,6 @@ time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw)
return result; 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. * Miscellaneous methods.
*/ */
...@@ -3412,7 +3397,7 @@ static PyMethodDef time_methods[] = { ...@@ -3412,7 +3397,7 @@ static PyMethodDef time_methods[] = {
{"strftime", (PyCFunction)time_strftime, METH_VARARGS | METH_KEYWORDS, {"strftime", (PyCFunction)time_strftime, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("format -> strftime() style string.")}, PyDoc_STR("format -> strftime() style string.")},
{"__format__", (PyCFunction)time_format, METH_VARARGS, {"__format__", (PyCFunction)date_format, METH_VARARGS,
PyDoc_STR("Formats self with strftime.")}, PyDoc_STR("Formats self with strftime.")},
{"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS, {"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS,
......
...@@ -704,6 +704,57 @@ PyBuffer_FillInfo(Py_buffer *view, void *buf, Py_ssize_t len, ...@@ -704,6 +704,57 @@ PyBuffer_FillInfo(Py_buffer *view, void *buf, Py_ssize_t len,
return 0; 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 */ /* Operations on numbers */
int int
......
...@@ -195,7 +195,7 @@ parse_internal_render_format_spec(PyObject *format_spec, ...@@ -195,7 +195,7 @@ parse_internal_render_format_spec(PyObject *format_spec,
return 1; return 1;
} }
#if defined FORMAT_FLOAT || defined FORMAT_LONG
/************************************************************************/ /************************************************************************/
/*********** common routines for numeric formatting *********************/ /*********** common routines for numeric formatting *********************/
/************************************************************************/ /************************************************************************/
...@@ -288,7 +288,8 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign, ...@@ -288,7 +288,8 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
else { else {
/* determine which of left, space, or right padding is /* determine which of left, space, or right padding is
needed */ 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 == '<') if (format->align == '<')
r->n_rpadding = padding; r->n_rpadding = padding;
else if (format->align == '>') else if (format->align == '>')
...@@ -338,6 +339,7 @@ fill_number(STRINGLIB_CHAR *p_buf, const NumberFieldWidths *spec, ...@@ -338,6 +339,7 @@ fill_number(STRINGLIB_CHAR *p_buf, const NumberFieldWidths *spec,
} }
return p_digits; return p_digits;
} }
#endif /* FORMAT_FLOAT || FORMAT_LONG */
/************************************************************************/ /************************************************************************/
/*********** string formatting ******************************************/ /*********** string formatting ******************************************/
...@@ -434,18 +436,23 @@ done: ...@@ -434,18 +436,23 @@ done:
/*********** long formatting ********************************************/ /*********** long formatting ********************************************/
/************************************************************************/ /************************************************************************/
#if defined FORMAT_LONG || defined FORMAT_INT
typedef PyObject*
(*IntOrLongToString)(PyObject *value, int base);
static PyObject * 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; PyObject *result = NULL;
int total_leading_chars_to_skip = 0; /* also includes sign, if PyObject *tmp = NULL;
present */ STRINGLIB_CHAR *pnumeric_chars;
STRINGLIB_CHAR numeric_char;
STRINGLIB_CHAR sign = '\0'; STRINGLIB_CHAR sign = '\0';
STRINGLIB_CHAR *p; STRINGLIB_CHAR *p;
Py_ssize_t n_digits; /* count of digits need from the computed Py_ssize_t n_digits; /* count of digits need from the computed
string */ string */
Py_ssize_t len; Py_ssize_t n_leading_chars;
Py_ssize_t tmp;
NumberFieldWidths spec; NumberFieldWidths spec;
long x; long x;
...@@ -469,6 +476,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format) ...@@ -469,6 +476,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format)
/* taken from unicodeobject.c formatchar() */ /* taken from unicodeobject.c formatchar() */
/* Integer input truncated to a character */ /* Integer input truncated to a character */
/* XXX: won't work for int */
x = PyLong_AsLong(value); x = PyLong_AsLong(value);
if (x == -1 && PyErr_Occurred()) if (x == -1 && PyErr_Occurred())
goto done; goto done;
...@@ -487,115 +495,101 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format) ...@@ -487,115 +495,101 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format)
goto done; goto done;
} }
#endif #endif
result = STRINGLIB_NEW(NULL, 1); numeric_char = (STRINGLIB_CHAR)x;
if (result == NULL) pnumeric_chars = &numeric_char;
goto done; n_digits = 1;
p = STRINGLIB_STR(result);
p[0] = (Py_UNICODE) x;
n_digits = len = 1;
} }
else { else {
int base; int base;
int format_leading_chars_to_skip; /* characters added by int leading_chars_to_skip; /* Number of characters added by
PyNumber_ToBase that we PyNumber_ToBase that we want to
want to skip over. skip over. */
instead of using them,
we'll compute our /* Compute the base and how many characters will be added by
own. */
/* compute the base and how many characters will be added by
PyNumber_ToBase */ PyNumber_ToBase */
switch (format->type) { switch (format->type) {
case 'b': case 'b':
base = 2; base = 2;
format_leading_chars_to_skip = 2; /* 0b */ leading_chars_to_skip = 2; /* 0b */
break; break;
case 'o': case 'o':
base = 8; base = 8;
format_leading_chars_to_skip = 2; /* 0o */ leading_chars_to_skip = 2; /* 0o */
break; break;
case 'x': case 'x':
case 'X': case 'X':
base = 16; base = 16;
format_leading_chars_to_skip = 2; /* 0x */ leading_chars_to_skip = 2; /* 0x */
break; break;
default: /* shouldn't be needed, but stops a compiler warning */ default: /* shouldn't be needed, but stops a compiler warning */
case 'd': case 'd':
base = 10; base = 10;
format_leading_chars_to_skip = 0; leading_chars_to_skip = 0;
break; break;
} }
/* do the hard part, converting to a string in a given base */ /* Do the hard part, converting to a string in a given base */
result = PyNumber_ToBase(value, base); tmp = tostring(value, base);
if (result == NULL) if (tmp == NULL)
goto done; goto done;
n_digits = STRINGLIB_LEN(result); pnumeric_chars = STRINGLIB_STR(tmp);
len = n_digits; n_digits = STRINGLIB_LEN(tmp);
p = STRINGLIB_STR(result);
/* if X, convert to uppercase */ /* Remember not to modify what pnumeric_chars points to. it
if (format->type == 'X') might be interned. Only modify it after we copy it into a
for (tmp = 0; tmp < len; tmp++) newly allocated output buffer. */
p[tmp] = STRINGLIB_TOUPPER(p[tmp]);
/* 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 */ and skip it */
sign = p[0]; sign = pnumeric_chars[0];
if (sign == '-') { if (sign == '-') {
total_leading_chars_to_skip += 1; ++leading_chars_to_skip;
n_digits--;
} }
/* skip over the leading digits (0x, 0b, etc.) */ /* Skip over the leading chars (0x, 0b, etc.) */
assert(n_digits >= format_leading_chars_to_skip + 1); n_digits -= leading_chars_to_skip;
n_digits -= format_leading_chars_to_skip; pnumeric_chars += leading_chars_to_skip;
total_leading_chars_to_skip += format_leading_chars_to_skip;
} }
/* Calculate the widths of the various leading and trailing parts */
calc_number_widths(&spec, sign, n_digits, format); calc_number_widths(&spec, sign, n_digits, format);
/* if the buffer is getting bigger, realloc it. if it's getting /* Allocate a new string to hold the result */
smaller, don't realloc because we need to move the results result = STRINGLIB_NEW(NULL, spec.n_total);
around first. realloc after we've done that */ if (!result)
goto done;
p = STRINGLIB_STR(result);
if (spec.n_total > len) { /* Fill in the digit parts */
if (STRINGLIB_RESIZE(&result, spec.n_total) < 0) n_leading_chars = spec.n_lpadding + spec.n_lsign + spec.n_spadding;
goto done; memmove(p + n_leading_chars,
/* recalc, because string might have moved */ pnumeric_chars,
p = STRINGLIB_STR(result); n_digits * sizeof(STRINGLIB_CHAR));
}
/* copy the characters into position first, since we're going to /* if X, convert to uppercase */
overwrite some of that space */ if (format->type == 'X') {
/* we need to move if the number of left padding in the output is Py_ssize_t t;
different from the number of characters we need to skip */ for (t = 0; t < n_digits; t++)
if ((spec.n_lpadding + spec.n_lsign + spec.n_spadding) != p[t + n_leading_chars] = STRINGLIB_TOUPPER(p[t + n_leading_chars]);
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, fill_number(p, &spec, n_digits,
format->fill_char == '\0' ? ' ' : format->fill_char); 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: done:
Py_XDECREF(tmp);
return result; return result;
} }
#endif /* defined FORMAT_LONG || defined FORMAT_INT */
/************************************************************************/ /************************************************************************/
/*********** float formatting *******************************************/ /*********** float formatting *******************************************/
/************************************************************************/ /************************************************************************/
#ifdef FORMAT_FLOAT
#if STRINGLIB_IS_UNICODE
/* taken from unicodeobject.c */ /* taken from unicodeobject.c */
static Py_ssize_t static Py_ssize_t
strtounicode(Py_UNICODE *buffer, const char *charbuffer) strtounicode(Py_UNICODE *buffer, const char *charbuffer)
...@@ -607,6 +601,7 @@ strtounicode(Py_UNICODE *buffer, const char *charbuffer) ...@@ -607,6 +601,7 @@ strtounicode(Py_UNICODE *buffer, const char *charbuffer)
return len; return len;
} }
#endif
/* the callback function to call to do the actual float formatting. /* the callback function to call to do the actual float formatting.
it matches the definition of PyOS_ascii_formatd */ it matches the definition of PyOS_ascii_formatd */
...@@ -694,7 +689,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value, ...@@ -694,7 +689,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value,
/* cast "type", because if we're in unicode we need to pass a /* 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" 8-bit char. this is safe, because we've restricted what "type"
can be */ 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 */ /* call the passed in function to do the actual formatting */
snprintf(charbuf, sizeof(charbuf), fmt, x); snprintf(charbuf, sizeof(charbuf), fmt, x);
...@@ -739,7 +735,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value, ...@@ -739,7 +735,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value,
format->fill_char == '\0' ? ' ' : format->fill_char); format->fill_char == '\0' ? ' ' : format->fill_char);
/* fill in the digit parts */ /* 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, p,
n_digits * sizeof(STRINGLIB_CHAR)); n_digits * sizeof(STRINGLIB_CHAR));
...@@ -755,20 +752,43 @@ format_float_internal(PyObject *value, const InternalFormatSpec *format) ...@@ -755,20 +752,43 @@ format_float_internal(PyObject *value, const InternalFormatSpec *format)
else else
return _format_float(format->type, value, format, PyOS_ascii_formatd); return _format_float(format->type, value, format, PyOS_ascii_formatd);
} }
#endif /* FORMAT_FLOAT */
/************************************************************************/ /************************************************************************/
/*********** built in formatters ****************************************/ /*********** built in formatters ****************************************/
/************************************************************************/ /************************************************************************/
#ifdef FORMAT_STRING
PyObject * PyObject *
FORMAT_STRING(PyObject* value, PyObject* args) FORMAT_STRING(PyObject* value, PyObject* args)
{ {
PyObject *format_spec; PyObject *format_spec;
PyObject *result = NULL; PyObject *result = NULL;
#if PY_VERSION_HEX < 0x03000000
PyObject *tmp = NULL;
#endif
InternalFormatSpec format; 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; goto done;
format_spec = tmp;
#endif
/* check for the special case of zero length format spec, make /* check for the special case of zero length format spec, make
it equivalent to str(value) */ it equivalent to str(value) */
...@@ -777,6 +797,7 @@ FORMAT_STRING(PyObject* value, PyObject* args) ...@@ -777,6 +797,7 @@ FORMAT_STRING(PyObject* value, PyObject* args)
goto done; goto done;
} }
/* parse the format_spec */ /* parse the format_spec */
if (!parse_internal_render_format_spec(format_spec, &format, 's')) if (!parse_internal_render_format_spec(format_spec, &format, 's'))
goto done; goto done;
...@@ -795,18 +816,24 @@ FORMAT_STRING(PyObject* value, PyObject* args) ...@@ -795,18 +816,24 @@ FORMAT_STRING(PyObject* value, PyObject* args)
} }
done: done:
#if PY_VERSION_HEX < 0x03000000
Py_XDECREF(tmp);
#endif
return result; return result;
} }
#endif /* FORMAT_STRING */
PyObject * #if defined FORMAT_LONG || defined FORMAT_INT
FORMAT_LONG(PyObject* value, PyObject* args) static PyObject*
format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring)
{ {
PyObject *format_spec; PyObject *format_spec;
PyObject *result = NULL; PyObject *result = NULL;
PyObject *tmp = NULL; PyObject *tmp = NULL;
InternalFormatSpec format; InternalFormatSpec format;
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", &format_spec)) if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__",
&format_spec))
goto done; goto done;
/* check for the special case of zero length format spec, make /* check for the special case of zero length format spec, make
...@@ -828,8 +855,9 @@ FORMAT_LONG(PyObject* value, PyObject* args) ...@@ -828,8 +855,9 @@ FORMAT_LONG(PyObject* value, PyObject* args)
case 'o': case 'o':
case 'x': case 'x':
case 'X': case 'X':
/* no type conversion needed, already an int. do the formatting */ /* no type conversion needed, already an int (or long). do
result = format_long_internal(value, &format); the formatting */
result = format_int_or_long_internal(value, &format, tostring);
break; break;
case 'e': case 'e':
...@@ -858,7 +886,52 @@ done: ...@@ -858,7 +886,52 @@ done:
Py_XDECREF(tmp); Py_XDECREF(tmp);
return result; 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 * PyObject *
FORMAT_FLOAT(PyObject *value, PyObject *args) FORMAT_FLOAT(PyObject *value, PyObject *args)
{ {
...@@ -904,3 +977,4 @@ FORMAT_FLOAT(PyObject *value, PyObject *args) ...@@ -904,3 +977,4 @@ FORMAT_FLOAT(PyObject *value, PyObject *args)
done: done:
return result; return result;
} }
#endif /* FORMAT_FLOAT */
...@@ -6,6 +6,11 @@ ...@@ -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 */ /* Defines for more efficiently reallocating the string buffer */
#define INITIAL_SIZE_INCREMENT 100 #define INITIAL_SIZE_INCREMENT 100
#define SIZE_MULTIPLIER 2 #define SIZE_MULTIPLIER 2
...@@ -470,66 +475,6 @@ error: ...@@ -470,66 +475,6 @@ error:
field object and field specification string generated by field object and field specification string generated by
get_field_and_spec, and renders the field into the output string. 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 render_field calls fieldobj.__format__(format_spec) method, and
appends to the output. appends to the output.
*/ */
...@@ -537,14 +482,21 @@ static int ...@@ -537,14 +482,21 @@ static int
render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output) render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output)
{ {
int ok = 0; 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) if (result == NULL)
goto done; goto done;
ok = output_data(output, ok = output_data(output,
STRINGLIB_STR(result), STRINGLIB_LEN(result)); STRINGLIB_STR(result), STRINGLIB_LEN(result));
done: done:
Py_DECREF(format_spec_object);
Py_XDECREF(result); Py_XDECREF(result);
return ok; return ok;
} }
...@@ -770,7 +722,7 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) ...@@ -770,7 +722,7 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion)
case 'r': case 'r':
return PyObject_Repr(obj); return PyObject_Repr(obj);
case 's': case 's':
return PyObject_Str(obj); return STRINGLIB_TOSTR(obj);
default: default:
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Unknown converion specifier %c", "Unknown converion specifier %c",
...@@ -845,7 +797,7 @@ done: ...@@ -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 searches through the format string for escapes to markup codes, and
calls other functions to move non-markup text to the output, calls other functions to move non-markup text to the output,
and to perform the markup to the output. and to perform the markup to the output.
...@@ -958,7 +910,7 @@ do_string_format(PyObject *self, PyObject *args, PyObject *kwargs) ...@@ -958,7 +910,7 @@ do_string_format(PyObject *self, PyObject *args, PyObject *kwargs)
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyUnicodeObject *str; STRINGLIB_OBJECT *str;
MarkupIterator it_markup; MarkupIterator it_markup;
} formatteriterobject; } formatteriterobject;
...@@ -984,7 +936,7 @@ formatteriter_next(formatteriterobject *it) ...@@ -984,7 +936,7 @@ formatteriter_next(formatteriterobject *it)
SubString literal; SubString literal;
SubString field_name; SubString field_name;
SubString format_spec; SubString format_spec;
Py_UNICODE conversion; STRINGLIB_CHAR conversion;
int format_spec_needs_expanding; int format_spec_needs_expanding;
int result = MarkupIterator_next(&it->it_markup, &literal, &field_name, int result = MarkupIterator_next(&it->it_markup, &literal, &field_name,
&format_spec, &conversion, &format_spec, &conversion,
...@@ -1028,7 +980,7 @@ formatteriter_next(formatteriterobject *it) ...@@ -1028,7 +980,7 @@ formatteriter_next(formatteriterobject *it)
Py_INCREF(conversion_str); Py_INCREF(conversion_str);
} }
else else
conversion_str = PyUnicode_FromUnicode(&conversion, 1); conversion_str = STRINGLIB_NEW(&conversion, 1);
if (conversion_str == NULL) if (conversion_str == NULL)
goto done; goto done;
...@@ -1047,7 +999,7 @@ static PyMethodDef formatteriter_methods[] = { ...@@ -1047,7 +999,7 @@ static PyMethodDef formatteriter_methods[] = {
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
PyTypeObject PyFormatterIter_Type = { static PyTypeObject PyFormatterIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"formatteriterator", /* tp_name */ "formatteriterator", /* tp_name */
sizeof(formatteriterobject), /* tp_basicsize */ sizeof(formatteriterobject), /* tp_basicsize */
...@@ -1085,7 +1037,7 @@ PyTypeObject PyFormatterIter_Type = { ...@@ -1085,7 +1037,7 @@ PyTypeObject PyFormatterIter_Type = {
describing the parsed elements. It's a wrapper around describing the parsed elements. It's a wrapper around
stringlib/string_format.h's MarkupIterator */ stringlib/string_format.h's MarkupIterator */
static PyObject * static PyObject *
formatter_parser(PyUnicodeObject *self) formatter_parser(STRINGLIB_OBJECT *self)
{ {
formatteriterobject *it; formatteriterobject *it;
...@@ -1099,8 +1051,8 @@ formatter_parser(PyUnicodeObject *self) ...@@ -1099,8 +1051,8 @@ formatter_parser(PyUnicodeObject *self)
/* initialize the contained MarkupIterator */ /* initialize the contained MarkupIterator */
MarkupIterator_init(&it->it_markup, MarkupIterator_init(&it->it_markup,
PyUnicode_AS_UNICODE(self), STRINGLIB_STR(self),
PyUnicode_GET_SIZE(self)); STRINGLIB_LEN(self));
return (PyObject *)it; return (PyObject *)it;
} }
...@@ -1118,7 +1070,7 @@ formatter_parser(PyUnicodeObject *self) ...@@ -1118,7 +1070,7 @@ formatter_parser(PyUnicodeObject *self)
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyUnicodeObject *str; STRINGLIB_OBJECT *str;
FieldNameIterator it_field; FieldNameIterator it_field;
} fieldnameiterobject; } fieldnameiterobject;
...@@ -1220,7 +1172,7 @@ static PyTypeObject PyFieldNameIter_Type = { ...@@ -1220,7 +1172,7 @@ static PyTypeObject PyFieldNameIter_Type = {
field_name_split. The iterator it returns is a field_name_split. The iterator it returns is a
FieldNameIterator */ FieldNameIterator */
static PyObject * static PyObject *
formatter_field_name_split(PyUnicodeObject *self) formatter_field_name_split(STRINGLIB_OBJECT *self)
{ {
SubString first; SubString first;
Py_ssize_t first_idx; Py_ssize_t first_idx;
......
...@@ -6,12 +6,15 @@ ...@@ -6,12 +6,15 @@
compiled as unicode. */ compiled as unicode. */
#define STRINGLIB_IS_UNICODE 0 #define STRINGLIB_IS_UNICODE 0
#define STRINGLIB_OBJECT PyStringObject
#define STRINGLIB_CHAR char #define STRINGLIB_CHAR char
#define STRINGLIB_TYPE_NAME "string" #define STRINGLIB_TYPE_NAME "string"
#define STRINGLIB_PARSE_CODE "S" #define STRINGLIB_PARSE_CODE "S"
#define STRINGLIB_EMPTY string_empty #define STRINGLIB_EMPTY nullstring
#define STRINGLIB_ISDECIMAL(x) ((x >= '0') && (x <= '9')) #define STRINGLIB_ISDECIMAL(x) ((x >= '0') && (x <= '9'))
#define STRINGLIB_TODECIMAL(x) (STRINGLIB_ISDECIMAL(x) ? (x - '0') : -1) #define STRINGLIB_TODECIMAL(x) (STRINGLIB_ISDECIMAL(x) ? (x - '0') : -1)
#define STRINGLIB_TOUPPER toupper
#define STRINGLIB_TOLOWER tolower
#define STRINGLIB_FILL memset #define STRINGLIB_FILL memset
#define STRINGLIB_STR PyString_AS_STRING #define STRINGLIB_STR PyString_AS_STRING
#define STRINGLIB_LEN PyString_GET_SIZE #define STRINGLIB_LEN PyString_GET_SIZE
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
compiled as unicode. */ compiled as unicode. */
#define STRINGLIB_IS_UNICODE 1 #define STRINGLIB_IS_UNICODE 1
#define STRINGLIB_OBJECT PyUnicodeObject
#define STRINGLIB_CHAR Py_UNICODE #define STRINGLIB_CHAR Py_UNICODE
#define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_TYPE_NAME "unicode"
#define STRINGLIB_PARSE_CODE "U" #define STRINGLIB_PARSE_CODE "U"
...@@ -20,7 +21,12 @@ ...@@ -20,7 +21,12 @@
#define STRINGLIB_NEW PyUnicode_FromUnicode #define STRINGLIB_NEW PyUnicode_FromUnicode
#define STRINGLIB_RESIZE PyUnicode_Resize #define STRINGLIB_RESIZE PyUnicode_Resize
#define STRINGLIB_CHECK PyUnicode_Check #define STRINGLIB_CHECK PyUnicode_Check
#if PY_VERSION_HEX < 0x03000000
#define STRINGLIB_TOSTR PyObject_Unicode
#else
#define STRINGLIB_TOSTR PyObject_Str #define STRINGLIB_TOSTR PyObject_Str
#endif
#define STRINGLIB_WANT_CONTAINS_OBJ 1 #define STRINGLIB_WANT_CONTAINS_OBJ 1
......
...@@ -304,58 +304,13 @@ If the predicate is None, 'lambda x: bool(x)' is assumed.\n\ ...@@ -304,58 +304,13 @@ If the predicate is None, 'lambda x: bool(x)' is assumed.\n\
static PyObject * static PyObject *
builtin_format(PyObject *self, PyObject *args) builtin_format(PyObject *self, PyObject *args)
{ {
static PyObject * format_str = NULL;
PyObject *value; PyObject *value;
PyObject *spec = NULL; PyObject *format_spec = NULL;
PyObject *meth;
PyObject *empty = NULL; if (!PyArg_ParseTuple(args, "O|U:format", &value, &format_spec))
PyObject *result = NULL; return NULL;
/* Initialize cached value */ return PyObject_Format(value, format_spec);
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;
} }
PyDoc_STRVAR(format_doc, PyDoc_STRVAR(format_doc,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment