diff --git a/Doc/library/string.rst b/Doc/library/string.rst index b7b92ecb14f8c8..153cbce7d83226 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -943,7 +943,8 @@ attributes: Alternatively, you can provide the entire regular expression pattern by overriding the class attribute *pattern*. If you do this, the value must be a -regular expression object with four named capturing groups. The capturing +regular expression pattern string, or a compiled regular expression +object, with four named capturing groups. The capturing groups correspond to the rules given above, along with the invalid placeholder rule: diff --git a/Lib/string.py b/Lib/string.py index 2eab6d4f595c4e..f6babf337e8e65 100644 --- a/Lib/string.py +++ b/Lib/string.py @@ -70,6 +70,11 @@ def __init_subclass__(cls): super().__init_subclass__() if 'pattern' in cls.__dict__: pattern = cls.pattern + if isinstance(pattern, _re.Pattern): + # An already-compiled pattern (which the documentation allows) + # is used as-is; re.compile() rejects flags on a compiled + # pattern. + return else: delim = _re.escape(cls.delimiter) id = cls.idpattern diff --git a/Lib/test/test_string.py b/Lib/test/test_string.py index 824b89ad517c12..537587aa9ad66d 100644 --- a/Lib/test/test_string.py +++ b/Lib/test/test_string.py @@ -272,6 +272,20 @@ def test_SafeTemplate(self): eq(s.safe_substitute(dict(who='tim', what='ham', meal='dinner')), 'tim likes ham for dinner') + def test_precompiled_pattern(self): + # A subclass may supply an already-compiled pattern; it must be reused, + # not recompiled (re.compile() rejects flags on a compiled pattern). + import re + compiled = re.compile( + r'\$(?:(?P\$)|(?P[a-z]+)|' + r'\{(?P[a-z]+)\}|(?P))') + class MyTemplate(Template): + pattern = compiled + self.assertIs(MyTemplate.pattern, compiled) + self.assertEqual( + MyTemplate('$who likes $what').substitute(who='tim', what='ham'), + 'tim likes ham') + def test_invalid_placeholders(self): raises = self.assertRaises s = Template('$who likes $') diff --git a/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst b/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst new file mode 100644 index 00000000000000..483340d3504215 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-12-00-00.gh-issue-153056.tMpLat.rst @@ -0,0 +1,3 @@ +Fix :class:`string.Template` raising a spurious :exc:`ValueError` when the +*pattern* attribute is a compiled regular expression object, which the +documentation allows.