ims_envista.commons._get_headers()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
"""IMS Envista Commons."""
2
3
import asyncio
4
import http
5
import logging
6
import socket
7
from json import JSONDecodeError
8
from typing import Any
9
from uuid import UUID
10
11
import async_timeout
12
from aiohttp import ClientError, ClientResponse, ClientSession
13
14
_LOGGER = logging.getLogger(__name__)
15
16
17
class ImsEnvistaApiClientError(Exception):
18
    """Exception to indicate a general API error."""
19
20
21
class ImsEnvistaApiClientCommunicationError(
22
    ImsEnvistaApiClientError,
23
):
24
    """Exception to indicate a communication error."""
25
26
27
class ImsEnvistaApiClientAuthenticationError(
28
    ImsEnvistaApiClientError,
29
):
30
    """Exception to indicate an authentication error."""
31
32
def _get_headers(token: UUID | str) -> dict[str, str]:
33
    return {
34
        "Accept": "application/vnd.github.v3.text-match+json",
35
        "Authorization": f"ApiToken {token!s}"
36
    }
37
38
def _verify_response_or_raise(response: ClientResponse) -> None:
39
    """Verify that the response is valid."""
40
    if response.status in (401, 403):
41
        _LOGGER.debug("Bad Response: %s", response.text())
42
        msg = "Invalid credentials"
43
        raise ImsEnvistaApiClientAuthenticationError(
44
            msg,
45
        )
46
    content_type = response.headers.get("Content-Type")
47
    if content_type and "application/json" not in content_type:
48
        _LOGGER.debug("Bad Response: %s", response.text())
49
        msg = f"Invalid response from IMS - bad Content-Type: {content_type}"
50
        raise ImsEnvistaApiClientError(
51
            msg,
52
        )
53
    response.raise_for_status()
54
55
56
async def get(
57
    session: ClientSession, url: str, token: UUID | str, headers: dict | None = None
58
) -> dict[str, Any]:
59
    if not headers:
60
        headers = _get_headers(token)
61
62
    try:
63
        async with async_timeout.timeout(180):
64
            _LOGGER.debug("Sending GET from %s", url)
65
            response = await session.get(
66
                url=url,
67
                headers=headers
68
            )
69
            _verify_response_or_raise(response)
70
            json_resp = await response.json()
71
72
    except (TimeoutError, asyncio.exceptions.TimeoutError) as exception:
73
        msg = f"Timeout error fetching information from {url} - {exception}"
74
        raise ImsEnvistaApiClientCommunicationError(
75
            msg,
76
        ) from exception
77
    except (ClientError, socket.gaierror) as exception:
78
        msg = f"Error fetching information from {url} - {exception}"
79
        raise ImsEnvistaApiClientCommunicationError(
80
            msg,
81
        ) from exception
82
    except JSONDecodeError as exception:
83
        msg = f"Failed Parsing Response JSON from {url} - {exception!s}"
84
        raise ImsEnvistaApiClientError(msg) from exception
85
    except Exception as exception:  # pylint: disable=broad-except
86
        msg = f"Something really wrong happened! {url} {exception}"
87
        raise ImsEnvistaApiClientError(
88
            msg,
89
        ) from exception
90
91
    _LOGGER.debug("Response from %s: %s", url, json_resp)
92
    if response.status != http.HTTPStatus.OK:
93
        msg = f"Received Error from IMS Envista API from {url}: {response.status, response.reason}"
94
        raise ImsEnvistaApiClientError(msg)
95
96
    return json_resp
97