File: base.py

package info (click to toggle)
aptly-api-client 0.2.4-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 208 kB
  • sloc: python: 1,493; makefile: 3
file content (133 lines) | stat: -rw-r--r-- 5,324 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from typing import IO, TextIO, BinaryIO, Sequence, Dict, Tuple, Optional, Union, List, Any, MutableMapping, Iterable, \
    Mapping
from urllib.parse import urljoin

import requests
from requests.auth import AuthBase

_filetype = Optional[
    Union[
        Dict[
            str, Union[
                Union[TextIO, BinaryIO, str, bytes],
                Tuple[Optional[str], Union[TextIO, BinaryIO, str, bytes]],
                Tuple[Optional[str], Union[TextIO, BinaryIO, str, bytes], str],
                Tuple[Optional[str], Union[TextIO, BinaryIO, str, bytes], str, Dict[str, str]]
            ]
        ],
        Sequence[
            Tuple[
                str, Union[
                    Union[TextIO, BinaryIO, str, bytes],
                    Tuple[Optional[str], Union[TextIO, BinaryIO, str, bytes]],
                    Tuple[Optional[str], Union[TextIO, BinaryIO, str, bytes], str],
                    Tuple[Optional[str], Union[TextIO, BinaryIO, str, bytes], str, Dict[str, str]]
                ]
            ]
        ],
    ]
]

_datatype = Optional[
    Union[
        Iterable[bytes],
        str,
        bytes,
        Union[TextIO, BinaryIO],
        List[Tuple[Any, Any]],
        Tuple[Tuple[Any, Any], ...],
        Mapping[Any, Any]
    ]
]


class AptlyAPIException(Exception):
    def __init__(self, *args: Any, status_code: int = 0) -> None:
        super().__init__(*args)
        self.status_code = status_code


class BaseAPIClient:
    def __init__(self, base_url: str, ssl_verify: Union[str, bool, None] = None,
                 ssl_cert: Optional[Tuple[str, str]] = None, http_auth: Optional[AuthBase] = None,
                 timeout: int = 60) -> None:
        self.base_url = base_url
        self.ssl_verify = ssl_verify
        self.ssl_cert = ssl_cert
        self.http_auth = http_auth
        self.exc_class = AptlyAPIException
        self.timeout = timeout

    def _error_from_response(self, resp: requests.Response) -> str:
        if resp.status_code == 200:
            return "no error (status 200)"

        try:
            rcnt = resp.json()
        except ValueError:
            return "%s %s %s" % (resp.status_code, resp.reason, resp.text,)

        if isinstance(rcnt, dict):
            content = rcnt
        else:
            content = rcnt[0]

        ret = "%s - %s -" % (resp.status_code, resp.reason)
        if "error" in content:
            ret = "%s %s" % (ret, content["error"],)
        if "meta" in content:
            ret = "%s (%s)" % (ret, content["meta"],)
        return ret

    def _make_url(self, path: str) -> str:
        return urljoin(self.base_url, path)

    def do_get(self, urlpath: str, params: Optional[Dict[str, str]] = None) -> requests.Response:
        resp = requests.get(self._make_url(urlpath), params=params, verify=self.ssl_verify,
                            cert=self.ssl_cert, auth=self.http_auth, timeout=self.timeout)

        if resp.status_code < 200 or resp.status_code >= 300:
            raise AptlyAPIException(self._error_from_response(resp), status_code=resp.status_code)

        return resp

    def do_post(self, urlpath: str, data: Union[bytes, MutableMapping[str, str], IO[Any], None] = None,
                params: Optional[Dict[str, str]] = None,
                files: _filetype = None,
                json: Optional[MutableMapping[Any, Any]] = None) -> requests.Response:
        resp = requests.post(self._make_url(urlpath), data=data, params=params, files=files, json=json,
                             verify=self.ssl_verify, cert=self.ssl_cert, auth=self.http_auth,
                             timeout=self.timeout)

        if resp.status_code < 200 or resp.status_code >= 300:
            raise AptlyAPIException(self._error_from_response(resp), status_code=resp.status_code)

        return resp

    def do_put(self, urlpath: str, data: Union[bytes, MutableMapping[str, str], IO[Any]] = None,
               files: _filetype = None,
               json: Optional[MutableMapping[Any, Any]] = None) -> requests.Response:
        resp = requests.put(self._make_url(urlpath), data=data, files=files, json=json,
                            verify=self.ssl_verify, cert=self.ssl_cert, auth=self.http_auth,
                            timeout=self.timeout)

        if resp.status_code < 200 or resp.status_code >= 300:
            raise AptlyAPIException(self._error_from_response(resp), status_code=resp.status_code)

        return resp

    def do_delete(self, urlpath: str, params: Optional[Dict[str, str]] = None,
                  data: _datatype = None,
                  json: Union[List[Dict[str, Any]], Dict[str, Any], None] = None) -> requests.Response:
        resp = requests.delete(self._make_url(urlpath), params=params, data=data, json=json,
                               verify=self.ssl_verify, cert=self.ssl_cert, auth=self.http_auth,
                               timeout=self.timeout)

        if resp.status_code < 200 or resp.status_code >= 300:
            raise AptlyAPIException(self._error_from_response(resp), status_code=resp.status_code)

        return resp