Coverage for faststream / _internal / utils / path.py: 83%
32 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-08 01:48 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-08 01:48 +0000
1import re
2from collections.abc import Callable
3from re import Pattern
4from typing import Any
6from faststream.exceptions import SetupError
8PARAM_REGEX = re.compile(r"{([a-zA-Z0-9_]+)}")
11def compile_path(
12 path: str,
13 replace_symbol: str,
14 patch_regex: Callable[[str], str] = lambda x: x,
15) -> tuple[Pattern[str] | None, str]:
16 path_regex = "^.*?"
17 original_path = ""
19 idx = 0
20 params = set()
21 duplicated_params = set()
22 for match in PARAM_REGEX.finditer(path):
23 param_name = match.groups("str")[0]
25 path_regex += re.escape(path[idx : match.start()])
26 path_regex += f"(?P<{param_name.replace('+', '')}>[^.]+)"
28 original_path += path[idx : match.start()]
29 original_path += replace_symbol
31 if param_name in params: 31 ↛ 32line 31 didn't jump to line 32 because the condition on line 31 was never true
32 duplicated_params.add(param_name)
33 else:
34 params.add(param_name)
36 idx = match.end()
38 if duplicated_params: 38 ↛ 39line 38 didn't jump to line 39 because the condition on line 38 was never true
39 names = ", ".join(sorted(duplicated_params))
40 ending = "s" if len(duplicated_params) > 1 else ""
41 msg = f"Duplicated param name{ending} {names} at path {path}"
42 raise SetupError(msg)
44 if idx == 0:
45 regex = None
46 else:
47 path_regex += re.escape(path[idx:]) + "$"
48 regex = re.compile(patch_regex(path_regex))
50 original_path += path[idx:]
51 return regex, original_path
54def match_path(pattern: Pattern[str] | None, subject: str) -> dict[str, Any]:
55 """Match subject against pattern and return named groups, or {} if no match."""
56 if pattern is not None and (match := pattern.match(subject)):
57 return match.groupdict()
58 return {}