Coverage for src/regex_template/__init__.py: 100%
22 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-13 11:01 -0700
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-13 11:01 -0700
1# SPDX-FileCopyrightText: 2025-present Trey Hunner
2#
3# SPDX-License-Identifier: MIT
4"""regex_template - Compiled regular expressions with auto-escaped interpolations"""
6import re
7from string import Formatter
8from string.templatelib import Interpolation, Template
11__all__ = ["compile"]
14# https://discuss.python.org/t/add-convert-function-to-string-templatelib/94569/10
15_convert = classmethod(Formatter.convert_field).__get__(Formatter)
18def compile(template, flags=0, verbose=True):
19 """
20 Compile a regular expression with auto-escaped interpolations.
22 Only accepts t-string Templates. Automatically escapes interpolated values
23 unless they use the :safe format specifier.
25 Args:
26 template: A t-string Template to compile
27 flags: Regular expression flags (same as re.compile)
28 verbose: If True, adds re.VERBOSE flag for readable patterns
30 Returns:
31 A compiled regular expression Pattern object
33 Raises:
34 TypeError: If template is not a Template object (t-string)
35 """
36 if not isinstance(template, Template):
37 raise TypeError(
38 f"regex_template.compile() only accepts t-string Templates, "
39 f"got {type(template).__name__}. Use re.compile() for regular strings."
40 )
42 if verbose:
43 flags |= re.VERBOSE
45 # Process t-string Template
46 parts = []
47 for item in template:
48 match item:
49 case Interpolation(value, _, conversion, format_spec):
50 value = _convert(value, conversion)
51 if format_spec == "safe":
52 parts.append(str(value))
53 else:
54 formatted_value = format(value, format_spec)
55 parts.append(re.escape(str(formatted_value)))
56 case _:
57 parts.append(item)
58 return re.compile("".join(parts), flags=flags)