Coverage for src/henrri_connect/utils.py: 97%
38 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-09 19:37 +0200
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-09 19:37 +0200
1"""
2Module utilitaire pour les clients Henrri Connect.
4Fournit l'ensemble des fonctions utilitaires nécessaires au package ``henrri_connect``.
6Functions:
7----------
8- raise_for_status: Levé une exception appropriée selon le code HTTP de la réponse.
9- clean: Nettoie un dictionnaire en supprimant les clés dont la valeur est ``None``.
10"""
11from __future__ import annotations
13import logging
14import json
15from typing import Any
16import httpx
17from .exc import (
18 HenrriAuthError,
19 HenrriForbiddenError,
20 HenrriHTTPError,
21 HenrriNotFoundError,
22 HenrriServerError,
23 HenrriValidationError,
24)
26logger = logging.getLogger(__name__)
28def raise_for_status(resp: httpx.Response) -> None:
29 """Lève une exception appropriée selon le code HTTP de la réponse.
31 Correspondance des codes HTTP :
33 - 400 : ``HenrriValidationError``
34 - 401 : ``HenrriAuthError``
35 - 403 : ``HenrriForbiddenError``
36 - 404 : ``HenrriNotFoundError``
37 - 5xx : ``HenrriServerError``
38 - Autres : ``HenrriHTTPError``
40 Tente d'extraire un message d'erreur détaillé depuis la réponse JSON,
41 ou utilise le texte brut de la réponse si le JSON est invalide.
43 Args:
44 resp: La réponse HTTP httpx à analyser.
46 Raises:
47 HenrriValidationError: Si le code HTTP est 400.
48 HenrriAuthError: Si le code HTTP est 401.
49 HenrriForbiddenError: Si le code HTTP est 403.
50 HenrriNotFoundError: Si le code HTTP est 404.
51 HenrriServerError: Si le code HTTP est >= 500.
52 HenrriHTTPError: Pour tout autre code d'erreur.
53 """
54 if resp.is_success:
55 return
56 body = None
57 try:
58 body = resp.json()
59 if isinstance(body, dict):
60 msg: str = (
61 body.get("detail")
62 or body.get("title")
63 or body.get("message")
64 or resp.text
65 )
66 else:
67 msg = resp.text or str(body) or f"Erreur HTTP {resp.status_code}"
68 except json.JSONDecodeError:
69 msg = resp.text or f"Erreur HTTP {resp.status_code}"
71 sc = resp.status_code
72 if sc == 400:
73 logger.error("Validation error: %s", msg)
74 raise HenrriValidationError(sc, str(msg), body)
75 if sc == 401:
76 logger.error("Authentication error: %s", msg)
77 raise HenrriAuthError(sc, str(msg), body)
78 if sc == 403:
79 logger.error("Forbidden error: %s", msg)
80 raise HenrriForbiddenError(sc, str(msg), body)
81 if sc == 404:
82 logger.error("Not found error: %s", msg)
83 raise HenrriNotFoundError(sc, str(msg), body)
84 if sc >= 500:
85 logger.error("Server error: %s", msg)
86 raise HenrriServerError(sc, str(msg), body)
87 logger.error("HTTP error: %s", msg)
88 raise HenrriHTTPError(sc, str(msg), body)
90def clean(params: dict[str, Any]) -> dict[str, Any]:
91 """
92 Supprime les valeurs None d'un dictionnaire
94 Args:
95 params (dict[str, Any]) : Dictionnaire contenant des valeurs None
97 Returns:
98 dict[str, Any]: Dictionnaire sans valeurs None
99 """
100 return {k: v for k, v in params.items() if v is not None}