Coverage for src\baobab_web_api_caller\core\json_response_decoder.py: 79%
33 statements
« prev ^ index » next coverage.py v7.10.3, created at 2026-03-21 12:10 +0100
« prev ^ index » next coverage.py v7.10.3, created at 2026-03-21 12:10 +0100
1"""Décodage JSON des réponses."""
3from __future__ import annotations
5import json
6from dataclasses import dataclass
8from baobab_web_api_caller.core.baobab_response import BaobabResponse
9from baobab_web_api_caller.core.response_decoder import ResponseDecoder
10from baobab_web_api_caller.exceptions.response_decoding_exception import ResponseDecodingException
13@dataclass(frozen=True, slots=True)
14class JsonResponseDecoder(ResponseDecoder):
15 """Décode le JSON à partir du corps texte/binaire.
17 Le décodage est tenté uniquement si l'en-tête ``Content-Type`` indique un JSON
18 (``application/json`` ou un type ``application/*+json``).
19 """
21 def decode(self, response: BaobabResponse) -> BaobabResponse:
22 content_type = response.headers.get("Content-Type", "")
23 if not self._is_json_content_type(content_type):
24 return response
26 if response.text is not None: 26 ↛ 28line 26 didn't jump to line 28 because the condition on line 26 was always true
27 raw_text = response.text
28 elif response.content is not None:
29 try:
30 raw_text = response.content.decode("utf-8")
31 except UnicodeDecodeError as exc:
32 raise ResponseDecodingException("Unable to decode JSON body as UTF-8") from exc
33 else:
34 raise ResponseDecodingException("Missing response body for JSON decoding")
35 if raw_text.strip() == "":
36 raise ResponseDecodingException("Missing response body for JSON decoding")
38 try:
39 json_data: object = json.loads(raw_text)
40 except json.JSONDecodeError as exc:
41 raise ResponseDecodingException("Invalid JSON response body") from exc
43 return BaobabResponse(
44 status_code=response.status_code,
45 headers=response.headers,
46 text=response.text,
47 content=response.content,
48 json_data=json_data,
49 )
51 @staticmethod
52 def _is_json_content_type(content_type: str) -> bool:
53 media_type = content_type.split(";", 1)[0].strip().lower()
54 if media_type == "application/json":
55 return True
56 return media_type.startswith("application/") and media_type.endswith("+json")