[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