mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
gh-71494: string.Formatter: support keys/attributes in unnumbered fields (GH-21767)
This commit is contained in:
parent
0373926260
commit
22b2d37f42
3 changed files with 28 additions and 7 deletions
|
@ -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
|
||||
|
|
|
@ -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={}):
|
||||
|
|
|
@ -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]}'.
|
Loading…
Add table
Add a link
Reference in a new issue