[Python-3000-checkins] r64960 - in python/branches/py3k: Lib/test/test_types.py Lib/test/test_unicode.py Objects/stringlib/formatter.h

eric.smith python-3000-checkins at python.org
Tue Jul 15 15:02:42 CEST 2008


Author: eric.smith
Date: Tue Jul 15 15:02:41 2008
New Revision: 64960

Log:
Forward port of r64958Added '#' formatting to integers.  This adds the 0b, 0o, or 0x prefix for bin, oct, hex.  There's still one failing case, and I need to finish the docs.  I hope to finish those today.

Modified:
   python/branches/py3k/Lib/test/test_types.py
   python/branches/py3k/Lib/test/test_unicode.py
   python/branches/py3k/Objects/stringlib/formatter.h

Modified: python/branches/py3k/Lib/test/test_types.py
==============================================================================
--- python/branches/py3k/Lib/test/test_types.py	(original)
+++ python/branches/py3k/Lib/test/test_types.py	Tue Jul 15 15:02:41 2008
@@ -293,6 +293,40 @@
         test(1234, "+b", "+10011010010")
         test(-1234, "+b", "-10011010010")
 
+        # alternate (#) formatting
+        test(0, "#b", '0b0')
+        test(0, "-#b", '0b0')
+        test(1, "-#b", '0b1')
+        test(-1, "-#b", '-0b1')
+        test(-1, "-#5b", ' -0b1')
+        test(1, "+#5b", ' +0b1')
+        test(100, "+#b", '+0b1100100')
+#        test(100, "#012b", '0b001100100')
+
+        test(0, "#o", '0o0')
+        test(0, "-#o", '0o0')
+        test(1, "-#o", '0o1')
+        test(-1, "-#o", '-0o1')
+        test(-1, "-#5o", ' -0o1')
+        test(1, "+#5o", ' +0o1')
+        test(100, "+#o", '+0o144')
+
+        test(0, "#x", '0x0')
+        test(0, "-#x", '0x0')
+        test(1, "-#x", '0x1')
+        test(-1, "-#x", '-0x1')
+        test(-1, "-#5x", ' -0x1')
+        test(1, "+#5x", ' +0x1')
+        test(100, "+#x", '+0x64')
+
+        test(0, "#X", '0X0')
+        test(0, "-#X", '0X0')
+        test(1, "-#X", '0X1')
+        test(-1, "-#X", '-0X1')
+        test(-1, "-#5X", ' -0X1')
+        test(1, "+#5X", ' +0X1')
+        test(100, "+#X", '+0X64')
+
         # make sure these are errors
 
         # precision disallowed
@@ -509,6 +543,10 @@
                 self.assertRaises(ValueError, format, 1e-100, format_spec)
                 self.assertRaises(ValueError, format, -1e-100, format_spec)
 
+        # Alternate formatting is not supported
+        self.assertRaises(ValueError, format, 0.0, '#')
+        self.assertRaises(ValueError, format, 0.0, '#20f')
+
 
 def test_main():
     run_unittest(TypesTests)

Modified: python/branches/py3k/Lib/test/test_unicode.py
==============================================================================
--- python/branches/py3k/Lib/test/test_unicode.py	(original)
+++ python/branches/py3k/Lib/test/test_unicode.py	Tue Jul 15 15:02:41 2008
@@ -700,6 +700,10 @@
         self.assertRaises(ValueError, format, "", "-")
         self.assertRaises(ValueError, "{0:=s}".format, '')
 
+        # Alternate formatting is not supported
+        self.assertRaises(ValueError, format, '', '#')
+        self.assertRaises(ValueError, format, '', '#20')
+
     def test_formatting(self):
         string_tests.MixinStrUnicodeUserStringTest.test_formatting(self)
         # Testing Unicode formatting strings...

Modified: python/branches/py3k/Objects/stringlib/formatter.h
==============================================================================
--- python/branches/py3k/Objects/stringlib/formatter.h	(original)
+++ python/branches/py3k/Objects/stringlib/formatter.h	Tue Jul 15 15:02:41 2008
@@ -89,6 +89,7 @@
 typedef struct {
     STRINGLIB_CHAR fill_char;
     STRINGLIB_CHAR align;
+    int alternate;
     STRINGLIB_CHAR sign;
     Py_ssize_t width;
     Py_ssize_t precision;
@@ -117,6 +118,7 @@
 
     format->fill_char = '\0';
     format->align = '\0';
+    format->alternate = 0;
     format->sign = '\0';
     format->width = -1;
     format->precision = -1;
@@ -154,6 +156,13 @@
         ++ptr;
     }
 
+    /* If the next character is #, we're in alternate mode.  This only
+       applies to integers. */
+    if (end-ptr >= 1 && ptr[0] == '#') {
+	format->alternate = 1;
+	++ptr;
+    }
+
     /* XXX add error checking */
     specified_width = get_integer(&ptr, end, &format->width);
 
@@ -221,7 +230,8 @@
    and more efficient enough to justify a little obfuscation? */
 static void
 calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
-                   Py_ssize_t n_digits, const InternalFormatSpec *format)
+		   Py_ssize_t n_prefix, Py_ssize_t n_digits,
+		   const InternalFormatSpec *format)
 {
     r->n_lpadding = 0;
     r->n_spadding = 0;
@@ -232,13 +242,15 @@
     r->n_rsign = 0;
 
     /* the output will look like:
-       |                                                           |
-       | <lpadding> <lsign> <spadding> <digits> <rsign> <rpadding> |
-       |                                                           |
+       |                                                                    |
+       | <lpadding> <lsign> <prefix> <spadding> <digits> <rsign> <rpadding> |
+       |                                                                    |
 
        lsign and rsign are computed from format->sign and the actual
        sign of the number
 
+       prefix is given (it's for the '0x' prefix)
+
        digits is already known
 
        the total width is either given, or computed from the
@@ -363,6 +375,14 @@
         goto done;
     }
 
+    /* alternate is not allowed on strings */
+    if (format->alternate) {
+        PyErr_SetString(PyExc_ValueError,
+                        "Alternate form (#) not allowed in string format "
+			"specifier");
+        goto done;
+    }
+
     /* '=' alignment not allowed on strings */
     if (format->align == '=') {
         PyErr_SetString(PyExc_ValueError,
@@ -505,31 +525,33 @@
     }
     else {
         int base;
-	int leading_chars_to_skip;  /* Number of characters added by
-				       PyNumber_ToBase that we want to
-				       skip over. */
+	int leading_chars_to_skip = 0;  /* Number of characters added by
+				           PyNumber_ToBase that we want to
+				           skip over. */
 
         /* Compute the base and how many characters will be added by
            PyNumber_ToBase */
         switch (format->type) {
         case 'b':
             base = 2;
-            leading_chars_to_skip = 2; /* 0b */
+	    if (!format->alternate)
+		leading_chars_to_skip = 2; /* 0b */
             break;
         case 'o':
             base = 8;
-            leading_chars_to_skip = 2; /* 0o */
+	    if (!format->alternate)
+		leading_chars_to_skip = 2; /* 0o */
             break;
         case 'x':
         case 'X':
             base = 16;
-            leading_chars_to_skip = 2; /* 0x */
+	    if (!format->alternate)
+		leading_chars_to_skip = 2; /* 0x */
             break;
         default:  /* shouldn't be needed, but stops a compiler warning */
         case 'd':
         case 'n':
             base = 10;
-            leading_chars_to_skip = 0;
             break;
         }
 
@@ -564,7 +586,7 @@
 			       0, &n_grouping_chars, 0);
 
     /* Calculate the widths of the various leading and trailing parts */
-    calc_number_widths(&spec, sign, n_digits + n_grouping_chars, format);
+    calc_number_widths(&spec, sign, 0, n_digits + n_grouping_chars, format);
 
     /* Allocate a new string to hold the result */
     result = STRINGLIB_NEW(NULL, spec.n_total);
@@ -670,6 +692,14 @@
     Py_UNICODE unicodebuf[FLOAT_FORMATBUFLEN];
 #endif
 
+    /* alternate is not allowed on floats. */
+    if (format->alternate) {
+        PyErr_SetString(PyExc_ValueError,
+                        "Alternate form (#) not allowed in float format "
+			"specifier");
+        goto done;
+    }
+
     /* first, do the conversion as 8-bit chars, using the platform's
        snprintf.  then, if needed, convert to unicode. */
 
@@ -730,7 +760,7 @@
         --n_digits;
     }
 
-    calc_number_widths(&spec, sign, n_digits, format);
+    calc_number_widths(&spec, sign, 0, n_digits, format);
 
     /* allocate a string with enough space */
     result = STRINGLIB_NEW(NULL, spec.n_total);


More information about the Python-3000-checkins mailing list