apytizer 0.0.1a0__py3-none-any.whl → 0.0.1b2__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 (75) 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 +460 -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.py +70 -12
  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 +171 -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 +376 -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.1b2.dist-info/METADATA +41 -0
  58. apytizer-0.0.1b2.dist-info/RECORD +60 -0
  59. {apytizer-0.0.1a0.dist-info → apytizer-0.0.1b2.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/utils/generate_key.py +0 -18
  71. apytizer/utils/merge.py +0 -19
  72. apytizer-0.0.1a0.dist-info/METADATA +0 -27
  73. apytizer-0.0.1a0.dist-info/RECORD +0 -25
  74. apytizer-0.0.1a0.dist-info/top_level.txt +0 -1
  75. {apytizer-0.0.1a0.dist-info → apytizer-0.0.1b2.dist-info/licenses}/LICENSE +0 -0
apytizer/__init__.py CHANGED
@@ -1,14 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
+ # src/apytizer/__init__.py
2
3
 
3
- from .adapters import TransportAdapter
4
- from .base import BasicAPI as API
5
- from .base import SessionAPI as Session
6
- from .base import BasicEndpoint as Endpoint
7
- from .base import BasicModel as Model
8
-
9
-
10
- VERSION = (0, 0, 1, 'alpha', 0)
11
-
12
- __version__ = '.'.join(str(v) for v in VERSION[:2])
13
-
14
- __release__ = '.'.join(str(v) for v in VERSION)
4
+ __version__ = "0.0.1"
@@ -1,5 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- # pylint: skip-file
4
-
5
- from .transport import TransportAdapter
3
+ # Local Imports
4
+ from .transport_adapter import *
@@ -0,0 +1,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/adapters/transport_adapter.py
3
+ """Transport Adapter.
4
+
5
+ This module defines a transport adapter class: an implementation of an
6
+ HTTPAdapter which handles exponential backoff for retrying requests and
7
+ provides default values for rate limiting and timeout.
8
+
9
+ """
10
+
11
+ # Standard Library Imports
12
+ from http import HTTPStatus
13
+ from typing import Any
14
+ from urllib3.util import Retry
15
+
16
+ # Third-Party Imports
17
+ from requests import PreparedRequest
18
+ from requests import Response
19
+ from requests.adapters import HTTPAdapter
20
+
21
+ # Local Import
22
+ from ..http_methods import HTTPMethod
23
+
24
+ __all__ = ["TransportAdapter"]
25
+
26
+
27
+ # Constants
28
+ DEFAULT_RATE_LIMIT = 1
29
+ DEFAULT_TIMEOUT = 5
30
+ NUMBER_OF_RETRIES = 10
31
+
32
+
33
+ class TransportAdapter(HTTPAdapter):
34
+ """Implementation of a transport adaptor.
35
+
36
+ Transport adapters define methods for interacting with HTTP services,
37
+ enabling the use of per-service configurations.
38
+
39
+ Args:
40
+ *args: Positional arguments.
41
+ rate_limit (optional): Rate limit.
42
+ timeout (optional): Timeout.
43
+ **kwargs: Keyword arguments.
44
+
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ *args: Any,
50
+ rate_limit: int = DEFAULT_RATE_LIMIT,
51
+ timeout: int = DEFAULT_TIMEOUT,
52
+ **kwargs: Any,
53
+ ) -> None:
54
+ kwargs.setdefault("max_retries", make_retry(rate_limit))
55
+ super().__init__(*args, **kwargs)
56
+ self.timeout = timeout
57
+
58
+ def send(
59
+ self,
60
+ request: PreparedRequest,
61
+ *args: Any,
62
+ **kwargs: Any,
63
+ ) -> Response:
64
+ kwargs.setdefault("timeout", self.timeout)
65
+ return super().send(request, *args, **kwargs)
66
+
67
+
68
+ def make_retry(rate_limit: int) -> Retry:
69
+ """Make retry configuration.
70
+
71
+ Args:
72
+ rate_limit: Rate limit for backoff factor.
73
+
74
+ Returns:
75
+ Retry configuration.
76
+
77
+ """
78
+ result = Retry(
79
+ total=NUMBER_OF_RETRIES,
80
+ status_forcelist=[
81
+ HTTPStatus.REQUEST_ENTITY_TOO_LARGE,
82
+ HTTPStatus.TOO_MANY_REQUESTS,
83
+ HTTPStatus.INTERNAL_SERVER_ERROR,
84
+ HTTPStatus.BAD_GATEWAY,
85
+ HTTPStatus.SERVICE_UNAVAILABLE,
86
+ HTTPStatus.GATEWAY_TIMEOUT,
87
+ ],
88
+ allowed_methods=[method.name for method in HTTPMethod],
89
+ backoff_factor=rate_limit,
90
+ )
91
+ return result
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/apis/__init__.py
3
+
4
+ # Local Imports
5
+ from .abstract_api import *
6
+ from .web_api import *
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/apis/abstract_api.py
3
+ """Abstract API Class.
4
+
5
+ This module defines an abstract API 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
+
18
+ __all__ = ["AbstractAPI"]
19
+
20
+
21
+ class AbstractAPI(abc.ABC):
22
+ """Represents an abstract API."""
23
+
24
+ @property
25
+ @abc.abstractmethod
26
+ def connection(self) -> Optional[AbstractConnection]:
27
+ """Connection with which to make requests."""
28
+ raise NotImplementedError
29
+
30
+ @abc.abstractmethod
31
+ def __eq__(self, other: object) -> bool:
32
+ raise NotImplementedError
33
+
34
+ @abc.abstractmethod
35
+ def __hash__(self) -> int:
36
+ raise NotImplementedError
@@ -0,0 +1,460 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/apis/web_api.py
3
+ """Web API class.
4
+
5
+ This module defines the web API class implementation.
6
+
7
+ """
8
+
9
+ # Standard Library Imports
10
+ from __future__ import annotations
11
+ from typing import Any
12
+ from typing import Dict
13
+ from typing import final
14
+ from typing import Optional
15
+ from typing import Type
16
+
17
+ # Third-Party Imports
18
+ from requests import Response
19
+
20
+ # Local Imports
21
+ from .abstract_api import AbstractAPI
22
+ from ..connections import HttpConnection
23
+ from ..endpoints import WebEndpoint
24
+ from ..engines import AbstractEngine
25
+ from ..routes import AbstractRoute
26
+ from .. import errors
27
+
28
+ __all__ = ["WebAPI"]
29
+
30
+
31
+ class WebAPI(AbstractAPI):
32
+ """Implements a web API.
33
+
34
+ Args:
35
+ engine: Engine.
36
+ endpoints (optional): Endpoints. Default ``None``.
37
+ locked (optional): Whether to lock endpoints. Default ``False``.
38
+
39
+ Raises:
40
+ TypeError: when `engine` argument is not type ``Engine``.
41
+ TypeError: when `endpoints` argument is not type ``dict``.
42
+ TypeError: when `locked` argument is not type ``bool``.
43
+
44
+ """
45
+
46
+ def __init__(
47
+ self,
48
+ engine: AbstractEngine,
49
+ /,
50
+ endpoints: Optional[Dict[AbstractRoute, Type[WebEndpoint]]] = None,
51
+ *,
52
+ locked: bool = False,
53
+ ) -> None:
54
+ if not isinstance(engine, AbstractEngine): # type: ignore
55
+ message = f"expected type 'Engine', got {type(engine)} instead"
56
+ raise TypeError(message)
57
+
58
+ if endpoints and not isinstance(endpoints, dict): # type: ignore
59
+ message = f"expected type 'dict', got {type(endpoints)} instead"
60
+ raise TypeError(message)
61
+
62
+ if not isinstance(locked, bool): # type: ignore
63
+ message = f"expected type 'bool', got {type(locked)} instead"
64
+ raise TypeError(message)
65
+
66
+ self._engine = engine
67
+ self._endpoints = endpoints.copy() if endpoints else {}
68
+ self._locked = locked
69
+
70
+ @property
71
+ def connection(self) -> Optional[HttpConnection]:
72
+ """Connection with which to make requests."""
73
+ result = getattr(self, "_connection", None)
74
+ return result
75
+
76
+ @property
77
+ def url(self) -> str:
78
+ """Base URL."""
79
+ return self._engine.url
80
+
81
+ @final
82
+ def __enter__(self) -> AbstractAPI:
83
+ """Starts API as context manager."""
84
+ self.connect()
85
+ return self
86
+
87
+ @final
88
+ def __exit__(self, *_) -> None:
89
+ """Ends API as context manager."""
90
+ self.close()
91
+
92
+ def __eq__(self, other: object) -> bool:
93
+ result = (
94
+ other.url.lower() == self.url.lower()
95
+ if isinstance(other, WebAPI)
96
+ else False
97
+ )
98
+ return result
99
+
100
+ def __hash__(self) -> int:
101
+ result = hash(self.url)
102
+ return result
103
+
104
+ def __repr__(self) -> str:
105
+ result = f"<{self.__class__.__name__!s} url={self.url!s}>"
106
+ return result
107
+
108
+ def __getitem__(self, path: str) -> WebEndpoint:
109
+ """Get endpoint.
110
+
111
+ Args:
112
+ path: Relative path of endpoint.
113
+
114
+ Returns:
115
+ Endpoint.
116
+
117
+ """
118
+ result = self.get_endpoint(path)
119
+ return result
120
+
121
+ def __truediv__(self, path: str) -> WebEndpoint:
122
+ """Get endpoint.
123
+
124
+ Args:
125
+ path: Relative path of endpoint.
126
+
127
+ Returns:
128
+ Endpoint.
129
+
130
+ """
131
+ result = self.get_endpoint(path)
132
+ return result
133
+
134
+ def get_endpoint(self, path: str) -> WebEndpoint:
135
+ """Get endpoint.
136
+
137
+ Arhs:
138
+ path: Relative path of endpoint.
139
+
140
+ Returns:
141
+ Endpoint.
142
+
143
+ """
144
+ try:
145
+ matches = sorted(
146
+ (route, endpoint)
147
+ for route, endpoint in self._endpoints.items()
148
+ if route == path
149
+ )
150
+ _, endpoint = next(iter(matches))
151
+
152
+ except StopIteration:
153
+ if self._locked is True:
154
+ message = f"endpoint not found: {path}"
155
+ raise errors.EndpointNotFound(message)
156
+
157
+ endpoint = WebEndpoint
158
+
159
+ result = endpoint(self, path)
160
+ return result
161
+
162
+ def connect(self) -> None:
163
+ """Start connection to web API."""
164
+ connection = self._engine.connect()
165
+ setattr(self, "_connection", connection)
166
+ connection.start()
167
+
168
+ def close(self) -> None:
169
+ """Close connection to web API."""
170
+ if self.connection is not None:
171
+ self.connection.close()
172
+ delattr(self, "_connection")
173
+
174
+ @final
175
+ def head(
176
+ self,
177
+ *,
178
+ headers: Optional[Dict[str, str]] = None,
179
+ params: Optional[Dict[str, Any]] = None,
180
+ **kwargs: Any,
181
+ ) -> Optional[Response]:
182
+ """Sends an HTTP HEAD request to the API.
183
+
184
+ Args:
185
+ headers (optional): Request headers (overrides global headers).
186
+ params (optional): Request parameters (overrides global parameters).
187
+ **kwargs: Keyword arguments to include in request.
188
+
189
+ Returns:
190
+ Response object.
191
+
192
+ Raises:
193
+ ConnectionNotStarted: when connection not started.
194
+
195
+ .. _MDN Web Docs:
196
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD
197
+
198
+ """
199
+ if self.connection is None:
200
+ message = "connection not started before making HEAD request"
201
+ raise errors.ConnectionNotStarted(message)
202
+
203
+ response = self.connection.head(
204
+ headers=headers,
205
+ params=params,
206
+ **kwargs,
207
+ )
208
+ return response
209
+
210
+ @final
211
+ def get(
212
+ self,
213
+ *,
214
+ headers: Optional[Dict[str, str]] = None,
215
+ params: Optional[Dict[str, Any]] = None,
216
+ **kwargs: Any,
217
+ ) -> Optional[Response]:
218
+ """Sends an HTTP GET request to the API.
219
+
220
+ Args:
221
+ headers (optional): Request headers (overrides global headers).
222
+ params (optional): Request parameters (overrides global parameters).
223
+ **kwargs: Keyword arguments to include in request.
224
+
225
+ Returns:
226
+ Response object.
227
+
228
+ Raises:
229
+ ConnectionNotStarted: when connection not started.
230
+
231
+ .. _MDN Web Docs:
232
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET
233
+
234
+ """
235
+ if self.connection is None:
236
+ message = "connection not started before making GET request"
237
+ raise errors.ConnectionNotStarted(message)
238
+
239
+ response = self.connection.get(
240
+ headers=headers,
241
+ params=params,
242
+ **kwargs,
243
+ )
244
+ return response
245
+
246
+ @final
247
+ def post(
248
+ self,
249
+ *,
250
+ headers: Optional[Dict[str, str]] = None,
251
+ params: Optional[Dict[str, Any]] = None,
252
+ **kwargs: Any,
253
+ ) -> Optional[Response]:
254
+ """Sends an HTTP POST request to the API.
255
+
256
+ Args:
257
+ headers (optional): Request headers (overrides global headers).
258
+ params (optional): Request parameters (overrides global parameters).
259
+ **kwargs: Keyword arguments to include in request.
260
+
261
+ Returns:
262
+ Response object.
263
+
264
+ Raises:
265
+ ConnectionNotStarted: when connection not started.
266
+
267
+ .. _MDN Web Docs:
268
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
269
+
270
+ """
271
+ if self.connection is None:
272
+ message = "connection not started before making POST request"
273
+ raise errors.ConnectionNotStarted(message)
274
+
275
+ response = self.connection.post(
276
+ headers=headers,
277
+ params=params,
278
+ **kwargs,
279
+ )
280
+ return response
281
+
282
+ @final
283
+ def put(
284
+ self,
285
+ *,
286
+ headers: Optional[Dict[str, str]] = None,
287
+ params: Optional[Dict[str, Any]] = None,
288
+ **kwargs: Any,
289
+ ) -> Optional[Response]:
290
+ """Sends an HTTP PUT request to the API.
291
+
292
+ Args:
293
+ headers (optional): Request headers (overrides global headers).
294
+ params (optional): Request parameters (overrides global parameters).
295
+ **kwargs: Keyword arguments to include in request.
296
+
297
+ Returns:
298
+ Response object.
299
+
300
+ Raises:
301
+ ConnectionNotStarted: when connection not started.
302
+
303
+ .. _MDN Web Docs:
304
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT
305
+
306
+ """
307
+ if self.connection is None:
308
+ message = "connection not started before making PUT request"
309
+ raise errors.ConnectionNotStarted(message)
310
+
311
+ response = self.connection.put(
312
+ headers=headers,
313
+ params=params,
314
+ **kwargs,
315
+ )
316
+ return response
317
+
318
+ @final
319
+ def patch(
320
+ self,
321
+ *,
322
+ headers: Optional[Dict[str, str]] = None,
323
+ params: Optional[Dict[str, Any]] = None,
324
+ **kwargs: Any,
325
+ ) -> Optional[Response]:
326
+ """Sends an HTTP PATCH request to the API.
327
+
328
+ Args:
329
+ headers (optional): Request headers (overrides global headers).
330
+ params (optional): Request parameters (overrides global parameters).
331
+ **kwargs: Keyword arguments to include in request.
332
+
333
+ Returns:
334
+ Response object.
335
+
336
+ Raises:
337
+ ConnectionNotStarted: when connection not started.
338
+
339
+ .. _MDN Web Docs:
340
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH
341
+
342
+ """
343
+ if self.connection is None:
344
+ message = "connection not started before making PATCH request"
345
+ raise errors.ConnectionNotStarted(message)
346
+
347
+ response = self.connection.patch(
348
+ headers=headers,
349
+ params=params,
350
+ **kwargs,
351
+ )
352
+ return response
353
+
354
+ @final
355
+ def delete(
356
+ self,
357
+ *,
358
+ headers: Optional[Dict[str, str]] = None,
359
+ params: Optional[Dict[str, Any]] = None,
360
+ **kwargs: Any,
361
+ ) -> Optional[Response]:
362
+ """Sends an HTTP DELETE request to the API.
363
+
364
+ Args:
365
+ headers (optional): Request headers (overrides global headers).
366
+ params (optional): Request parameters (overrides global parameters).
367
+ **kwargs: Keyword arguments to include in request.
368
+
369
+ Returns:
370
+ Response object.
371
+
372
+ Raises:
373
+ ConnectionNotStarted: when connection not started.
374
+
375
+ .. _MDN Web Docs:
376
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE
377
+
378
+ """
379
+ if self.connection is None:
380
+ message = "connection not started before making DELETE request"
381
+ raise errors.ConnectionNotStarted(message)
382
+
383
+ response = self.connection.delete(
384
+ headers=headers,
385
+ params=params,
386
+ **kwargs,
387
+ )
388
+ return response
389
+
390
+ @final
391
+ def options(
392
+ self,
393
+ *,
394
+ headers: Optional[Dict[str, str]] = None,
395
+ params: Optional[Dict[str, Any]] = None,
396
+ **kwargs: Any,
397
+ ) -> Optional[Response]:
398
+ """Sends an HTTP OPTIONS request to the API.
399
+
400
+ Args:
401
+ headers (optional): Request headers (overrides global headers).
402
+ params (optional): Request parameters (overrides global parameters).
403
+ **kwargs: Keyword arguments to include in request.
404
+
405
+ Returns:
406
+ Response object.
407
+
408
+ Raises:
409
+ ConnectionNotStarted: when connection not started.
410
+
411
+ .. _MDN Web Docs:
412
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
413
+
414
+ """
415
+ if self.connection is None:
416
+ message = "connection not started before making OPTIONS request"
417
+ raise errors.ConnectionNotStarted(message)
418
+
419
+ response = self.connection.options(
420
+ headers=headers,
421
+ params=params,
422
+ **kwargs,
423
+ )
424
+ return response
425
+
426
+ @final
427
+ def trace(
428
+ self,
429
+ *,
430
+ headers: Optional[Dict[str, str]] = None,
431
+ params: Optional[Dict[str, Any]] = None,
432
+ **kwargs: Any,
433
+ ) -> Optional[Response]:
434
+ """Sends an HTTP TRACE request to the API.
435
+
436
+ Args:
437
+ headers (optional): Request headers (overrides global headers).
438
+ params (optional): Request parameters (overrides global parameters).
439
+ **kwargs: Keyword arguments to include in request.
440
+
441
+ Returns:
442
+ Response object.
443
+
444
+ Raises:
445
+ ConnectionNotStarted: when connection not started.
446
+
447
+ .. _MDN Web Docs:
448
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/TRACE
449
+
450
+ """
451
+ if self.connection is None:
452
+ message = "connection not started before making TRACE request"
453
+ raise errors.ConnectionNotStarted(message)
454
+
455
+ response = self.connection.trace(
456
+ headers=headers,
457
+ params=params,
458
+ **kwargs,
459
+ )
460
+ return response
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/connections/__init__.py
3
+
4
+ # Local Imports
5
+ from .abstract_connection import *
6
+ from .http_connection import *
@@ -0,0 +1,28 @@
1
+ # -*- coding: utf-8 -*-
2
+ # src/apytizer/connections/abstract_connection.py
3
+ """Abstract Connection Class.
4
+
5
+ This module defines an abstract connection class which provides an
6
+ interface for subclasses to implement.
7
+
8
+ """
9
+
10
+ # Standard Library Imports
11
+ from __future__ import annotations
12
+ import abc
13
+
14
+ __all__ = ["AbstractConnection"]
15
+
16
+
17
+ class AbstractConnection(abc.ABC):
18
+ """Represents an abstract connection."""
19
+
20
+ @abc.abstractmethod
21
+ def start(self) -> None:
22
+ """Start connection."""
23
+ raise NotImplementedError
24
+
25
+ @abc.abstractmethod
26
+ def close(self) -> None:
27
+ """Close connection."""
28
+ raise NotImplementedError