Passed
Push — main ( 8ce80f...888872 )
by Guy
02:10
created

ims_envista.commons.on_request_chunk_sent_debug()   A

Complexity

Conditions 3

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nop 3
dl 0
loc 5
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
        msg = "Invalid credentials"
42
        raise ImsEnvistaApiClientAuthenticationError(
43
            msg,
44
        )
45
    content_type = response.headers.get("Content-Type")
46
    if content_type and "application/json" not in content_type:
47
        msg = f"Invalid response from IMS - bad Content-Type: {content_type}"
48
        raise ImsEnvistaApiClientError(
49
            msg,
50
        )
51
    response.raise_for_status()
52
53
54
async def get(
55
    session: ClientSession, url: str, token: UUID | str, headers: dict | None = None
56
) -> dict[str, Any]:
57
    if not headers:
58
        headers = _get_headers(token)
59
60
    try:
61
        async with async_timeout.timeout(180):
62
            _LOGGER.debug("Sending GET from %s", url)
63
            response = await session.get(
64
                url=url,
65
                headers=headers
66
            )
67
            _verify_response_or_raise(response)
68
            json_resp = await response.json()
69
70
    except (TimeoutError, asyncio.exceptions.TimeoutError) as exception:
71
        msg = f"Timeout error fetching information from {url} - {exception}"
72
        raise ImsEnvistaApiClientCommunicationError(
73
            msg,
74
        ) from exception
75
    except (ClientError, socket.gaierror) as exception:
76
        msg = f"Error fetching information from {url} - {exception}"
77
        raise ImsEnvistaApiClientCommunicationError(
78
            msg,
79
        ) from exception
80
    except JSONDecodeError as exception:
81
        msg = f"Failed Parsing Response JSON from {url} - {exception!s}"
82
        raise ImsEnvistaApiClientError(msg) from exception
83
    except Exception as exception:  # pylint: disable=broad-except
84
        msg = f"Something really wrong happened! {url} {exception}"
85
        raise ImsEnvistaApiClientError(
86
            msg,
87
        ) from exception
88
89
    if response.status != http.HTTPStatus.OK:
90
        msg = f"Received Error from IMS Envista API from {url}: {response.status, response.reason}"
91
        raise ImsEnvistaApiClientError(msg)
92
93
    return json_resp
94