Coverage for src/regex_template/__init__.py: 100%

1# SPDX-FileCopyrightText: 2025-present Trey Hunner

2#

3# SPDX-License-Identifier: MIT

4"""regex_template - Compiled regular expressions with auto-escaped interpolations"""

5

6 import re

7 from string import Formatter

8 from string.templatelib import Interpolation, Template

9

10

11 __all__ = ["compile"]

12

13

14# https://discuss.python.org/t/add-convert-function-to-string-templatelib/94569/10

15 _convert = classmethod(Formatter.convert_field).__get__(Formatter)

16

17

18 def compile(template, flags=0, verbose=True):

19 """

20 Compile a regular expression with auto-escaped interpolations.

21

22 Only accepts t-string Templates. Automatically escapes interpolated values

23 unless they use the :safe format specifier.

24

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

29

30 Returns:

31 A compiled regular expression Pattern object

32

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 )

41

42 if verbose:

43 flags |= re.VERBOSE

44

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)

59