celitech-sdk 1.0.0__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 (53) hide show
  1. celitech/__init__.py +2 -0
  2. celitech/hooks/__init__.py +0 -0
  3. celitech/hooks/hook.py +95 -0
  4. celitech/models/__init__.py +14 -0
  5. celitech/models/base.py +251 -0
  6. celitech/models/create_purchase_ok_response.py +85 -0
  7. celitech/models/create_purchase_request.py +54 -0
  8. celitech/models/edit_purchase_ok_response.py +41 -0
  9. celitech/models/edit_purchase_request.py +41 -0
  10. celitech/models/get_esim_device_ok_response.py +41 -0
  11. celitech/models/get_esim_history_ok_response.py +50 -0
  12. celitech/models/get_esim_mac_ok_response.py +39 -0
  13. celitech/models/get_esim_ok_response.py +43 -0
  14. celitech/models/get_purchase_consumption_ok_response.py +17 -0
  15. celitech/models/list_destinations_ok_response.py +38 -0
  16. celitech/models/list_packages_ok_response.py +61 -0
  17. celitech/models/list_purchases_ok_response.py +129 -0
  18. celitech/models/top_up_esim_ok_response.py +82 -0
  19. celitech/models/top_up_esim_request.py +49 -0
  20. celitech/models/utils/cast_models.py +81 -0
  21. celitech/models/utils/json_map.py +80 -0
  22. celitech/net/__init__.py +0 -0
  23. celitech/net/environment/__init__.py +1 -0
  24. celitech/net/environment/environment.py +11 -0
  25. celitech/net/headers/__init__.py +0 -0
  26. celitech/net/headers/base_header.py +9 -0
  27. celitech/net/request_chain/__init__.py +0 -0
  28. celitech/net/request_chain/handlers/__init__.py +0 -0
  29. celitech/net/request_chain/handlers/base_handler.py +39 -0
  30. celitech/net/request_chain/handlers/hook_handler.py +47 -0
  31. celitech/net/request_chain/handlers/http_handler.py +80 -0
  32. celitech/net/request_chain/handlers/retry_handler.py +65 -0
  33. celitech/net/request_chain/request_chain.py +57 -0
  34. celitech/net/transport/__init__.py +0 -0
  35. celitech/net/transport/request.py +89 -0
  36. celitech/net/transport/request_error.py +53 -0
  37. celitech/net/transport/response.py +57 -0
  38. celitech/net/transport/serializer.py +249 -0
  39. celitech/net/transport/utils.py +28 -0
  40. celitech/sdk.py +30 -0
  41. celitech/services/__init__.py +0 -0
  42. celitech/services/destinations.py +29 -0
  43. celitech/services/e_sim.py +121 -0
  44. celitech/services/packages.py +72 -0
  45. celitech/services/purchases.py +189 -0
  46. celitech/services/utils/base_service.py +63 -0
  47. celitech/services/utils/default_headers.py +57 -0
  48. celitech/services/utils/validator.py +170 -0
  49. celitech_sdk-1.0.0.dist-info/LICENSE +21 -0
  50. celitech_sdk-1.0.0.dist-info/METADATA +482 -0
  51. celitech_sdk-1.0.0.dist-info/RECORD +53 -0
  52. celitech_sdk-1.0.0.dist-info/WHEEL +5 -0
  53. celitech_sdk-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,189 @@
1
+ from .utils.validator import Validator
2
+ from .utils.base_service import BaseService
3
+ from ..net.transport.serializer import Serializer
4
+ from ..models.utils.cast_models import cast_models
5
+ from ..models.top_up_esim_request import TopUpEsimRequest
6
+ from ..models.top_up_esim_ok_response import TopUpEsimOkResponse
7
+ from ..models.list_purchases_ok_response import ListPurchasesOkResponse
8
+ from ..models.get_purchase_consumption_ok_response import (
9
+ GetPurchaseConsumptionOkResponse,
10
+ )
11
+ from ..models.edit_purchase_request import EditPurchaseRequest
12
+ from ..models.edit_purchase_ok_response import EditPurchaseOkResponse
13
+ from ..models.create_purchase_request import CreatePurchaseRequest
14
+ from ..models.create_purchase_ok_response import CreatePurchaseOkResponse
15
+
16
+
17
+ class PurchasesService(BaseService):
18
+
19
+ @cast_models
20
+ def list_purchases(
21
+ self,
22
+ iccid: str = None,
23
+ after_date: str = None,
24
+ before_date: str = None,
25
+ after_cursor: str = None,
26
+ limit: float = None,
27
+ after: float = None,
28
+ before: float = None,
29
+ ) -> ListPurchasesOkResponse:
30
+ """This endpoint can be used to list all the successful purchases made between a given interval.
31
+
32
+ :param iccid: iccid, defaults to None
33
+ :type iccid: str, optional
34
+ :param after_date: Start date of the interval for filtering purchases in the format 'yyyy-MM-dd', defaults to None
35
+ :type after_date: str, optional
36
+ :param before_date: End date of the interval for filtering purchases in the format 'yyyy-MM-dd', defaults to None
37
+ :type before_date: str, optional
38
+ :param after_cursor: after_cursor, defaults to None
39
+ :type after_cursor: str, optional
40
+ :param limit: limit, defaults to None
41
+ :type limit: float, optional
42
+ :param after: Epoch value representing the start of the time interval for filtering purchases, defaults to None
43
+ :type after: float, optional
44
+ :param before: Epoch value representing the end of the time interval for filtering purchases, defaults to None
45
+ :type before: float, optional
46
+ ...
47
+ :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
48
+ ...
49
+ :return: Successful Response
50
+ :rtype: ListPurchasesOkResponse
51
+ """
52
+
53
+ Validator(str).is_optional().validate(iccid)
54
+ Validator(str).is_optional().validate(after_date)
55
+ Validator(str).is_optional().validate(before_date)
56
+ Validator(str).is_optional().validate(after_cursor)
57
+ Validator(float).is_optional().validate(limit)
58
+ Validator(float).is_optional().validate(after)
59
+ Validator(float).is_optional().validate(before)
60
+
61
+ serialized_request = (
62
+ Serializer(f"{self.base_url}/purchases", self.get_default_headers())
63
+ .add_query("iccid", iccid)
64
+ .add_query("afterDate", after_date)
65
+ .add_query("beforeDate", before_date)
66
+ .add_query("afterCursor", after_cursor)
67
+ .add_query("limit", limit)
68
+ .add_query("after", after)
69
+ .add_query("before", before)
70
+ .serialize()
71
+ .set_method("GET")
72
+ )
73
+
74
+ response = self.send_request(serialized_request)
75
+
76
+ return ListPurchasesOkResponse._unmap(response)
77
+
78
+ @cast_models
79
+ def create_purchase(
80
+ self, request_body: CreatePurchaseRequest = None
81
+ ) -> CreatePurchaseOkResponse:
82
+ """This endpoint is used to purchase a new eSIM by providing the package details.
83
+
84
+ :param request_body: The request body., defaults to None
85
+ :type request_body: CreatePurchaseRequest, optional
86
+ ...
87
+ :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
88
+ ...
89
+ :return: Successful Response
90
+ :rtype: CreatePurchaseOkResponse
91
+ """
92
+
93
+ Validator(CreatePurchaseRequest).is_optional().validate(request_body)
94
+
95
+ serialized_request = (
96
+ Serializer(f"{self.base_url}/purchases", self.get_default_headers())
97
+ .serialize()
98
+ .set_method("POST")
99
+ .set_body(request_body)
100
+ )
101
+
102
+ response = self.send_request(serialized_request)
103
+
104
+ return CreatePurchaseOkResponse._unmap(response)
105
+
106
+ @cast_models
107
+ def top_up_esim(self, request_body: TopUpEsimRequest = None) -> TopUpEsimOkResponse:
108
+ """This endpoint is used to top-up an eSIM with the previously associated destination by providing an existing ICCID and the package details. The top-up is not feasible for eSIMs in "DELETED" or "ERROR" state.
109
+
110
+ :param request_body: The request body., defaults to None
111
+ :type request_body: TopUpEsimRequest, optional
112
+ ...
113
+ :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
114
+ ...
115
+ :return: Successful Response
116
+ :rtype: TopUpEsimOkResponse
117
+ """
118
+
119
+ Validator(TopUpEsimRequest).is_optional().validate(request_body)
120
+
121
+ serialized_request = (
122
+ Serializer(f"{self.base_url}/purchases/topup", self.get_default_headers())
123
+ .serialize()
124
+ .set_method("POST")
125
+ .set_body(request_body)
126
+ )
127
+
128
+ response = self.send_request(serialized_request)
129
+
130
+ return TopUpEsimOkResponse._unmap(response)
131
+
132
+ @cast_models
133
+ def edit_purchase(
134
+ self, request_body: EditPurchaseRequest = None
135
+ ) -> EditPurchaseOkResponse:
136
+ """This endpoint allows you to modify the dates of an existing package with a future activation start time. Editing can only be performed for packages that have not been activated, and it cannot change the package size. The modification must not change the package duration category to ensure pricing consistency.
137
+
138
+ :param request_body: The request body., defaults to None
139
+ :type request_body: EditPurchaseRequest, optional
140
+ ...
141
+ :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
142
+ ...
143
+ :return: Successful Response
144
+ :rtype: EditPurchaseOkResponse
145
+ """
146
+
147
+ Validator(EditPurchaseRequest).is_optional().validate(request_body)
148
+
149
+ serialized_request = (
150
+ Serializer(f"{self.base_url}/purchases/edit", self.get_default_headers())
151
+ .serialize()
152
+ .set_method("POST")
153
+ .set_body(request_body)
154
+ )
155
+
156
+ response = self.send_request(serialized_request)
157
+
158
+ return EditPurchaseOkResponse._unmap(response)
159
+
160
+ @cast_models
161
+ def get_purchase_consumption(
162
+ self, purchase_id: str
163
+ ) -> GetPurchaseConsumptionOkResponse:
164
+ """This endpoint can be called for consumption notifications (e.g. every 1 hour or when the user clicks a button). It returns the data balance (consumption) of purchased packages.
165
+
166
+ :param purchase_id: purchase_id
167
+ :type purchase_id: str
168
+ ...
169
+ :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
170
+ ...
171
+ :return: Successful Response
172
+ :rtype: GetPurchaseConsumptionOkResponse
173
+ """
174
+
175
+ Validator(str).validate(purchase_id)
176
+
177
+ serialized_request = (
178
+ Serializer(
179
+ f"{self.base_url}/purchases/{{purchaseId}}/consumption",
180
+ self.get_default_headers(),
181
+ )
182
+ .add_path("purchaseId", purchase_id)
183
+ .serialize()
184
+ .set_method("GET")
185
+ )
186
+
187
+ response = self.send_request(serialized_request)
188
+
189
+ return GetPurchaseConsumptionOkResponse._unmap(response)
@@ -0,0 +1,63 @@
1
+ from typing import Any, Dict
2
+ from enum import Enum
3
+
4
+ from .default_headers import DefaultHeaders, DefaultHeadersKeys
5
+ from ...net.transport.request import Request
6
+ from ...net.request_chain.request_chain import RequestChain
7
+ from ...net.request_chain.handlers.hook_handler import HookHandler
8
+ from ...net.request_chain.handlers.http_handler import HttpHandler
9
+ from ...net.request_chain.handlers.retry_handler import RetryHandler
10
+
11
+
12
+ class BaseService:
13
+ """
14
+ A base class for services providing common functionality.
15
+
16
+ :ivar str base_url: The base URL for the service.
17
+ :ivar dict _default_headers: A dictionary of default headers.
18
+ """
19
+
20
+ def __init__(self, base_url: str) -> None:
21
+ """
22
+ Initializes a BaseService instance.
23
+
24
+ :param str base_url: The base URL for the service. Defaults to None.
25
+ """
26
+ self.base_url = base_url
27
+ self._default_headers = DefaultHeaders()
28
+ self._request_handler = (
29
+ RequestChain()
30
+ .add_handler(RetryHandler())
31
+ .add_handler(HookHandler())
32
+ .add_handler(HttpHandler())
33
+ )
34
+
35
+ def set_base_url(self, base_url: str):
36
+ """
37
+ Sets the base URL for the service.
38
+
39
+ :param str base_url: The base URL to be set.
40
+ """
41
+ self.base_url = base_url
42
+
43
+ return self
44
+
45
+ def send_request(self, request: Request) -> dict:
46
+ """
47
+ Sends the given request.
48
+
49
+ :param Request request: The request to be sent.
50
+ :return: The response data.
51
+ :rtype: dict
52
+ """
53
+ response = self._request_handler.send(request)
54
+ return response.body
55
+
56
+ def get_default_headers(self) -> list:
57
+ """
58
+ Get the default headers.
59
+
60
+ :return: A list of the default headers.
61
+ :rtype: list
62
+ """
63
+ return self._default_headers.get_headers()
@@ -0,0 +1,57 @@
1
+ from enum import Enum
2
+ from typing import Any, Dict
3
+
4
+ from ...net.headers.base_header import BaseHeader
5
+
6
+
7
+ class DefaultHeadersKeys(Enum):
8
+ """
9
+ An enumeration of default headers.
10
+
11
+ :ivar str ACCESS_AUTH: The access token authentication header.
12
+ :ivar str BASIC_AUTH: The basic authentication header.
13
+ :ivar str API_KEY_AUTH: The API key authentication header.
14
+ """
15
+
16
+ ACCESS_AUTH = "access_token_auth"
17
+ BASIC_AUTH = "basic_auth"
18
+ API_KEY_AUTH = "api_key_auth"
19
+
20
+
21
+ class DefaultHeaders:
22
+ """
23
+ A class to manage default headers.
24
+
25
+ :ivar Dict[str, BaseHeader] _default_headers: The default headers.
26
+ """
27
+
28
+ def __init__(self):
29
+ self._default_headers: Dict[str, BaseHeader] = {}
30
+
31
+ def set_header(self, key: DefaultHeadersKeys, value: BaseHeader) -> None:
32
+ """
33
+ Set a default header.
34
+
35
+ :param DefaultHeadersKeys key: The key of the header to set.
36
+ :param Any value: The value to set for the header.
37
+ """
38
+ self._default_headers[key.value] = value
39
+
40
+ def get_header(self, key: DefaultHeadersKeys) -> BaseHeader:
41
+ """
42
+ Get a default header.
43
+
44
+ :param DefaultHeadersKeys key: The key of the header to get.
45
+ :return: The value of the header.
46
+ :rtype: Any
47
+ """
48
+ return self._default_headers[key.value]
49
+
50
+ def get_headers(self) -> list:
51
+ """
52
+ Get the default headers.
53
+
54
+ :return: A list of the default headers.
55
+ :rtype: list
56
+ """
57
+ return list(self._default_headers.values())
@@ -0,0 +1,170 @@
1
+ import re
2
+ from typing import Union, Any, Type, Pattern, get_args
3
+ from ...models.base import OneOfBaseModel
4
+
5
+
6
+ class Validator:
7
+ """
8
+ A simple validator class for validating the type and pattern of a value.
9
+
10
+ :ivar Type[Any] _type: The expected type for the value.
11
+ :ivar bool _is_optional: Flag indicating whether the value is optional.
12
+ :ivar bool _is_array: Flag indicating whether the value is an array.
13
+ :ivar Pattern[str] _pattern: The regular expression pattern for validating the value.
14
+ :ivar int _min: The minimum value for validating the value.
15
+ :ivar int _max: The maximum value for validating the value.
16
+ """
17
+
18
+ def __init__(self, _type: Type[Any] = None):
19
+ """
20
+ Initializes a Validator instance.
21
+
22
+ :param Type[Any] _type: The expected type for the value. Defaults to None.
23
+ """
24
+ self._type: Type[Any] = _type
25
+ self._is_optional: bool = False
26
+ self._is_array: bool = False
27
+ self._pattern: Pattern[str] = None
28
+ self._min: int = None
29
+ self._max: int = None
30
+
31
+ def is_array(self) -> "Validator":
32
+ """
33
+ Marks the value as an array.
34
+
35
+ :return: The Validator instance for method chaining.
36
+ :rtype: Validator
37
+ """
38
+ self._is_array = True
39
+ return self
40
+
41
+ def is_optional(self) -> "Validator":
42
+ """
43
+ Marks the value as optional.
44
+
45
+ :return: The Validator instance for method chaining.
46
+ :rtype: Validator
47
+ """
48
+ self._is_optional = True
49
+ return self
50
+
51
+ def pattern(self, pattern: str) -> "Validator":
52
+ """
53
+ Specifies a regular expression pattern for validating the value.
54
+
55
+ :param str pattern: The regular expression pattern.
56
+ :return: The Validator instance for method chaining.
57
+ :rtype: Validator
58
+ """
59
+ self._pattern = re.compile(pattern)
60
+ return self
61
+
62
+ def min(self, min: int) -> "Validator":
63
+ """
64
+ Specifies a minimum value for validating the value.
65
+
66
+ :param int min: The minimum value.
67
+ :return: The Validator instance for method chaining.
68
+ :rtype: Validator
69
+ """
70
+ self._min = min
71
+ return self
72
+
73
+ def max(self, max: int) -> "Validator":
74
+ """
75
+ Specifies a maximum value for validating the value.
76
+
77
+ :param int max: The maximum value.
78
+ :return: The Validator instance for method chaining.
79
+ :rtype: Validator
80
+ """
81
+ self._max = max
82
+ return self
83
+
84
+ def validate(self, value: Any) -> None:
85
+ """
86
+ Validates the provided value based on the specified criteria.
87
+
88
+ :param Any value: The input that needs to be checked
89
+ :raises ValueError: If the value does not meet the specified validation criteria.
90
+ """
91
+ if not self._type:
92
+ raise TypeError("Invalid type: No type specified")
93
+ if self._is_optional and value is None:
94
+ return
95
+
96
+ self._validate_type(value)
97
+ self._validate_rules(value)
98
+
99
+ def _validate_type(self, value: Any) -> None:
100
+ """
101
+ Validates the type of the value.
102
+
103
+ :param Any value: The input that needs to be checked
104
+ :raises ValueError: If the value does not meet the expected type.
105
+ """
106
+ if self._is_one_of_type(self._type):
107
+ self._validate_one_of_type(value)
108
+ elif self._is_array:
109
+ self._validate_array_type(value)
110
+ elif not self._match_type(value):
111
+ raise TypeError(f"Invalid type: Expected {self._type}, got {type(value)}")
112
+
113
+ def _validate_one_of_type(self, value: Any) -> None:
114
+ """
115
+ Validates oneOf model type.
116
+
117
+ :param Any value: The input that needs to be checked
118
+ :raises ValueError: If the value does not match the oneOf rules.
119
+ """
120
+ class_list = {arg.__name__: arg for arg in get_args(self._type) if arg.__name__}
121
+ OneOfBaseModel.class_list = class_list
122
+ OneOfBaseModel.return_one_of(value)
123
+
124
+ def _validate_array_type(self, value: Any) -> None:
125
+ """
126
+ Validates the type of an array value.
127
+
128
+ :param Any value: The input that needs to be checked
129
+ :raises ValueError: If the array items do not match the expected type.
130
+ """
131
+ if any(self._match_type(v) is False for v in value):
132
+ raise TypeError(f"Invalid type: Expected {self._type}, got {type(value)}")
133
+
134
+ def _match_type(self, value: Any) -> bool:
135
+ """
136
+ Checks if the value matches the expected type.
137
+
138
+ :param Any value: The input that needs to be checked
139
+ :raises ValueError: If the value does not match the expected type.
140
+ """
141
+ is_numeric = self._type is float and isinstance(value, int)
142
+ if isinstance(value, self._type) or is_numeric:
143
+ return True
144
+ return False
145
+
146
+ def _validate_rules(self, value: Any) -> None:
147
+ """
148
+ Validate the rules specified for the value.
149
+
150
+ :param Any value: The input that needs to be validated
151
+ :raises ValueError: If the value does not meet the specified validation criteria.
152
+ """
153
+ if self._min is not None and value < self._min:
154
+ raise ValueError(f"Invalid value: {value} is less than {self._min}")
155
+ if self._max is not None and value > self._max:
156
+ raise ValueError(f"Invalid value: {value} is greater than {self._max}")
157
+ if self._pattern and not self._pattern.match(str(value)):
158
+ raise ValueError(
159
+ f"Invalid value: {value} does not match pattern {self._pattern}"
160
+ )
161
+
162
+ def _is_one_of_type(self, cls_type):
163
+ """
164
+ Checks if the provided type is a Union type.
165
+
166
+ :param Type[Any] cls_type: The type to be checked.
167
+ :return: True if the type is a Union type, False otherwise.
168
+ :rtype: bool
169
+ """
170
+ return hasattr(cls_type, "__origin__") and cls_type.__origin__ is Union
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.