Coverage for tdom / placeholders.py: 100%
44 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-17 23:32 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-17 23:32 +0000
1import random
2import re
3import string
5from .template_utils import TemplateRef
7FRAGMENT_TAG = f"t🐍f-{''.join(random.choices(string.ascii_lowercase, k=4))}-"
8_PLACEHOLDER_PREFIX = f"t🐍{''.join(random.choices(string.ascii_lowercase, k=2))}-"
9_PLACEHOLDER_SUFFIX = f"-{''.join(random.choices(string.ascii_lowercase, k=2))}🐍t"
10_PLACEHOLDER_PATTERN = re.compile(
11 re.escape(_PLACEHOLDER_PREFIX) + r"(\d+)" + re.escape(_PLACEHOLDER_SUFFIX)
12)
15def make_placeholder(i: int) -> str:
16 """Generate a placeholder for the i-th interpolation."""
17 return f"{_PLACEHOLDER_PREFIX}{i}{_PLACEHOLDER_SUFFIX}"
20def match_placeholders(s: str) -> list[re.Match[str]]:
21 """Find all placeholders in a string."""
22 return list(_PLACEHOLDER_PATTERN.finditer(s))
25def find_placeholders(s: str) -> TemplateRef:
26 """
27 Find all placeholders in a string and return a TemplateRef.
29 If no placeholders are found, returns a static TemplateRef.
30 """
31 matches = match_placeholders(s)
32 if not matches:
33 return TemplateRef.literal(s)
35 strings: list[str] = []
36 i_indexes: list[int] = []
37 last_index = 0
38 for match in matches:
39 start, end = match.span()
40 strings.append(s[last_index:start])
41 i_indexes.append(int(match[1]))
42 last_index = end
43 strings.append(s[last_index:])
45 return TemplateRef(tuple(strings), tuple(i_indexes))
48class PlaceholderState:
49 known: set[int]
50 """Collection of currently 'known and active' placeholder indexes."""
52 def __init__(self):
53 self.known = set()
55 @property
56 def is_empty(self) -> bool:
57 return len(self.known) == 0
59 def add_placeholder(self, index: int) -> str:
60 placeholder = make_placeholder(index)
61 self.known.add(index)
62 return placeholder
64 def remove_placeholders(self, text: str) -> TemplateRef:
65 """
66 Find all known placeholders in the text and return their indices.
68 If unknown placeholders are found, raises ValueError.
70 If no placeholders are found, returns a static PlaceholderRef.
71 """
72 pt = find_placeholders(text)
73 for index in pt.i_indexes:
74 if index not in self.known:
75 raise ValueError(f"Unknown placeholder index {index} found in text.")
76 self.known.remove(index)
77 return pt