[Python-checkins] r54143 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c

eric.smith python-checkins at python.org
Tue Mar 6 04:02:42 CET 2007


Author: eric.smith
Date: Tue Mar  6 04:02:40 2007
New Revision: 54143

Modified:
   sandbox/trunk/pep3101/README.txt
   sandbox/trunk/pep3101/test_simpleformat.py
   sandbox/trunk/pep3101/unicodeformat.c
Log:
Added 'n' formatting, as I understand it.  Added test cases, but they could use some work, such as testing different locales.  Added notes to README.txt about these issues.  Removed dummy formatter.

Modified: sandbox/trunk/pep3101/README.txt
==============================================================================
--- sandbox/trunk/pep3101/README.txt	(original)
+++ sandbox/trunk/pep3101/README.txt	Tue Mar  6 04:02:40 2007
@@ -61,4 +61,8 @@
     - Add capability to control exception handling to pep_differences
       and to code:  1) ability to dump exceptions into string, 2)
       ability to re-do lower exceptions or "pile-on"
+    - Refactor format_locale_number() and format_float() to avoid
+      massive code duplication.
+    - Test suite needs to test different locales for 'n' formatting.
+
 

Modified: sandbox/trunk/pep3101/test_simpleformat.py
==============================================================================
--- sandbox/trunk/pep3101/test_simpleformat.py	(original)
+++ sandbox/trunk/pep3101/test_simpleformat.py	Tue Mar  6 04:02:40 2007
@@ -1,6 +1,8 @@
 import unittest
 from test import test_support
 
+import locale
+
 import pep3101
 
 # Variables used for testing name mapper
@@ -274,6 +276,14 @@
         self.formatEqualsWithUnicode("(" + "1" * 100 + ")", "{0:()b}", -(2**100 - 1))
         self.formatEqualsWithUnicode("(" + " " * 98 + "1" * 100 + ")", "{0:=()200b}", -(2**100 - 1))
 
+    def test_number_specifier(self):
+        def test(value):
+            self.formatEqualsWithUnicode(locale.format("%f", value), "{0:n}", value)
+
+        test(0)
+        test(1)
+        test(10**100)
+
     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	Tue Mar  6 04:02:40 2007
@@ -1003,34 +1003,6 @@
 }
 
 
-/* XXX delete this when all internal conversions are implemented */
-static int
-format_DUMMY(PyObject *fieldobj, FmtState *fs)
-{
-    PyObject *myobj;
-    int ok;
-
-    /* Test implementation, only at top level */
-    CH_TYPE under = '_';
-
-    myobj = STROBJ_STR(fieldobj);
-    if (myobj == NULL)
-        return 0;
-    ok = output_data(fs, STROBJ_AS_PTR(myobj),
-                         STROBJ_GET_SIZE(myobj));
-    Py_DECREF(myobj);
-    if (!ok)
-        return 0;
-    if (fs->fieldspec.ptr != fs->fieldspec.end) {
-        if (!output_data(fs, &under, 1))
-            return 0;
-        if (!output_data(fs, fs->fieldspec.ptr,
-                             fs->fieldspec.end - fs->fieldspec.ptr))
-            return 0;
-    }
-    return 1;
-}
-
 /************************************************************************/
 /*************************  Builtin formatters  *************************/
 /************************************************************************/
@@ -1616,11 +1588,85 @@
     return 1;
 }
 
+/* this code is really the same as format_exponent, except it calls
+   PyOS_snprintf() instead of PyOS_ascii_formatd().  it needs to be
+   refactored to avoid all of the duplicate code. */
 static int
 format_locale_number(PyObject *fieldobj, FmtState *fs,
               const InternalFormatSpec *format)
 {
-    return format_DUMMY(fieldobj, fs);
+    /* first, do the conversion as 8-bit chars, using the platform's
+       snprintf.  then, if needed, convert to unicode. */
+
+    /* fmt = '%.' + `prec` + `type` + '%%'
+       worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/
+    char fmt[20];
+
+    double x;
+    CH_TYPE type = 'f';
+    Py_ssize_t precision = format->precision;
+    CH_TYPE *buf;
+    int buflen;
+    int len;
+    char* trailing = "";
+
+    /* 'F' is the same as 'f', per the PEP */
+    if (type == 'F')
+        type = 'f';
+
+    x = PyFloat_AsDouble(fieldobj);
+    if (x == -1.0 && PyErr_Occurred())
+	return 0;
+
+    if (precision < 0)
+	precision = 6;
+    if (type == 'f' && (fabs(x) / 1e25) >= 1e25)
+	type = 'g';
+
+    /* 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), "%%.%d%c%s", precision, (char)type, trailing);
+
+    /* this is taken from unicodeobject.c, except we don't force a
+       limit here, we dynamically allocate instead */
+    /* Worst case length calc to ensure no buffer overrun:
+
+       'g' formats:
+	 fmt = %#.<prec>g
+	 buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
+	    for any double rep.)
+	 len = 1 + prec + 1 + 2 + 5 = 9 + prec
+
+       'f' formats:
+	 buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50)
+	 len = 1 + 50 + 1 + prec = 52 + prec
+
+       If prec=0 the effective precision is 1 (the leading digit is
+       always given), therefore increase the length by one.
+
+    */
+    /* so, allocate the precision plus 54 chars (we add one additional
+       for the trailing percent).  do this allocation as the native
+       type, because we're going to convert to unicode anyway */
+    buflen = 54 + precision;
+    if (output_allocate(fs, buflen, &buf) == 0)
+        return 0;
+    PyOS_snprintf((char *)buf, buflen, fmt, x);
+
+#if C_UNICODE
+    len = strtounicode(buf, (char*)buf, -1);
+#else
+    /* compute the length.  I believe this is done because the return
+       value from snprintf above is unreliable */
+    len = strlen(buf);
+#endif
+
+    /* shrink the buffer down to how many characters we actually
+       wrote.  this is cheap, just pointer arithmetic */
+    output_shrink(fs, buflen - len);
+
+    return 1;
 }
 
 static int


More information about the Python-checkins mailing list