mirror of
https://github.com/python/cpython.git
synced 2024-11-24 02:15:30 +08:00
bpo-1198569: Allow string.Template braced pattern to be different (#3288)
* bpo-1198569: Allow the braced pattern to be different ``string.Template`` subclasses can optionally define ``braceidpattern`` if they want to specify different placeholder patterns inside and outside the braces. If None (the default) it falls back to ``idpattern``.
This commit is contained in:
parent
f9f17346d7
commit
ba4279683f
@ -754,9 +754,21 @@ attributes:
|
||||
be set in the subclass's class namespace).
|
||||
|
||||
* *idpattern* -- This is the regular expression describing the pattern for
|
||||
non-braced placeholders (the braces will be added automatically as
|
||||
appropriate). The default value is the regular expression
|
||||
``[_a-z][_a-z0-9]*``.
|
||||
non-braced placeholders. The default value is the regular expression
|
||||
``[_a-z][_a-z0-9]*``. If this is given and *braceidpattern* is ``None``
|
||||
this pattern will also apply to braced placeholders.
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
*braceidpattern* can be used to define separate patterns used inside and
|
||||
outside the braces.
|
||||
|
||||
* *braceidpattern* -- This is like *idpattern* but describes the pattern for
|
||||
braced placeholders. Defaults to ``None`` which means to fall back to
|
||||
*idpattern* (i.e. the same pattern is used both inside and outside braces).
|
||||
If given, this allows you to define different patterns for braced and
|
||||
unbraced placeholders.
|
||||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
* *flags* -- The regular expression flags that will be applied when compiling
|
||||
the regular expression used for recognizing substitutions. The default value
|
||||
|
@ -57,7 +57,7 @@ class _TemplateMetaclass(type):
|
||||
%(delim)s(?:
|
||||
(?P<escaped>%(delim)s) | # Escape sequence of two delimiters
|
||||
(?P<named>%(id)s) | # delimiter and a Python identifier
|
||||
{(?P<braced>%(id)s)} | # delimiter and a braced identifier
|
||||
{(?P<braced>%(bid)s)} | # delimiter and a braced identifier
|
||||
(?P<invalid>) # Other ill-formed delimiter exprs
|
||||
)
|
||||
"""
|
||||
@ -70,6 +70,7 @@ class _TemplateMetaclass(type):
|
||||
pattern = _TemplateMetaclass.pattern % {
|
||||
'delim' : _re.escape(cls.delimiter),
|
||||
'id' : cls.idpattern,
|
||||
'bid' : cls.braceidpattern or cls.idpattern,
|
||||
}
|
||||
cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE)
|
||||
|
||||
@ -79,6 +80,7 @@ class Template(metaclass=_TemplateMetaclass):
|
||||
|
||||
delimiter = '$'
|
||||
idpattern = r'[_a-z][_a-z0-9]*'
|
||||
braceidpattern = None
|
||||
flags = _re.IGNORECASE
|
||||
|
||||
def __init__(self, template):
|
||||
|
@ -282,6 +282,30 @@ class TestTemplate(unittest.TestCase):
|
||||
s = PathPattern('$bag.foo.who likes to eat a bag of $bag.what')
|
||||
self.assertEqual(s.substitute(m), 'tim likes to eat a bag of ham')
|
||||
|
||||
def test_idpattern_override_inside_outside(self):
|
||||
# bpo-1198569: Allow the regexp inside and outside braces to be
|
||||
# different when deriving from Template.
|
||||
class MyPattern(Template):
|
||||
idpattern = r'[a-z]+'
|
||||
braceidpattern = r'[A-Z]+'
|
||||
flags = 0
|
||||
m = dict(foo='foo', BAR='BAR')
|
||||
s = MyPattern('$foo ${BAR}')
|
||||
self.assertEqual(s.substitute(m), 'foo BAR')
|
||||
|
||||
def test_idpattern_override_inside_outside_invalid_unbraced(self):
|
||||
# bpo-1198569: Allow the regexp inside and outside braces to be
|
||||
# different when deriving from Template.
|
||||
class MyPattern(Template):
|
||||
idpattern = r'[a-z]+'
|
||||
braceidpattern = r'[A-Z]+'
|
||||
flags = 0
|
||||
m = dict(foo='foo', BAR='BAR')
|
||||
s = MyPattern('$FOO')
|
||||
self.assertRaises(ValueError, s.substitute, m)
|
||||
s = MyPattern('${bar}')
|
||||
self.assertRaises(ValueError, s.substitute, m)
|
||||
|
||||
def test_pattern_override(self):
|
||||
class MyPattern(Template):
|
||||
pattern = r"""
|
||||
|
@ -0,0 +1,3 @@
|
||||
``string.Template`` subclasses can optionally define ``braceidpattern`` if
|
||||
they want to specify different placeholder patterns inside and outside the
|
||||
braces. If None (the default) it falls back to ``idpattern``.
|
Loading…
Reference in New Issue
Block a user