[Python-checkins] r54100 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c
eric.smith
python-checkins at python.org
Sat Mar 3 01:30:41 CET 2007
Author: eric.smith
Date: Sat Mar 3 01:30:36 2007
New Revision: 54100
Modified:
sandbox/trunk/pep3101/README.txt
sandbox/trunk/pep3101/test_simpleformat.py
sandbox/trunk/pep3101/unicodeformat.c
Log:
Added character formatter, code cleanup, added to do items in README.
Modified: sandbox/trunk/pep3101/README.txt
==============================================================================
--- sandbox/trunk/pep3101/README.txt (original)
+++ sandbox/trunk/pep3101/README.txt Sat Mar 3 01:30:36 2007
@@ -7,7 +7,7 @@
Current developers:
Patrick Maupin (pmaupin at gmail.com)
- Eric V. Smith
+ Eric V. Smith (eric at trueblade.com)
Pete Shinner
The code is only half-baked at present
@@ -61,6 +61,10 @@
compatible template systems.
- Play with possible options for specifying additional
escape syntaxes
+ - Should we have stricter checking on format strings? For example
+ type "s" doesn't allow a sign character. Should specifying one
+ be an error?
+ - Test suite needs to check for specific exceptions.
_flags options to consider adding:
Modified: sandbox/trunk/pep3101/test_simpleformat.py
==============================================================================
--- sandbox/trunk/pep3101/test_simpleformat.py (original)
+++ sandbox/trunk/pep3101/test_simpleformat.py Sat Mar 3 01:30:36 2007
@@ -89,7 +89,7 @@
self.formatEquals("32_*>4d", "{0:{1}{2}4{3}}", 32, "*", ">", "d")
def test_specifiers(self):
- self.formatEquals("97_c", "{0:c}", ord("a"))
+ self.formatEquals("a", "{0:c}", ord("a"))
self.formatEquals("8_08b", "{0:08b}", 8)
self.formatEquals("8_ >3d", "{0: >3d}", 8)
self.formatEquals("0.1515_.0%", "{0:.0%}", .1515)
@@ -101,9 +101,11 @@
self.formatEquals("abc", "{0:.3s}", "abcdef")
self.formatEquals("resultx", "{0:x<7s}", "result")
+ self.formatEquals("resultxx", "{0:x<8s}", "result")
self.formatEquals("result ", "{0: <7s}", "result")
self.formatEquals("result ", "{0:<7s}", "result")
self.formatEquals(" result", "{0:>7s}", "result")
+ self.formatEquals(" result", "{0:>8s}", "result")
def test_repr_specifiers(self):
self.formatEquals("3", "{0:r}", 3)
@@ -113,6 +115,30 @@
self.formatEquals("'abcdefg'", "{0:r}", "abcdefg")
self.formatEquals("'abcdefg", "{0:8r}", "abcdefg")
+ def test_decimal_specifiers(self):
+ pass
+# self.assertRaises(Exception, "{0:d}", "non-number")
+
+# self.formatEquals("0", "{0:d}", 0)
+# self.formatEquals("1" + "0" * 100, "{0:d}", 10**100)
+
+ def test_char_specifiers(self):
+ self.formatEquals("A", "{0:c}", "A")
+ self.formatEquals("8", "{0:c}", "8")
+ self.formatEquals(";", "{0:c}", ";")
+ self.formatEquals(";", "{0:c}", long(ord(";")))
+
+ self.formatRaises(TypeError, "{0:c}", "abcd")
+
+ # XXX not sure why this doesn't raise
+ #self.formatRaises(TypeError, "{0:c}", [1, 2, 3])
+
+ # XXX not sure why this doesn't raise
+ #self.formatRaises(TypeError, "{0:c}", 1j)
+
+ # XXX this should raise, but instead gives a DeprecationWarning
+ #self.formatRaises(TypeError, "{0:c}", 3.14)
+
def test_missing_type_specifier(self):
# make sure floats use 'g', ints and longs 'd', and everything else 's'
pass
Modified: sandbox/trunk/pep3101/unicodeformat.c
==============================================================================
--- sandbox/trunk/pep3101/unicodeformat.c (original)
+++ sandbox/trunk/pep3101/unicodeformat.c Sat Mar 3 01:30:36 2007
@@ -1,5 +1,3 @@
-#define DUMMY_FORMATTING 1
-
/*
unicodeformat.c -- implementation of PEP 3101
@@ -26,6 +24,7 @@
#define CH_TYPE Py_UNICODE
#define CH_TYPE_ISDECIMAL Py_UNICODE_ISDECIMAL
#define CH_TYPE_TODECIMAL Py_UNICODE_TODECIMAL
+#define CH_TYPE_FILL Py_UNICODE_FILL
#define STROBJ_AS_PTR PyUnicode_AS_UNICODE
#define STROBJ_GET_SIZE PyUnicode_GET_SIZE
#define STROBJ_NEW PyUnicode_FromUnicode
@@ -37,6 +36,7 @@
#define CH_TYPE char
#define CH_TYPE_ISDECIMAL(x) ((x >= '0') && (x <= '9'))
#define CH_TYPE_TODECIMAL(x) (CH_TYPE_ISDECIMAL(x) ? (x - '0') : -1)
+#define CH_TYPE_FILL Py_UNICODE_FILL
#define STROBJ_AS_PTR PyString_AS_STRING
#define STROBJ_GET_SIZE PyString_GET_SIZE
#define STROBJ_NEW PyString_FromStringAndSize
@@ -67,6 +67,19 @@
/*********** Global data structures and forward declarations *********/
/************************************************************************/
+/* FORMATBUFLEN is taken from stringobject.c, it should probably be
+ factored out */
+/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
+
+ FORMATBUFLEN is the length of the buffer in which the floats, ints, &
+ chars are formatted. XXX This is a magic number. Each formatting
+ routine does bounds checking to ensure no overflow, but a better
+ solution may be to malloc a buffer of appropriate size for each
+ format. For now, the current solution is sufficient.
+*/
+#define FORMATBUFLEN (size_t)120
+
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -161,17 +174,6 @@
/************************** Utility functions ************************/
/************************************************************************/
-/* XXX probably a better way to do this. can't use memset, though,
- because of Unicode and char* support */
-Py_LOCAL_INLINE(void)
-charset(CH_TYPE* dst, CH_TYPE ch, Py_ssize_t len)
-{
- CH_TYPE* end = dst + len;
- for(; dst < end; dst++) {
- *dst = ch;
- }
-}
-
/************************************************************************/
/*********** Error handling and exception generation **************/
@@ -748,7 +750,8 @@
/* used to output simple strings, only supports a maximum width and
total field alignment */
static int
-output_string_chars(FmtState *fs, CH_TYPE *src, Py_ssize_t len, const InternalFormatSpec *format)
+output_string_chars(FmtState *fs, CH_TYPE *src, Py_ssize_t len,
+ const InternalFormatSpec *format)
{
Py_ssize_t ok;
Py_ssize_t width; /* total field width */
@@ -762,6 +765,10 @@
if (format->width >= 0) {
width = format->width;
+ /* don't write out more than width characters */
+ if (len > width) {
+ len = width;
+ }
} else {
/* not specified, use all of the chars and no more */
width = len;
@@ -773,11 +780,13 @@
/* now write into that space */
- /* if right aligning, increment the destination allow space on the left */
- memcpy(dst + (format->align == '>' ? (width - len) : 0), src, len * sizeof(CH_TYPE));
+ /* if right aligning, increment the destination allow space on the
+ left */
+ memcpy(dst + (format->align == '>' ? (width - len) : 0), src,
+ len * sizeof(CH_TYPE));
/* do any padding */
- if (len != width) {
+ if (width > len) {
CH_TYPE fill_char = format->fill_char;
if (fill_char == '\0') {
/* use the default, if not specified */
@@ -786,27 +795,19 @@
if (format->align == '>') {
/* right align, pad on left */
- charset(dst, fill_char, width - len);
+ CH_TYPE_FILL(dst, fill_char, width - len);
} else {
/* left align, pad on right */
- charset(dst + len, fill_char, width - len);
+ CH_TYPE_FILL(dst + len, fill_char, width - len);
}
}
return 1;
}
-/*
- Our internal conversion functions have this signature.
-
- returns 0 on failure, else 1
-*/
-typedef int
-(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format);
-
/* XXX delete this when all internal conversions are implemented */
static int
-convert_DUMMY(PyObject *fieldobj, FmtState *fs)
+format_DUMMY(PyObject *fieldobj, FmtState *fs)
{
PyObject *myobj;
int ok;
@@ -832,23 +833,70 @@
return 1;
}
-/* conversion functions */
+/************************************************************************/
+/************************* Builtin formatters *************************/
+/************************************************************************/
+
+/*
+ return 0 on failure, else 1
+*/
+typedef int
+(*FormatFunction)(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format);
+
static int
-convert_binary(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_binary(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_char(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_char(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ int ok;
+ CH_TYPE buf;
+
+ if (PyString_Check(fieldobj)) {
+ if (!PyArg_Parse(fieldobj, "c;%c requires int or char", &buf))
+ return 0;
+ }
+ else {
+ if (!PyArg_Parse(fieldobj, "b;%c requires int or char", &buf))
+ return -1;
+ }
+
+ return output_data(fs, &buf, 1);
}
static int
-convert_decimal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_decimal(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+#if 0
+ if (PyLong_Check(fieldobj)) {
+ int ilen;
+ temp = _PyString_FormatLong(v, flags,
+ prec, c, &pbuf, &ilen);
+ len = ilen;
+ if (!temp)
+ goto error;
+ sign = 1;
+ }
+ else {
+ pbuf = formatbuf;
+ len = formatint(pbuf,
+ sizeof(formatbuf),
+ flags, prec, c, v);
+ if (len < 0)
+ goto error;
+ sign = 1;
+ }
+ if (flags & F_ZERO)
+ fill = '0';
+#endif
+ return format_DUMMY(fieldobj, fs);
#if 0
PyObject *intobj;
PyObject *strobj;
@@ -884,55 +932,64 @@
}
static int
-convert_exponent(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_exponent(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_exponentUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_exponentUC(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_fixed(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_fixed(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_fixedUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_fixedUC(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_general(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_general(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_generalUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_generalUC(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_number(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_number(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_octal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_octal(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_repr(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_repr(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
int ok;
PyObject *strobj;
@@ -945,14 +1002,16 @@
strobj = STROBJ_STR(reprobj);
Py_DECREF(reprobj);
- ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), STROBJ_GET_SIZE(strobj), format);
+ ok = output_string_chars(fs, STROBJ_AS_PTR(strobj),
+ STROBJ_GET_SIZE(strobj), format);
Py_DECREF(strobj);
return ok;
}
static int
-convert_string(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_string(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
PyObject *strobj;
int ok;
@@ -961,54 +1020,58 @@
if (strobj == NULL)
return 0;
- ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), STROBJ_GET_SIZE(strobj), format);
+ ok = output_string_chars(fs, STROBJ_AS_PTR(strobj),
+ STROBJ_GET_SIZE(strobj), format);
Py_DECREF(strobj);
return ok;
}
static int
-convert_hex(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_hex(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_hexUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_hexUC(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
static int
-convert_percentage(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format)
+format_percentage(PyObject *fieldobj, FmtState *fs,
+ const InternalFormatSpec *format)
{
- return convert_DUMMY(fieldobj, fs);
+ return format_DUMMY(fieldobj, fs);
}
/* returns a pointer to our conversion function, or NULL if invalid */
-Py_LOCAL_INLINE(ConversionFunction)
-conversion_function(CH_TYPE c)
+Py_LOCAL_INLINE(FormatFunction)
+format_function(CH_TYPE c)
{
switch (c) {
- case 'b': return convert_binary; /* base-2 */
- case 'c': return convert_char; /* as character */
- case 'd': return convert_decimal; /* decimal integer */
- case 'e': return convert_exponent; /* exponential notation */
- case 'E': return convert_exponentUC; /* exponential notation
- with uppercase 'E' */
- case 'f': return convert_fixed; /* fixed-point */
- case 'F': return convert_fixedUC; /* fixed-point with uppercase */
- case 'g': return convert_general; /* general number notation */
- case 'G': return convert_generalUC; /* general number notation
- with uppercase 'E' */
- case 'n': return convert_number; /* number in locale-specific
- format */
- case 'o': return convert_octal; /* octal */
- case 'r': return convert_repr; /* in repr() format */
- case 's': return convert_string; /* convert using str() */
- case 'x': return convert_hex; /* base 16 */
- case 'X': return convert_hexUC; /* base 16 uppercase */
- case '%': return convert_percentage; /* as percentage */
+ case 'b': return format_binary; /* base-2 */
+ case 'c': return format_char; /* as character */
+ case 'd': return format_decimal; /* decimal integer */
+ case 'e': return format_exponent; /* exponential notation */
+ case 'E': return format_exponentUC; /* exponential notation
+ with uppercase 'E' */
+ case 'f': return format_fixed; /* fixed-point */
+ case 'F': return format_fixedUC; /* fixed-point with uppercase */
+ case 'g': return format_general; /* general number notation */
+ case 'G': return format_generalUC; /* general number notation
+ with uppercase 'E' */
+ case 'n': return format_number; /* number in locale-specific
+ format */
+ case 'o': return format_octal; /* octal */
+ case 'r': return format_repr; /* in repr() format */
+ case 's': return format_string; /* convert using str() */
+ case 'x': return format_hex; /* base 16 */
+ case 'X': return format_hexUC; /* base 16 uppercase */
+ case '%': return format_percentage; /* as percentage */
default:
return NULL;
}
@@ -1020,7 +1083,7 @@
static int internal_render(FmtState *fs, PyObject *fieldobj)
{
InternalFormatSpec format;
- ConversionFunction conversion;
+ FormatFunction formatter;
if (!parse_internal_render_format_spec(fs, &format)) {
return 0;
@@ -1038,18 +1101,18 @@
}
}
- /* XXX handle conversion functions that logically map to
- other conversion functions? percent is the only one, and I'm not wild
+ /* XXX handle conversion functions that logically map to other
+ conversion functions? percent is the only one, and I'm not wild
about having percent at all*/
- conversion = conversion_function(format.type);
- if (conversion == NULL) {
+ formatter = format_function(format.type);
+ if (formatter == NULL) {
SetError(fs, "Invalid conversion character");
return 0;
}
- /* do the conversion, writing into the output string */
- return conversion(fieldobj, fs, &format);
+ /* do the formatting, writing into the output string */
+ return formatter(fieldobj, fs, &format);
#if 0
More information about the Python-checkins
mailing list