Coverage for src\baobab_web_api_caller\core\request_url_builder.py: 90%

27 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2026-03-21 12:10 +0100

1"""Construction d'URL de requête.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass 

6from urllib.parse import urlencode 

7 

8from baobab_web_api_caller.core.baobab_request import BaobabRequest 

9from baobab_web_api_caller.exceptions.configuration_exception import ConfigurationException 

10 

11 

12@dataclass(frozen=True, slots=True) 

13class RequestUrlBuilder: 

14 """Construit l'URL finale à partir d'une base URL et d'une requête. 

15 

16 :param base_url: Base URL normalisée (sans ``/`` final). 

17 :type base_url: str 

18 :raises ConfigurationException: Si la base URL est invalide. 

19 """ 

20 

21 base_url: str 

22 

23 def __post_init__(self) -> None: 

24 if not isinstance(self.base_url, str) or self.base_url.strip() == "": 24 ↛ 25line 24 didn't jump to line 25 because the condition on line 24 was never true

25 raise ConfigurationException("base_url must be a non-empty string") 

26 if self.base_url.endswith("/"): 

27 raise ConfigurationException("base_url must not end with '/'") 

28 

29 def build(self, request: BaobabRequest) -> str: 

30 """Construit l'URL à appeler. 

31 

32 :param request: Requête. 

33 :type request: BaobabRequest 

34 :return: URL finale. 

35 :rtype: str 

36 """ 

37 

38 if not request.path.startswith("/"): 38 ↛ 39line 38 didn't jump to line 39 because the condition on line 38 was never true

39 raise ConfigurationException("request.path must start with '/'") 

40 

41 url = f"{self.base_url}{request.path}" 

42 if request.query_params: 

43 items: list[tuple[str, str]] = [] 

44 for key, value in request.query_params.items(): 

45 if isinstance(value, str): 

46 items.append((key, value)) 

47 else: 

48 for v in value: 

49 items.append((key, v)) 

50 query = urlencode(items, doseq=True, safe=":/") 

51 return f"{url}?{query}" 

52 return url