[pypy-commit] pypy py3.6: support for '_' format modifiert for formatting strings

cfbolz pypy.commits at gmail.com
Sun May 27 15:45:46 EDT 2018


Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: py3.6
Changeset: r94693:846993741acb
Date: 2018-05-27 21:44 +0200
http://bitbucket.org/pypy/pypy/changeset/846993741acb/

Log:	support for '_' format modifiert for formatting strings

diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py
--- a/pypy/objspace/std/newformat.py
+++ b/pypy/objspace/std/newformat.py
@@ -455,7 +455,7 @@
             self._align = default_align
             self._alternate = False
             self._sign = "\0"
-            self._thousands_sep = False
+            self._thousands_sep = "\0"
             self._precision = -1
             the_type = default_type
             spec = self.spec
@@ -488,8 +488,17 @@
                 i += 1
             self._width, i = _parse_int(self.space, spec, i, length)
             if length != i and spec[i] == ",":
-                self._thousands_sep = True
+                self._thousands_sep = ","
                 i += 1
+            if length != i and spec[i] == "_":
+                if self._thousands_sep != "\0":
+                    raise oefmt(
+                        space.w_ValueError, "Cannot specify both ',' and '_'.")
+                self._thousands_sep = "_"
+                i += 1
+                if length != i and spec[i] == ",":
+                    raise oefmt(
+                        space.w_ValueError, "Cannot specify both ',' and '_'.")
             if length != i and spec[i] == ".":
                 i += 1
                 self._precision, i = _parse_int(self.space, spec, i, length)
@@ -509,7 +518,7 @@
                     the_type = presentation_type
                 i += 1
             self._type = the_type
-            if self._thousands_sep:
+            if self._thousands_sep != "\0":
                 tp = self._type
                 if (tp == "d" or
                     tp == "e" or
@@ -522,8 +531,15 @@
                     tp == "\0"):
                     # ok
                     pass
+                elif self._thousands_sep == "_" and (
+                        tp == "b" or
+                        tp == "o" or
+                        tp == "x" or
+                        tp == "X"):
+                    pass # ok
                 else:
-                    raise oefmt(space.w_ValueError, "invalid type with ','")
+                    raise oefmt(space.w_ValueError,
+                                "invalid type with ',' or '_'")
             return False
 
         def _calc_padding(self, string, length):
@@ -601,10 +617,13 @@
         def _get_locale(self, tp):
             if tp == "n":
                 dec, thousands, grouping = rlocale.numeric_formatting()
-            elif self._thousands_sep:
+            elif self._thousands_sep != "\0":
+                thousands = self._thousands_sep
                 dec = "."
-                thousands = ","
                 grouping = "\3"
+                if tp in "boxX":
+                    assert self._thousands_sep == "_"
+                    grouping = "\4"
             else:
                 dec = "."
                 thousands = ""
diff --git a/pypy/objspace/std/test/test_newformat.py b/pypy/objspace/std/test/test_newformat.py
--- a/pypy/objspace/std/test/test_newformat.py
+++ b/pypy/objspace/std/test/test_newformat.py
@@ -246,12 +246,18 @@
     def test_invalid(self):
         raises(ValueError, format, self.i(8), "s")
         raises(ValueError, format, self.i(8), ".3")
+        raises(ValueError, format, self.i(3), '_,')
+        raises(ValueError, format, self.i(3), ',_')
+        raises(ValueError, format, self.i(3), '_,d')
+        raises(ValueError, format, self.i(3), ',_d')
+
 
     def test_c(self):
         a = self.i(ord("a"))
         assert format(a, "c") == "a"
         raises(ValueError, format, a, "-c")
         raises(ValueError, format, a, ",c")
+        raises(ValueError, format, a, "_c")
         raises(ValueError, format, a, "#c")
         assert format(a, "3c") == "  a"
         assert format(a, "<3c") == "a  "
@@ -262,6 +268,8 @@
     def test_binary(self):
         assert format(self.i(2), "b") == "10"
         assert format(self.i(2), "#b") == "0b10"
+        assert format(12345, '_b') == '11_0000_0011_1001'
+        raises(ValueError, format, self.i(1234567890), ',b')
 
     def test_octal(self):
         assert format(self.i(8), "o") == "10"
@@ -270,6 +278,8 @@
         assert format(self.i(-8), "#o") == "-0o10"
         assert format(self.i(8), "+o") == "+10"
         assert format(self.i(8), "+#o") == "+0o10"
+        raises(ValueError, format, self.i(1234567890), ',o')
+        assert format(self.i(1234567890), '_o'), '111_4540_1322'
 
     def test_hex(self):
         assert format(self.i(16), "x") == "10"
@@ -278,6 +288,10 @@
         assert format(self.i(10), "#x") == "0xa"
         assert format(self.i(10), "X") == "A"
         assert format(self.i(10), "#X") == "0XA"
+        raises(ValueError, format, 1234567890, ',x')
+        assert format(1234567890, '_x') == '4996_02d2'
+        assert format(1234567890, '_X') == '4996_02D2'
+
 
     def test_padding(self):
         assert format(self.i(6), "3") == "  6"
@@ -310,6 +324,14 @@
         assert format(self.i(1234), "0=10,") == "00,001,234"
         assert format(self.i(1234), "010,") == "00,001,234"
 
+    def test_thousands_separator_underscore(self):
+        assert format(self.i(123), "_") == "123"
+        assert format(self.i(12345), "_") == "12_345"
+        assert format(self.i(123456789), "_") == "123_456_789"
+        assert format(self.i(12345), "7_") == " 12_345"
+        assert format(self.i(12345), "<7_") == "12_345 "
+        assert format(self.i(1234), "0=10_") == "00_001_234"
+        assert format(self.i(1234), "010_") == "00_001_234"
 
 class AppTestIntFormatting(BaseIntegralFormattingTest):
     def setup_class(cls):
@@ -342,6 +364,9 @@
     def test_digit_separator(self):
         assert format(-1234., "012,f") == "-1,234.000000"
 
+    def test_digit_separator_underscore(self):
+        assert format(-1234., "012_f") == "-1_234.000000"
+
     def test_locale(self):
         import locale
         for name in ['en_US.UTF8', 'en_US', 'en']:


More information about the pypy-commit mailing list