Coverage for netbox_data_import/transform_regex.py: 100%
27 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-09 20:50 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-09 20:50 +0000
1# SPDX-License-Identifier: Apache-2.0
2# SPDX-FileCopyrightText: 2026 Marcin Zieba <marcinpsk@gmail.com>
3"""Compile transform patterns with the safe regular-expression engine."""
5from __future__ import annotations
7from dataclasses import dataclass
8from typing import Any, Self
10import re2 # type: ignore[import-untyped]
13class TransformPatternError(ValueError):
14 """A transform pattern uses invalid or unsupported syntax."""
17@dataclass(frozen=True)
18class TransformPattern:
19 """A compiled transform pattern with engine details kept private."""
21 _compiled: Any
23 @classmethod
24 def compile(cls, pattern: str) -> Self:
25 """Compile one pattern without writing parser errors to the server log."""
26 options = re2.Options()
27 options.log_errors = False
28 try:
29 return cls(re2.compile(pattern, options=options))
30 except re2.error as exc:
31 detail = exc.args[0]
32 if isinstance(detail, bytes):
33 detail = detail.decode(errors="replace")
34 raise TransformPatternError(str(detail)) from exc
36 @property
37 def group_count(self) -> int:
38 """Return the number of capturing groups in the pattern."""
39 return int(self._compiled.groups)
41 def capture_groups(self, text: str) -> tuple[str | None, ...] | None:
42 """Return captured values for a full match, or None when the text does not match."""
43 match = self._compiled.fullmatch(text)
44 if match is None:
45 return None
46 return tuple(match.groups())