Passed
Pull Request — main (#51)
by Guy
01:27
created

ims_envista.commons._get_headers()   A

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 http
4
import logging
5
import socket
6
from json import JSONDecodeError
7
from typing import Any
8
from uuid import UUID
9
10
import async_timeout
11
from aiohttp import (
12
    ClientError,
13
    ClientResponse,
14
    ClientSession,
15
    TraceRequestChunkSentParams,
16
    TraceRequestEndParams,
17
    TraceRequestStartParams,
18
)
19
20
logger = logging.getLogger(__name__)
21
22
23
class ImsEnvistaApiClientError(Exception):
24
    """Exception to indicate a general API error."""
25
26
27
class ImsEnvistaApiClientCommunicationError(
28
    ImsEnvistaApiClientError,
29
):
30
    """Exception to indicate a communication error."""
31
32
33
class ImsEnvistaApiClientAuthenticationError(
34
    ImsEnvistaApiClientError,
35
):
36
    """Exception to indicate an authentication error."""
37
38
39
async def on_request_start_debug(session: ClientSession, context,params: TraceRequestStartParams) -> None:  # noqa: ANN001, ARG001
40
    logger.debug("HTTP %s: %s", params.method, params.url)
41
42
43
async def on_request_chunk_sent_debug(
44
    session: ClientSession, context, params: TraceRequestChunkSentParams  # noqa: ANN001, ARG001
45
) -> None:
46
    if (params.method in ("POST", "PUT")) and params.chunk:
47
        logger.debug("HTTP Content %s: %s", params.method, params.chunk)
48
49
50
async def on_request_end_debug(session: ClientSession, context, params: TraceRequestEndParams) -> None:  # noqa: ANN001, ARG001
51
    response_text = await params.response.text()
52
    logger.debug("HTTP %s Response <%s>: %s", params.method, params.response.status, response_text)
53
54
55
def _get_headers(token: UUID | str) -> dict[str, str]:
56
    return {
57
        "Accept": "application/vnd.github.v3.text-match+json",
58
        "Authorization": f"ApiToken {token!s}"
59
    }
60
61
def _verify_response_or_raise(response: ClientResponse) -> None:
62
    """Verify that the response is valid."""
63
    if response.status in (401, 403):
64
        msg = "Invalid credentials"
65
        raise ImsEnvistaApiClientAuthenticationError(
66
            msg,
67
        )
68
    response.raise_for_status()
69
70
71
async def get(
72
    session: ClientSession, url: str, token: UUID | str, headers: dict | None = None
73
) -> dict[str, Any]:
74
    if not headers:
75
        headers = _get_headers(token)
76
77
    try:
78
        async with async_timeout.timeout(10):
79
            response = await session.get(
80
                url=url,
81
                headers=headers
82
            )
83
            _verify_response_or_raise(response)
84
            json_resp = await response.json()
85
86
    except TimeoutError as exception:
87
        msg = f"Timeout error fetching information - {exception}"
88
        raise ImsEnvistaApiClientCommunicationError(
89
            msg,
90
        ) from exception
91
    except (ClientError, socket.gaierror) as exception:
92
        msg = f"Error fetching information - {exception}"
93
        raise ImsEnvistaApiClientCommunicationError(
94
            msg,
95
        ) from exception
96
    except JSONDecodeError as exception:
97
        msg = f"Failed Parsing Response JSON: {exception!s}"
98
        raise ImsEnvistaApiClientError(msg) from exception
99
    except Exception as exception:  # pylint: disable=broad-except
100
        msg = f"Something really wrong happened! - {exception}"
101
        raise ImsEnvistaApiClientError(
102
            msg,
103
        ) from exception
104
105
    if response.status != http.HTTPStatus.OK:
106
        msg = f"Received Error from IMS Envista API: {response.status, response.reason}"
107
        raise ImsEnvistaApiClientError(msg)
108
109
    return json_resp
110