]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-71494: string.Formatter: support keys/attributes in unnumbered fields (GH-21767)
authorqm2k <qm2k@yandex.ru>
Fri, 31 Jan 2025 12:16:24 +0000 (12:16 +0000)
committerGitHub <noreply@github.com>
Fri, 31 Jan 2025 12:16:24 +0000 (13:16 +0100)
Lib/string.py
Lib/test/test_string.py
Misc/NEWS.d/next/Library/2020-08-07-16-55-57.bpo-27307.Xqzzda.rst [new file with mode: 0644]

index 2eab6d4f595c4e1b42a4902fcaf790ce5dd8e5f2..c4f05c7223ce8a15f428f6d618533cf7579b00b4 100644 (file)
@@ -212,19 +212,20 @@ class Formatter:
                 # this is some markup, find the object and do
                 #  the formatting
 
-                # handle arg indexing when empty field_names are given.
-                if field_name == '':
+                # handle arg indexing when empty field first parts are given.
+                field_first, _ = _string.formatter_field_name_split(field_name)
+                if field_first == '':
                     if auto_arg_index is False:
                         raise ValueError('cannot switch from manual field '
                                          'specification to automatic field '
                                          'numbering')
-                    field_name = str(auto_arg_index)
+                    field_name = str(auto_arg_index) + field_name
                     auto_arg_index += 1
-                elif field_name.isdigit():
+                elif isinstance(field_first, int):
                     if auto_arg_index:
-                        raise ValueError('cannot switch from manual field '
-                                         'specification to automatic field '
-                                         'numbering')
+                        raise ValueError('cannot switch from automatic field '
+                                         'numbering to manual field '
+                                         'specification')
                     # disable auto arg incrementing, if it gets
                     # used later on, then an exception will be raised
                     auto_arg_index = False
index 824b89ad517c120b0a665e85ae8ed8de7e8a8fe6..f6d112d8a93ec4e84ba71759b6fa9cda8196d405 100644 (file)
@@ -1,6 +1,7 @@
 import unittest
 import string
 from string import Template
+import types
 
 
 class ModuleTest(unittest.TestCase):
@@ -101,6 +102,24 @@ class ModuleTest(unittest.TestCase):
         with self.assertRaises(KeyError):
             fmt.format("{0[2]}{0[0]}", {})
 
+    def test_auto_numbering_lookup(self):
+        fmt = string.Formatter()
+        namespace = types.SimpleNamespace(foo=types.SimpleNamespace(bar='baz'))
+        widths = [None, types.SimpleNamespace(qux=4)]
+        self.assertEqual(
+            fmt.format("{.foo.bar:{[1].qux}}", namespace, widths), 'baz ')
+
+    def test_auto_numbering_reenterability(self):
+        class ReenteringFormatter(string.Formatter):
+            def format_field(self, value, format_spec):
+                if format_spec.isdigit() and int(format_spec) > 0:
+                    return self.format('{:{}}!', value, int(format_spec) - 1)
+                else:
+                    return super().format_field(value, format_spec)
+        fmt = ReenteringFormatter()
+        x = types.SimpleNamespace(a='X')
+        self.assertEqual(fmt.format('{.a:{}}', x, 3), 'X!!!')
+
     def test_override_get_value(self):
         class NamespaceFormatter(string.Formatter):
             def __init__(self, namespace={}):
diff --git a/Misc/NEWS.d/next/Library/2020-08-07-16-55-57.bpo-27307.Xqzzda.rst b/Misc/NEWS.d/next/Library/2020-08-07-16-55-57.bpo-27307.Xqzzda.rst
new file mode 100644 (file)
index 0000000..6e7a856
--- /dev/null
@@ -0,0 +1 @@
+Add attribute and item access support to :class:`string.Formatter` in auto-numbering mode, which allows format strings like '{.name}' and '{[1]}'.