[Python-checkins] r54153 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c

eric.smith python-checkins at python.org
Tue Mar 6 12:23:23 CET 2007


Author: eric.smith
Date: Tue Mar  6 12:23:22 2007
New Revision: 54153

Modified:
   sandbox/trunk/pep3101/test_simpleformat.py
   sandbox/trunk/pep3101/unicodeformat.c
Log:
At Patrick Maupin's suggestion, improved the logic for looking up default internal formatter if not type specifier is present.  Added test cases for same.  Removed bogus printf left over from debugging.

Modified: sandbox/trunk/pep3101/test_simpleformat.py
==============================================================================
--- sandbox/trunk/pep3101/test_simpleformat.py	(original)
+++ sandbox/trunk/pep3101/test_simpleformat.py	Tue Mar  6 12:23:22 2007
@@ -52,18 +52,7 @@
         self.assertEquals(val, unicode(result.upper()))
 
     def formatRaises(self, exc, text, *args, **kwargs):
-        exc = exc or Exception #StringFormat.FormatError
-        text = str(text)
-        #prevState = StringFormat.strict_format_errors
-        #StringFormat.strict_format_errors = True
-        try:
-            self.assertRaises(exc,
-                              lambda: pep3101.format(
-                                text, *args, **kwargs))
-        finally:
-            pass
-            #StringFormat.strict_format_errors = prevState
-
+        self.assertRaises(exc, pep3101.format, text, *args, **kwargs)
 
     def test_basic(self):
         # directly from the pep intro
@@ -286,7 +275,17 @@
 
     def test_missing_type_specifier(self):
         # make sure floats use 'g', ints and longs 'd', and everything else 's'
-        pass
+
+        self.formatEqualsWithUnicode("3.5", "{0}", 3.5)
+        self.formatEqualsWithUnicode("5e+99", "{0}", 0.5e100)
+        self.formatEqualsWithUnicode("5e-101", "{0}", 0.5e-100)
+        self.formatEqualsWithUnicode("0", "{0}", 0)
+        self.formatEqualsWithUnicode("1", "{0}", 1)
+        self.formatEqualsWithUnicode("-1", "{0}", -1)
+        self.formatEqualsWithUnicode("(1)", "{0:()}", -1)
+        self.formatEqualsWithUnicode("1" + "0" * 100, "{0}", 10**100)
+        self.formatEqualsWithUnicode("hello, world", "{0}", "hello, world")
+        self.formatEqualsWithUnicode("        hello, world", "{0:>20}", "hello, world")
 
     def test_custom_format(self):
         class Custom(object):
@@ -306,6 +305,12 @@
         self.formatRaises(ValueError, "{{ {{{0}}", True)
         self.formatRaises(ValueError, "{0}}", True)
 
+    def test_invalid_type_specifier(self):
+        self.formatRaises(ValueError, "{0::}", 0)
+        self.formatRaises(ValueError, "{0:&}", 0)
+        self.formatRaises(ValueError, "{0:k}", 0)
+        self.formatRaises(ValueError, "{0:4<10.20K}", 0)
+
     def test_name_mapper(self):
         mydict = dict(foo=1, bar=2)
         dict2 = mydict, dict(foobar=3)

Modified: sandbox/trunk/pep3101/unicodeformat.c
==============================================================================
--- sandbox/trunk/pep3101/unicodeformat.c	(original)
+++ sandbox/trunk/pep3101/unicodeformat.c	Tue Mar  6 12:23:22 2007
@@ -1511,7 +1511,7 @@
 }
 
 /* use type instead of format->type, so that it can be overridden by
-   format_locale_number() */
+   format_number() */
 static int
 _format_float(CH_TYPE type, PyObject *fieldobj, FmtState *fs,
               const InternalFormatSpec *format,
@@ -1535,10 +1535,8 @@
         type = 'f';
 
     x = PyFloat_AsDouble(fieldobj);
-    if (x == -1.0 && PyErr_Occurred()) {
-        printf("not a float\n");
+    if (x == -1.0 && PyErr_Occurred())
 	return 0;
-    }
 
     if (type == '%') {
         type = 'f';
@@ -1616,8 +1614,8 @@
 /* this code is really the same as format_exponent, except it calls
    PyOS_snprintf() instead of PyOS_ascii_formatd(). */
 static int
-format_locale_number(PyObject *fieldobj, FmtState *fs,
-                     const InternalFormatSpec *format)
+format_number(PyObject *fieldobj, FmtState *fs,
+              const InternalFormatSpec *format)
 {
     return _format_float('f', fieldobj, fs, format, snprintf_double);
 }
@@ -1662,32 +1660,52 @@
     return ok;
 }
 
-/* returns a pointer to our conversion function, or NULL if invalid */
+static int
+format_bad_type_specifier(PyObject *fieldobj, FmtState *fs,
+                          const InternalFormatSpec *format)
+{
+    SetError(fs, "Invalid conversion character");
+    return 0;
+}
+
+/* returns a pointer to our conversion function.  also sets
+   format->type based on the type of fieldobj, if format->type was not
+   specified.  if format->type is unknown, returns a pointer to the
+   psueod-conversion function format_bad_type_specifier() */
 Py_LOCAL_INLINE(FormatFunction)
-format_function(CH_TYPE c)
+format_function(PyObject *fieldobj, InternalFormatSpec *format)
 {
-    switch (c) {
-    case 'b': return format_binary;          /* base-2 */
-    case 'c': return format_char;            /* as character */
-    case 'n': return format_locale_number;   /* number in locale-specific
+    while (1)
+        switch (format->type) {
+        case 'b': return format_binary;      /* base-2 */
+        case 'c': return format_char;        /* as character */
+        case 'n': return format_number;      /* number in locale-specific
                                                 format */
-    case 'd':                                /* decimal integer */
-    case 'o':                                /* octal */
-    case 'x':                                /* base 16 */
-    case 'X': return format_integer;         /* base 16 uppercase */
-    case 'r': return format_repr;            /* in repr() format */
-    case 's': return format_string;          /* convert using str() */
-    case 'e':                                /* exponential notation */
-    case 'E':                                /* exponential notation
+        case 'd':                            /* decimal integer */
+        case 'o':                            /* octal */
+        case 'x':                            /* base 16 */
+        case 'X': return format_integer;     /* base 16 uppercase */
+        case 'r': return format_repr;        /* in repr() format */
+        case 's': return format_string;      /* convert using str() */
+        case 'e':                            /* exponential notation */
+        case 'E':                            /* exponential notation
                                                 with uppercase 'E' */
-    case 'f':                                /* fixed-point */
-    case 'F':                                /* fixed-point with uppercase */
-    case 'g':                                /* general number notation */
-    case 'G':                                /* general number notation
+        case 'f':                            /* fixed-point */
+        case 'F':                            /* fixed-point with uppercase */
+        case 'g':                            /* general number notation */
+        case 'G':                            /* general number notation
                                                 with uppercase 'E' */
-    case '%': return format_float;           /* as percentage */
-    default:
-        return NULL;
+        case '%': return format_float;       /* as percentage */
+        case '\0':
+            /* if no type character was specified, look up the default
+               type character, based on the type of our object, then
+               loop around and execute the switch statement again */
+            format->type = (PyInt_Check(fieldobj) ||
+                            PyLong_Check(fieldobj)) ? 'd'
+                            : (PyFloat_Check(fieldobj)) ?'g' : 's';
+            continue;
+        default:
+            return format_bad_type_specifier;
     }
 }
 
@@ -1697,33 +1715,15 @@
 static int internal_render(FmtState *fs, PyObject *fieldobj)
 {
     InternalFormatSpec format;
-    FormatFunction formatter;
 
     if (!parse_internal_render_format_spec(fs, &format)) {
         return 0;
     }
 
-    /* if no type character was specified, look up the default
-       type character, based on the type of our object */
-    if (format.type == '\0') {
-        if (PyInt_Check(fieldobj) || PyLong_Check(fieldobj)) {
-            format.type = 'd';
-        } else if (PyFloat_Check(fieldobj)) {
-            format.type = 'g';
-        } else {
-            format.type = 's';
-        }
-    }
-
-    /* find the formatter function */
-    formatter = format_function(format.type);
-    if (formatter == NULL) {
-        SetError(fs, "Invalid conversion character");
-        return 0;
-    }
-
-    /* do the formatting, writing into the output string */
-    return formatter(fieldobj, fs, &format);
+    /* do the formatting, writing into the output string.  if there's
+     * an error in format.type, this still works by calling
+     * format_bad_type_specifier() to set an error */
+    return format_function(fieldobj, &format)(fieldobj, fs, &format);
 }
 
 static PyObject *


More information about the Python-checkins mailing list