1"""Consistent error reporting and matching of xCal element content."""
2
3from __future__ import annotations
4
5import re
6from typing import TYPE_CHECKING
7
8from icalendar.error import XCalParsingError
9
10if TYPE_CHECKING:
11 from icalendar.parser.xcal.adapter import ElementAdapter
12
13
14class XCalRegexMatcher:
15 """Match a regex and provide consistent error messages.
16
17 Parameters:
18 regex: The regex to match.
19 expected_message: The start of the error message saying what is expected.
20 flags: The regex flags to use. Only used of regex is a string.
21 """
22
23 def __init__(self, regex: str | re.Pattern, expected_message: str, flags: int = 0):
24 self._regex = (
25 re.compile(f"^{regex}$", flags) if isinstance(regex, str) else regex
26 )
27 self._expected_message = expected_message
28
29 def match(self, element: ElementAdapter) -> re.Match:
30 """Return the match for the element's text.
31
32 Parameters:
33 element: The element to match the text from.
34
35 Returns:
36 The match if successful.
37
38 Raises:
39 ~icalendar.error.XCalParsingError: If the provided xCal is invalid.
40 """
41
42 match = self._regex.match(element.get_xsd_string())
43 if match is None:
44 raise XCalParsingError(
45 self._expected_message,
46 element.get_xsd_string(),
47 element,
48 )
49 return match
50
51 def groups(self, element: ElementAdapter) -> tuple[str, ...]:
52 """Return the match groups for the element's text.
53
54 Parameters:
55 element: The element to match the text from.
56
57 Returns:
58 The groups of the match if successful.
59
60 Raises:
61 ~icalendar.error.XCalParsingError: If the provided xCal is invalid.
62 """
63 return self.match(element).groups()
64
65
66__all__ = ["XCalRegexMatcher"]