apytizer 0.0.1a0__py3-none-any.whl → 0.0.1b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. apytizer/__init__.py +2 -12
  2. apytizer/adapters/__init__.py +2 -3
  3. apytizer/adapters/transport_adapter.py +91 -0
  4. apytizer/apis/__init__.py +6 -0
  5. apytizer/apis/abstract_api.py +36 -0
  6. apytizer/apis/web_api.py +461 -0
  7. apytizer/connections/__init__.py +6 -0
  8. apytizer/connections/abstract_connection.py +28 -0
  9. apytizer/connections/http_connection.py +431 -0
  10. apytizer/decorators/__init__.py +5 -5
  11. apytizer/decorators/caching.py +60 -9
  12. apytizer/decorators/chunking.py +105 -0
  13. apytizer/decorators/connection.py +55 -20
  14. apytizer/decorators/json_response.py +93 -0
  15. apytizer/decorators/pagination.py +50 -32
  16. apytizer/endpoints/__init__.py +6 -0
  17. apytizer/endpoints/abstract_endpoint.py +38 -0
  18. apytizer/endpoints/web_endpoint.py +519 -0
  19. apytizer/engines/__init__.py +6 -0
  20. apytizer/engines/abstract_engine.py +45 -0
  21. apytizer/engines/http_engine.py +129 -0
  22. apytizer/errors.py +34 -0
  23. apytizer/factories/__init__.py +5 -0
  24. apytizer/factories/abstract_factory.py +17 -0
  25. apytizer/http_methods.py +34 -0
  26. apytizer/managers/__init__.py +12 -0
  27. apytizer/managers/abstract_manager.py +80 -0
  28. apytizer/managers/base_manager.py +116 -0
  29. apytizer/mappers/__init__.py +6 -0
  30. apytizer/mappers/abstract_mapper.py +48 -0
  31. apytizer/mappers/base_mapper.py +78 -0
  32. apytizer/media_types.py +118 -0
  33. apytizer/models/__init__.py +6 -0
  34. apytizer/models/abstract_model.py +119 -0
  35. apytizer/models/base_model.py +85 -0
  36. apytizer/protocols.py +38 -0
  37. apytizer/repositories/__init__.py +6 -0
  38. apytizer/repositories/abstract_repository.py +81 -0
  39. apytizer/repositories/managed_repository.py +92 -0
  40. apytizer/routes/__init__.py +6 -0
  41. apytizer/routes/abstract_route.py +32 -0
  42. apytizer/routes/base_route.py +138 -0
  43. apytizer/sessions/__init__.py +33 -0
  44. apytizer/sessions/abstract_session.py +63 -0
  45. apytizer/sessions/requests_session.py +125 -0
  46. apytizer/states/__init__.py +6 -0
  47. apytizer/states/abstract_state.py +71 -0
  48. apytizer/states/local_state.py +99 -0
  49. apytizer/utils/__init__.py +9 -4
  50. apytizer/utils/caching.py +39 -0
  51. apytizer/utils/dictionaries.py +375 -0
  52. apytizer/utils/errors.py +104 -0
  53. apytizer/utils/iterables.py +91 -0
  54. apytizer/utils/objects.py +145 -0
  55. apytizer/utils/strings.py +69 -0
  56. apytizer/utils/typing.py +29 -0
  57. apytizer-0.0.1b1.dist-info/METADATA +41 -0
  58. apytizer-0.0.1b1.dist-info/RECORD +60 -0
  59. {apytizer-0.0.1a0.dist-info → apytizer-0.0.1b1.dist-info}/WHEEL +1 -2
  60. apytizer/abstracts/__init__.py +0 -8
  61. apytizer/abstracts/api.py +0 -147
  62. apytizer/abstracts/endpoint.py +0 -177
  63. apytizer/abstracts/model.py +0 -50
  64. apytizer/abstracts/session.py +0 -39
  65. apytizer/adapters/transport.py +0 -40
  66. apytizer/base/__init__.py +0 -8
  67. apytizer/base/api.py +0 -510
  68. apytizer/base/endpoint.py +0 -443
  69. apytizer/base/model.py +0 -119
  70. apytizer/decorators/json.py +0 -35
  71. apytizer/utils/generate_key.py +0 -18
  72. apytizer/utils/merge.py +0 -19
  73. apytizer-0.0.1a0.dist-info/METADATA +0 -27
  74. apytizer-0.0.1a0.dist-info/RECORD +0 -25
  75. apytizer-0.0.1a0.dist-info/top_level.txt +0 -1
  76. {apytizer-0.0.1a0.dist-info → apytizer-0.0.1b1.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,519 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/endpoints/base_endpoint.py
3
+ """WEb Endpoint Class.
4
+
5
+ This module defines the web endpoint class implementation.
6
+
7
+ """
8
+
9
+ # Standard Library Imports
10
+ from __future__ import annotations
11
+ import logging
12
+ from typing import Any
13
+ from typing import Collection
14
+ from typing import Dict
15
+ from typing import MutableMapping
16
+ from typing import Optional
17
+ from typing import Set
18
+ from typing import Union
19
+ from typing import TYPE_CHECKING
20
+ from urllib.parse import urljoin
21
+
22
+ # Third-Party Imports
23
+ from requests import Response
24
+
25
+ # Local Imports
26
+ from .abstract_endpoint import AbstractEndpoint
27
+ from ..connections import HttpConnection
28
+ from ..decorators import cache_response
29
+ from ..http_methods import HTTPMethod
30
+ from ..routes import Route
31
+ from .. import errors
32
+ from .. import utils
33
+
34
+ if TYPE_CHECKING:
35
+ from ..apis import WebAPI
36
+
37
+ __all__ = ["WebEndpoint"]
38
+
39
+
40
+ log = logging.getLogger("apytizer")
41
+
42
+ # Define constants.
43
+ DEFAULT_METHODS = (
44
+ HTTPMethod.HEAD,
45
+ HTTPMethod.GET,
46
+ HTTPMethod.POST,
47
+ HTTPMethod.PUT,
48
+ HTTPMethod.PATCH,
49
+ HTTPMethod.DELETE,
50
+ HTTPMethod.OPTIONS,
51
+ HTTPMethod.TRACE,
52
+ )
53
+
54
+
55
+ class WebEndpoint(AbstractEndpoint):
56
+ """Implements an endpoint for web APIs.
57
+
58
+ Args:
59
+ __api: API instance.
60
+ path: Relative path to endpoint.
61
+ methods (optional): List of HTTP methods accepted by endpoint.
62
+ headers (optional): Headers to set globally for endpoint.
63
+ params (optional): Parameters to set globally for endpoint.
64
+ cache (optional): Mutable mapping for caching responses.
65
+
66
+ Attributes:
67
+ connection: Connection with which to make requests.
68
+
69
+ """
70
+
71
+ __slots__ = (
72
+ "_api",
73
+ "_path",
74
+ "_methods",
75
+ "_headers",
76
+ "_params",
77
+ "_cache",
78
+ )
79
+
80
+ def __init__(
81
+ self,
82
+ __api: "WebAPI",
83
+ /,
84
+ path: Union[int, Route, str],
85
+ *,
86
+ methods: Collection[HTTPMethod] = DEFAULT_METHODS,
87
+ headers: Optional[Dict[str, str]] = None,
88
+ params: Optional[Dict[str, Any]] = None,
89
+ cache: Optional[MutableMapping[str, Any]] = None,
90
+ ) -> None:
91
+ self._api = __api
92
+ self._path = str(path).strip("/")
93
+ self._methods = set(methods)
94
+ self._headers = headers
95
+ self._params = params
96
+ self._cache = cache
97
+
98
+ @property
99
+ def api(self) -> "WebAPI":
100
+ """API."""
101
+ return self._api
102
+
103
+ @property
104
+ def connection(self) -> Optional[HttpConnection]:
105
+ """Connection with which to make requests."""
106
+ return self._api.connection
107
+
108
+ @property
109
+ def path(self) -> str:
110
+ """Endpoint path."""
111
+ return self._path
112
+
113
+ @property
114
+ def url(self) -> str:
115
+ """Endpoint URL."""
116
+ result = urljoin(self.api.url, self.path)
117
+ return result
118
+
119
+ @property
120
+ def methods(self) -> Set[HTTPMethod]:
121
+ """Endpoint methods."""
122
+ return self._methods
123
+
124
+ @property
125
+ def headers(self) -> Optional[Dict[str, str]]:
126
+ """Headers."""
127
+ return self._headers
128
+
129
+ @property
130
+ def params(self) -> Optional[Dict[str, Any]]:
131
+ """Parameters."""
132
+ return self._params
133
+
134
+ @property
135
+ def cache(self) -> Optional[MutableMapping[str, Any]]:
136
+ """Cache."""
137
+ return self._cache
138
+
139
+ def __eq__(self, other: object) -> bool:
140
+ result = (
141
+ other.path.lower() == self.path.lower()
142
+ if isinstance(other, WebEndpoint)
143
+ else False
144
+ )
145
+ return result
146
+
147
+ def __hash__(self) -> int:
148
+ return hash(self.path)
149
+
150
+ def __repr__(self) -> str:
151
+ result = f"<{self.__class__.__name__!s} (path={self.path!s})>"
152
+ return result
153
+
154
+ def __str__(self) -> str:
155
+ return self.path
156
+
157
+ def __getitem__(self, path: str) -> AbstractEndpoint:
158
+ """Get endpoint.
159
+
160
+ Args:
161
+ path: Relative path of endpoint.
162
+
163
+ Returns:
164
+ Endpoint.
165
+
166
+ """
167
+ route = "/".join([self._path, path])
168
+ result = self._api[route]
169
+ return result
170
+
171
+ def __truediv__(self, path: str) -> AbstractEndpoint:
172
+ """Get endpoint.
173
+
174
+ Args:
175
+ path: Relative path of endpoint.
176
+
177
+ Returns:
178
+ Endpoint.
179
+
180
+ """
181
+ route = "/".join([self._path, path])
182
+ result = self._api[route]
183
+ return result
184
+
185
+ @cache_response
186
+ def head(
187
+ self,
188
+ *,
189
+ headers: Optional[Dict[str, str]] = None,
190
+ params: Optional[Dict[str, Any]] = None,
191
+ **kwargs: Any,
192
+ ) -> Optional[Response]:
193
+ """Sends an HTTP HEAD request to the endpoint.
194
+
195
+ Args:
196
+ headers (optional): Request headers (overrides global headers).
197
+ params (optional): Request parameters (overrides global parameters).
198
+ **kwargs: Keyword arguments to include in request.
199
+
200
+ Returns:
201
+ Response object.
202
+
203
+ Raises:
204
+ ConnectionNotStarted: when connection not started.
205
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
206
+
207
+ .. _MDN Web Docs:
208
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD
209
+
210
+ """
211
+ if self.connection is None:
212
+ message = "connection not started before making HEAD request"
213
+ raise errors.ConnectionNotStarted(message)
214
+
215
+ if HTTPMethod.HEAD not in self.methods:
216
+ message = f"HEAD method not allowed at {self.path!s} endpoint"
217
+ raise errors.MethodNotAllowed(message)
218
+
219
+ response = self.connection.head(
220
+ self.path,
221
+ headers=utils.merge(self.headers, headers),
222
+ params=utils.merge(self.params, params),
223
+ **kwargs,
224
+ )
225
+ return response
226
+
227
+ @cache_response
228
+ def get(
229
+ self,
230
+ *,
231
+ headers: Optional[Dict[str, str]] = None,
232
+ params: Optional[Dict[str, Any]] = None,
233
+ **kwargs: Any,
234
+ ) -> Optional[Response]:
235
+ """Sends an HTTP GET request to the endpoint.
236
+
237
+ Args:
238
+ headers (optional): Request headers (overrides global headers).
239
+ params (optional): Request parameters (overrides global parameters).
240
+ **kwargs: Keyword arguments to include in request.
241
+
242
+ Returns:
243
+ Response object.
244
+
245
+ Raises:
246
+ ConnectionNotStarted: when connection not started.
247
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
248
+
249
+ .. _MDN Web Docs:
250
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET
251
+
252
+ """
253
+ if self.connection is None:
254
+ message = "connection not started before making GET request"
255
+ raise errors.ConnectionNotStarted(message)
256
+
257
+ if HTTPMethod.GET not in self.methods:
258
+ message = f"GET method not allowed at {self.path!s} endpoint"
259
+ raise errors.MethodNotAllowed(message)
260
+
261
+ response = self.connection.get(
262
+ self.path,
263
+ headers=utils.merge(self.headers, headers),
264
+ params=utils.merge(self.params, params),
265
+ **kwargs,
266
+ )
267
+ return response
268
+
269
+ @cache_response
270
+ def post(
271
+ self,
272
+ *,
273
+ headers: Optional[Dict[str, str]] = None,
274
+ params: Optional[Dict[str, Any]] = None,
275
+ **kwargs: Any,
276
+ ) -> Optional[Response]:
277
+ """Sends an HTTP POST request to the endpoint.
278
+
279
+ Args:
280
+ headers (optional): Request headers (overrides global headers).
281
+ params (optional): Request parameters (overrides global parameters).
282
+ **kwargs: Keyword arguments to include in request.
283
+
284
+ Returns:
285
+ Response object.
286
+
287
+ Raises:
288
+ ConnectionNotStarted: when connection not started.
289
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
290
+
291
+ .. _MDN Web Docs:
292
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
293
+
294
+ """
295
+ if self.connection is None:
296
+ message = "connection not started before making POST request"
297
+ raise errors.ConnectionNotStarted(message)
298
+
299
+ if HTTPMethod.POST not in self.methods:
300
+ message = f"POST method not allowed at {self.path!s} endpoint"
301
+ raise errors.MethodNotAllowed(message)
302
+
303
+ response = self.connection.post(
304
+ self.path,
305
+ headers=utils.merge(self.headers, headers),
306
+ params=utils.merge(self.params, params),
307
+ **kwargs,
308
+ )
309
+ return response
310
+
311
+ @cache_response
312
+ def put(
313
+ self,
314
+ *,
315
+ headers: Optional[Dict[str, str]] = None,
316
+ params: Optional[Dict[str, Any]] = None,
317
+ **kwargs: Any,
318
+ ) -> Optional[Response]:
319
+ """Sends an HTTP PUT request to the endpoint.
320
+
321
+ Args:
322
+ headers (optional): Request headers (overrides global headers).
323
+ params (optional): Request parameters (overrides global parameters).
324
+ **kwargs: Keyword arguments to include in request.
325
+
326
+ Returns:
327
+ Response object.
328
+
329
+ Raises:
330
+ ConnectionNotStarted: when connection not started.
331
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
332
+
333
+ .. _MDN Web Docs:
334
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT
335
+
336
+ """
337
+ if self.connection is None:
338
+ message = "connection not started before making PUT request"
339
+ raise errors.ConnectionNotStarted(message)
340
+
341
+ if HTTPMethod.PUT not in self.methods:
342
+ message = f"PUT method not allowed at {self.path!s} endpoint"
343
+ raise errors.MethodNotAllowed(message)
344
+
345
+ response = self.connection.put(
346
+ self.path,
347
+ headers=utils.merge(self.headers, headers),
348
+ params=utils.merge(self.params, params),
349
+ **kwargs,
350
+ )
351
+ return response
352
+
353
+ @cache_response
354
+ def patch(
355
+ self,
356
+ *,
357
+ headers: Optional[Dict[str, str]] = None,
358
+ params: Optional[Dict[str, Any]] = None,
359
+ **kwargs: Any,
360
+ ) -> Optional[Response]:
361
+ """Sends an HTTP PATCH request to the endpoint.
362
+
363
+ Args:
364
+ headers (optional): Request headers (overrides global headers).
365
+ params (optional): Request parameters (overrides global parameters).
366
+ **kwargs: Keyword arguments to include in request.
367
+
368
+ Returns:
369
+ Response object.
370
+
371
+ Raises:
372
+ ConnectionNotStarted: when connection not started.
373
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
374
+
375
+ .. _MDN Web Docs:
376
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH
377
+
378
+ """
379
+ if self.connection is None:
380
+ message = "connection not started before making PATCH request"
381
+ raise errors.ConnectionNotStarted(message)
382
+
383
+ if HTTPMethod.PATCH not in self.methods:
384
+ message = f"PATCH method not allowed at {self.path!s} endpoint"
385
+ raise errors.MethodNotAllowed(message)
386
+
387
+ response = self.connection.patch(
388
+ self.path,
389
+ headers=utils.merge(self.headers, headers),
390
+ params=utils.merge(self.params, params),
391
+ **kwargs,
392
+ )
393
+ return response
394
+
395
+ @cache_response
396
+ def delete(
397
+ self,
398
+ *,
399
+ headers: Optional[Dict[str, str]] = None,
400
+ params: Optional[Dict[str, Any]] = None,
401
+ **kwargs: Any,
402
+ ) -> Optional[Response]:
403
+ """Sends an HTTP DELETE request to the endpoint.
404
+
405
+ Args:
406
+ headers (optional): Request headers (overrides global headers).
407
+ params (optional): Request parameters (overrides global parameters).
408
+ **kwargs: Keyword arguments to include in request.
409
+
410
+ Returns:
411
+ Response object.
412
+
413
+ Raises:
414
+ ConnectionNotStarted: when connection not started.
415
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
416
+
417
+ .. _MDN Web Docs:
418
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE
419
+
420
+ """
421
+ if self.connection is None:
422
+ message = "connection not started before making DELETE request"
423
+ raise errors.ConnectionNotStarted(message)
424
+
425
+ if HTTPMethod.DELETE not in self.methods:
426
+ message = f"DELETE method not allowed at {self.path!s} endpoint"
427
+ raise errors.MethodNotAllowed(message)
428
+
429
+ response = self.connection.delete(
430
+ self.path,
431
+ headers=utils.merge(self.headers, headers),
432
+ params=utils.merge(self.params, params),
433
+ **kwargs,
434
+ )
435
+ return response
436
+
437
+ @cache_response
438
+ def options(
439
+ self,
440
+ *,
441
+ headers: Optional[Dict[str, str]] = None,
442
+ params: Optional[Dict[str, Any]] = None,
443
+ **kwargs: Any,
444
+ ) -> Optional[Response]:
445
+ """Sends an HTTP OPTIONS request to the endpoint.
446
+
447
+ Args:
448
+ headers (optional): Request headers (overrides global headers).
449
+ params (optional): Request parameters (overrides global parameters).
450
+ **kwargs: Keyword arguments to include in request.
451
+
452
+ Returns:
453
+ Response object.
454
+
455
+ Raises:
456
+ ConnectionNotStarted: when connection not started.
457
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
458
+
459
+ .. _MDN Web Docs:
460
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
461
+
462
+ """
463
+ if self.connection is None:
464
+ message = "connection not started before making OPTIONS request"
465
+ raise errors.ConnectionNotStarted(message)
466
+
467
+ if HTTPMethod.OPTIONS not in self.methods:
468
+ message = f"OPTIONS method not allowed at {self.path!s} endpoint"
469
+ raise errors.MethodNotAllowed(message)
470
+
471
+ response = self.connection.options(
472
+ self.path,
473
+ headers=utils.merge(self.headers, headers),
474
+ params=utils.merge(self.params, params),
475
+ **kwargs,
476
+ )
477
+ return response
478
+
479
+ @cache_response
480
+ def trace(
481
+ self,
482
+ *,
483
+ headers: Optional[Dict[str, str]] = None,
484
+ params: Optional[Dict[str, Any]] = None,
485
+ **kwargs: Any,
486
+ ) -> Optional[Response]:
487
+ """Sends an HTTP TRACE request to the endpoint.
488
+
489
+ Args:
490
+ headers (optional): Request headers (overrides global headers).
491
+ params (optional): Request parameters (overrides global parameters).
492
+ **kwargs: Keyword arguments to include in request.
493
+
494
+ Returns:
495
+ Response object.
496
+
497
+ Raises:
498
+ ConnectionNotStarted: when connection not started.
499
+ MethodNotAllowed: when HTTP method not allowed on endpoint.
500
+
501
+ .. _MDN Web Docs:
502
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/TRACE
503
+
504
+ """
505
+ if self.connection is None:
506
+ message = "connection not started before making TRACE request"
507
+ raise errors.ConnectionNotStarted(message)
508
+
509
+ if HTTPMethod.TRACE not in self.methods:
510
+ message = f"TRACE method not allowed at {self.path!s} endpoint"
511
+ raise errors.MethodNotAllowed(message)
512
+
513
+ response = self.connection.trace(
514
+ self.path,
515
+ headers=utils.merge(self.headers, headers),
516
+ params=utils.merge(self.params, params),
517
+ **kwargs,
518
+ )
519
+ return response
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/engines/__init__.py
3
+
4
+ # Local Imports
5
+ from .abstract_engine import *
6
+ from .http_engine import *
@@ -0,0 +1,45 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/engines/abstract_engine.py
3
+ """Abstract Engine Class.
4
+
5
+ This module defines an abstract engine class which provides an interface
6
+ for subclasses to implement.
7
+
8
+ """
9
+
10
+ # Standard Library Imports
11
+ from __future__ import annotations
12
+ import abc
13
+ from typing import Optional
14
+
15
+ # Local Imports
16
+ from ..connections import AbstractConnection
17
+ from ..protocols import Protocol
18
+
19
+ __all__ = ["AbstractEngine"]
20
+
21
+
22
+ class AbstractEngine(abc.ABC):
23
+ """Represents an abstract engine."""
24
+
25
+ @property
26
+ @abc.abstractmethod
27
+ def protocol(self) -> Optional[Protocol]:
28
+ """Protocol."""
29
+ raise NotImplementedError
30
+
31
+ @property
32
+ @abc.abstractmethod
33
+ def url(self) -> str:
34
+ """Base URL."""
35
+ raise NotImplementedError
36
+
37
+ @abc.abstractmethod
38
+ def connect(self) -> AbstractConnection:
39
+ """Establish connection.
40
+
41
+ Returns:
42
+ Connection.
43
+
44
+ """
45
+ raise NotImplementedError
@@ -0,0 +1,129 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/engines/http_engine.py
3
+ """HTTP Engine Class.
4
+
5
+ This module defines the HTTP engine class implementation.
6
+
7
+ """
8
+
9
+ # Standard Library Imports
10
+ from typing import Any
11
+ from typing import Dict
12
+ from typing import MutableMapping
13
+ from typing import Optional
14
+ from typing import Tuple
15
+ from typing import Type
16
+ from typing import TypeVar
17
+ from typing import Union
18
+
19
+ # Third-Party Imports
20
+ from requests.auth import AuthBase
21
+ from requests.adapters import HTTPAdapter
22
+
23
+ # Local Imports
24
+ from .abstract_engine import AbstractEngine
25
+ from ..connections import HttpConnection
26
+ from ..protocols import Protocol
27
+ from ..protocols import get_protocol
28
+ from ..utils import errors
29
+
30
+ __all__ = ["HTTPEngine"]
31
+
32
+
33
+ # Custom types:
34
+ T = TypeVar("T")
35
+
36
+
37
+ class HTTPEngine(AbstractEngine):
38
+ """Implements an HTTP engine.
39
+
40
+ Args:
41
+ url: Base URL.
42
+ adapters (optional): Connection adapters. Default ``None``.
43
+ uth (optional): Authentication header. default ``None``.
44
+ cert (optional): Client certificate. Default ``None``.
45
+ headers (optional): Headers to set globally. Default ``None``.
46
+ params (optional): Parameters to set globally. Default ``None``.
47
+ proxies (optional): Protocols mapped to proxy URLs. Default ``None``.
48
+ stream (optional): Whether to stream response content. Default ``False``.
49
+ timeout (optional): How long to wait before timing out. Default ``None``.
50
+ verify (optional): Whether to verify certificate. Default ``True``.
51
+
52
+ Raises:
53
+ TypeError: when URL of type other than `str`.
54
+
55
+ """
56
+
57
+ _connection_cls: Type[HttpConnection] = HttpConnection
58
+
59
+ def __init__(
60
+ self,
61
+ url: str,
62
+ *,
63
+ adapters: Optional[Dict[Protocol, HTTPAdapter]] = None,
64
+ auth: Optional[Union[AuthBase, Tuple[str, str]]] = None,
65
+ cert: Optional[Union[str, Tuple[str, str]]] = None,
66
+ headers: Optional[Dict[str, str]] = None,
67
+ params: Optional[Dict[str, Any]] = None,
68
+ proxies: Optional[MutableMapping[str, str]] = None,
69
+ stream: Optional[bool] = False,
70
+ timeout: Optional[Union[float, Tuple[float, float]]] = None,
71
+ verify: Optional[bool] = True,
72
+ ) -> None:
73
+ self.url = url
74
+ self.adapters = adapters or {}
75
+ self.auth = auth
76
+ self.cert = cert
77
+ self.headers = headers
78
+ self.params = params
79
+ self.proxies = proxies
80
+ self.stream = stream
81
+ self.timeout = timeout
82
+ self.verify = verify
83
+
84
+ @property
85
+ def protocol(self) -> Optional[Protocol]:
86
+ """Protocol."""
87
+ result = get_protocol(self.url)
88
+ return result
89
+
90
+ @property
91
+ def url(self) -> str:
92
+ """Base URL."""
93
+ return self._url
94
+
95
+ @url.setter
96
+ def url(self, value: str) -> None:
97
+ errors.raise_for_instance(value, str)
98
+ self._url = standardize_url(value)
99
+
100
+ def __repr__(self) -> str:
101
+ return f"Engine({self.url!r})"
102
+
103
+ def connect(self) -> HttpConnection:
104
+ """Establish connection.
105
+
106
+ Returns:
107
+ Connection instance.
108
+
109
+ """
110
+ result = self._connection_cls(self)
111
+ return result
112
+
113
+
114
+ def standardize_url(__url: Any, /) -> str:
115
+ """Standardize URL.
116
+
117
+ Args:
118
+ __url: URL.
119
+
120
+ Returns:
121
+ URL.
122
+
123
+ """
124
+ if not isinstance(__url, str):
125
+ message = f"expected type 'str', got {type(__url)} instead"
126
+ raise TypeError(message)
127
+
128
+ result = __url if __url.endswith("/") else __url + "/"
129
+ return result