|
1 | 1 | import time |
| 2 | +from typing import Optional, Union |
2 | 3 |
|
3 | 4 | import requests |
4 | 5 |
|
@@ -32,24 +33,19 @@ class Client: |
32 | 33 |
|
33 | 34 | def __init__( |
34 | 35 | self, |
35 | | - token, |
36 | | - api_endpoint="https://api.hetzner.cloud/v1", |
37 | | - application_name=None, |
38 | | - application_version=None, |
39 | | - poll_interval=1, |
| 36 | + token: str, |
| 37 | + api_endpoint: str = "https://api.hetzner.cloud/v1", |
| 38 | + application_name: Optional[str] = None, |
| 39 | + application_version: Optional[str] = None, |
| 40 | + poll_interval: int = 1, |
40 | 41 | ): |
41 | 42 | """Create an new Client instance |
42 | 43 |
|
43 | | - :param token: str |
44 | | - Hetzner Cloud API token |
45 | | - :param api_endpoint: str |
46 | | - Hetzner Cloud API endpoint (default is https://api.hetzner.cloud/v1) |
47 | | - :param application_name: str |
48 | | - Your application name (default is None) |
49 | | - :param application_version: str |
50 | | - Your application _version (default is None) |
51 | | - :param poll_interval: int |
52 | | - Interval for polling information from Hetzner Cloud API in seconds (default is 1) |
| 44 | + :param token: Hetzner Cloud API token |
| 45 | + :param api_endpoint: Hetzner Cloud API endpoint |
| 46 | + :param application_name: Your application name |
| 47 | + :param application_version: Your application _version |
| 48 | + :param poll_interval: Interval for polling information from Hetzner Cloud API in seconds |
53 | 49 | """ |
54 | 50 | self.token = token |
55 | 51 | self._api_endpoint = api_endpoint |
@@ -148,85 +144,79 @@ def __init__( |
148 | 144 | :type: :class:`PlacementGroupsClient <hcloud.placement_groups.client.PlacementGroupsClient>` |
149 | 145 | """ |
150 | 146 |
|
151 | | - def _get_user_agent(self): |
| 147 | + def _get_user_agent(self) -> str: |
152 | 148 | """Get the user agent of the hcloud-python instance with the user application name (if specified) |
153 | 149 |
|
154 | | - :return: str |
155 | | - The user agent of this hcloud-python instance |
156 | | - """ |
157 | | - if self._application_name is not None and self._application_version is None: |
158 | | - return "{application_name} {prefix}/{version}".format( |
159 | | - application_name=self._application_name, |
160 | | - prefix=self.__user_agent_prefix, |
161 | | - version=self._version, |
162 | | - ) |
163 | | - elif ( |
164 | | - self._application_name is not None and self._application_version is not None |
165 | | - ): |
166 | | - return "{application_name}/{application_version} {prefix}/{version}".format( |
167 | | - application_name=self._application_name, |
168 | | - application_version=self._application_version, |
169 | | - prefix=self.__user_agent_prefix, |
170 | | - version=self._version, |
171 | | - ) |
172 | | - else: |
173 | | - return "{prefix}/{version}".format( |
174 | | - prefix=self.__user_agent_prefix, version=self._version |
175 | | - ) |
176 | | - |
177 | | - def _get_headers(self): |
| 150 | + :return: The user agent of this hcloud-python instance |
| 151 | + """ |
| 152 | + user_agents = [] |
| 153 | + for name, version in [ |
| 154 | + (self._application_name, self._application_version), |
| 155 | + (self.__user_agent_prefix, self._version), |
| 156 | + ]: |
| 157 | + if name is not None: |
| 158 | + user_agents.append(name if version is None else f"{name}/{version}") |
| 159 | + |
| 160 | + return " ".join(user_agents) |
| 161 | + |
| 162 | + def _get_headers(self) -> dict: |
178 | 163 | headers = { |
179 | 164 | "User-Agent": self._get_user_agent(), |
180 | 165 | "Authorization": f"Bearer {self.token}", |
181 | 166 | } |
182 | 167 | return headers |
183 | 168 |
|
184 | | - def _raise_exception_from_response(self, response): |
| 169 | + def _raise_exception_from_response(self, response: requests.Response): |
185 | 170 | raise APIException( |
186 | 171 | code=response.status_code, |
187 | 172 | message=response.reason, |
188 | 173 | details={"content": response.content}, |
189 | 174 | ) |
190 | 175 |
|
191 | | - def _raise_exception_from_json_content(self, json_content): |
| 176 | + def _raise_exception_from_content(self, content: dict): |
192 | 177 | raise APIException( |
193 | | - code=json_content["error"]["code"], |
194 | | - message=json_content["error"]["message"], |
195 | | - details=json_content["error"]["details"], |
| 178 | + code=content["error"]["code"], |
| 179 | + message=content["error"]["message"], |
| 180 | + details=content["error"]["details"], |
196 | 181 | ) |
197 | 182 |
|
198 | | - def request(self, method, url, tries=1, **kwargs): |
| 183 | + def request( |
| 184 | + self, |
| 185 | + method: str, |
| 186 | + url: str, |
| 187 | + tries: int = 1, |
| 188 | + **kwargs, |
| 189 | + ) -> Union[bytes, dict]: |
199 | 190 | """Perform a request to the Hetzner Cloud API, wrapper around requests.request |
200 | 191 |
|
201 | | - :param method: str |
202 | | - HTTP Method to perform the Request |
203 | | - :param url: str |
204 | | - URL of the Endpoint |
205 | | - :param tries: int |
206 | | - Tries of the request (used internally, should not be set by the user) |
| 192 | + :param method: HTTP Method to perform the Request |
| 193 | + :param url: URL of the Endpoint |
| 194 | + :param tries: Tries of the request (used internally, should not be set by the user) |
207 | 195 | :return: Response |
208 | | - :rtype: requests.Response |
209 | 196 | """ |
210 | 197 | response = self._requests_session.request( |
211 | | - method, self._api_endpoint + url, headers=self._get_headers(), **kwargs |
| 198 | + method=method, |
| 199 | + url=self._api_endpoint + url, |
| 200 | + headers=self._get_headers(), |
| 201 | + **kwargs, |
212 | 202 | ) |
213 | 203 |
|
214 | | - json_content = response.content |
| 204 | + content = response.content |
215 | 205 | try: |
216 | | - if len(json_content) > 0: |
217 | | - json_content = response.json() |
| 206 | + if len(content) > 0: |
| 207 | + content = response.json() |
218 | 208 | except (TypeError, ValueError): |
219 | 209 | self._raise_exception_from_response(response) |
220 | 210 |
|
221 | 211 | if not response.ok: |
222 | | - if json_content: |
223 | | - if json_content["error"]["code"] == "rate_limit_exceeded" and tries < 5: |
| 212 | + if content: |
| 213 | + if content["error"]["code"] == "rate_limit_exceeded" and tries < 5: |
224 | 214 | time.sleep(tries * self._retry_wait_time) |
225 | 215 | tries = tries + 1 |
226 | 216 | return self.request(method, url, tries, **kwargs) |
227 | 217 | else: |
228 | | - self._raise_exception_from_json_content(json_content) |
| 218 | + self._raise_exception_from_content(content) |
229 | 219 | else: |
230 | 220 | self._raise_exception_from_response(response) |
231 | 221 |
|
232 | | - return json_content |
| 222 | + return content |
0 commit comments