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

1import re 

2from collections.abc import Callable 

3from re import Pattern 

4from typing import Any 

5 

6from faststream.exceptions import SetupError 

7 

8PARAM_REGEX = re.compile(r"{([a-zA-Z0-9_]+)}") 

9 

10 

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 = "" 

18 

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] 

24 

25 path_regex += re.escape(path[idx : match.start()]) 

26 path_regex += f"(?P<{param_name.replace('+', '')}>[^.]+)" 

27 

28 original_path += path[idx : match.start()] 

29 original_path += replace_symbol 

30 

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) 

35 

36 idx = match.end() 

37 

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) 

43 

44 if idx == 0: 

45 regex = None 

46 else: 

47 path_regex += re.escape(path[idx:]) + "$" 

48 regex = re.compile(patch_regex(path_regex)) 

49 

50 original_path += path[idx:] 

51 return regex, original_path 

52 

53 

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 {}