everysk-lib 1.10.2__cp312-cp312-win_amd64.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 (137) hide show
  1. everysk/__init__.py +30 -0
  2. everysk/_version.py +683 -0
  3. everysk/api/__init__.py +61 -0
  4. everysk/api/api_requestor.py +167 -0
  5. everysk/api/api_resources/__init__.py +23 -0
  6. everysk/api/api_resources/api_resource.py +371 -0
  7. everysk/api/api_resources/calculation.py +779 -0
  8. everysk/api/api_resources/custom_index.py +42 -0
  9. everysk/api/api_resources/datastore.py +81 -0
  10. everysk/api/api_resources/file.py +42 -0
  11. everysk/api/api_resources/market_data.py +223 -0
  12. everysk/api/api_resources/parser.py +66 -0
  13. everysk/api/api_resources/portfolio.py +43 -0
  14. everysk/api/api_resources/private_security.py +42 -0
  15. everysk/api/api_resources/report.py +65 -0
  16. everysk/api/api_resources/report_template.py +39 -0
  17. everysk/api/api_resources/tests.py +115 -0
  18. everysk/api/api_resources/worker_execution.py +64 -0
  19. everysk/api/api_resources/workflow.py +65 -0
  20. everysk/api/api_resources/workflow_execution.py +93 -0
  21. everysk/api/api_resources/workspace.py +42 -0
  22. everysk/api/http_client.py +63 -0
  23. everysk/api/tests.py +32 -0
  24. everysk/api/utils.py +262 -0
  25. everysk/config.py +451 -0
  26. everysk/core/_tests/serialize/test_json.py +336 -0
  27. everysk/core/_tests/serialize/test_orjson.py +295 -0
  28. everysk/core/_tests/serialize/test_pickle.py +48 -0
  29. everysk/core/cloud_function/main.py +78 -0
  30. everysk/core/cloud_function/tests.py +86 -0
  31. everysk/core/compress.py +245 -0
  32. everysk/core/datetime/__init__.py +12 -0
  33. everysk/core/datetime/calendar.py +144 -0
  34. everysk/core/datetime/date.py +424 -0
  35. everysk/core/datetime/date_expression.py +299 -0
  36. everysk/core/datetime/date_mixin.py +1475 -0
  37. everysk/core/datetime/date_settings.py +30 -0
  38. everysk/core/datetime/datetime.py +713 -0
  39. everysk/core/exceptions.py +435 -0
  40. everysk/core/fields.py +1176 -0
  41. everysk/core/firestore.py +555 -0
  42. everysk/core/fixtures/_settings.py +29 -0
  43. everysk/core/fixtures/other/_settings.py +18 -0
  44. everysk/core/fixtures/user_agents.json +88 -0
  45. everysk/core/http.py +691 -0
  46. everysk/core/lists.py +92 -0
  47. everysk/core/log.py +709 -0
  48. everysk/core/number.py +37 -0
  49. everysk/core/object.py +1469 -0
  50. everysk/core/redis.py +1021 -0
  51. everysk/core/retry.py +51 -0
  52. everysk/core/serialize.py +674 -0
  53. everysk/core/sftp.py +414 -0
  54. everysk/core/signing.py +53 -0
  55. everysk/core/slack.py +127 -0
  56. everysk/core/string.py +199 -0
  57. everysk/core/tests.py +240 -0
  58. everysk/core/threads.py +199 -0
  59. everysk/core/undefined.py +70 -0
  60. everysk/core/unittests.py +73 -0
  61. everysk/core/workers.py +241 -0
  62. everysk/sdk/__init__.py +23 -0
  63. everysk/sdk/base.py +98 -0
  64. everysk/sdk/brutils/cnpj.py +391 -0
  65. everysk/sdk/brutils/cnpj_pd.py +129 -0
  66. everysk/sdk/engines/__init__.py +26 -0
  67. everysk/sdk/engines/cache.py +185 -0
  68. everysk/sdk/engines/compliance.py +37 -0
  69. everysk/sdk/engines/cryptography.py +69 -0
  70. everysk/sdk/engines/expression.cp312-win_amd64.pyd +0 -0
  71. everysk/sdk/engines/expression.pyi +55 -0
  72. everysk/sdk/engines/helpers.cp312-win_amd64.pyd +0 -0
  73. everysk/sdk/engines/helpers.pyi +26 -0
  74. everysk/sdk/engines/lock.py +120 -0
  75. everysk/sdk/engines/market_data.py +244 -0
  76. everysk/sdk/engines/settings.py +19 -0
  77. everysk/sdk/entities/__init__.py +23 -0
  78. everysk/sdk/entities/base.py +784 -0
  79. everysk/sdk/entities/base_list.py +131 -0
  80. everysk/sdk/entities/custom_index/base.py +209 -0
  81. everysk/sdk/entities/custom_index/settings.py +29 -0
  82. everysk/sdk/entities/datastore/base.py +160 -0
  83. everysk/sdk/entities/datastore/settings.py +17 -0
  84. everysk/sdk/entities/fields.py +375 -0
  85. everysk/sdk/entities/file/base.py +215 -0
  86. everysk/sdk/entities/file/settings.py +63 -0
  87. everysk/sdk/entities/portfolio/base.py +248 -0
  88. everysk/sdk/entities/portfolio/securities.py +241 -0
  89. everysk/sdk/entities/portfolio/security.py +580 -0
  90. everysk/sdk/entities/portfolio/settings.py +97 -0
  91. everysk/sdk/entities/private_security/base.py +226 -0
  92. everysk/sdk/entities/private_security/settings.py +17 -0
  93. everysk/sdk/entities/query.py +603 -0
  94. everysk/sdk/entities/report/base.py +214 -0
  95. everysk/sdk/entities/report/settings.py +23 -0
  96. everysk/sdk/entities/script.py +310 -0
  97. everysk/sdk/entities/secrets/base.py +128 -0
  98. everysk/sdk/entities/secrets/script.py +119 -0
  99. everysk/sdk/entities/secrets/settings.py +17 -0
  100. everysk/sdk/entities/settings.py +48 -0
  101. everysk/sdk/entities/tags.py +174 -0
  102. everysk/sdk/entities/worker_execution/base.py +307 -0
  103. everysk/sdk/entities/worker_execution/settings.py +63 -0
  104. everysk/sdk/entities/workflow_execution/base.py +113 -0
  105. everysk/sdk/entities/workflow_execution/settings.py +32 -0
  106. everysk/sdk/entities/workspace/base.py +99 -0
  107. everysk/sdk/entities/workspace/settings.py +27 -0
  108. everysk/sdk/settings.py +67 -0
  109. everysk/sdk/tests.py +105 -0
  110. everysk/sdk/worker_base.py +47 -0
  111. everysk/server/__init__.py +9 -0
  112. everysk/server/applications.py +63 -0
  113. everysk/server/endpoints.py +516 -0
  114. everysk/server/example_api.py +69 -0
  115. everysk/server/middlewares.py +80 -0
  116. everysk/server/requests.py +62 -0
  117. everysk/server/responses.py +119 -0
  118. everysk/server/routing.py +64 -0
  119. everysk/server/settings.py +36 -0
  120. everysk/server/tests.py +36 -0
  121. everysk/settings.py +98 -0
  122. everysk/sql/__init__.py +9 -0
  123. everysk/sql/connection.py +232 -0
  124. everysk/sql/model.py +376 -0
  125. everysk/sql/query.py +417 -0
  126. everysk/sql/row_factory.py +63 -0
  127. everysk/sql/settings.py +49 -0
  128. everysk/sql/utils.py +129 -0
  129. everysk/tests.py +23 -0
  130. everysk/utils.py +81 -0
  131. everysk/version.py +15 -0
  132. everysk_lib-1.10.2.dist-info/.gitignore +5 -0
  133. everysk_lib-1.10.2.dist-info/METADATA +326 -0
  134. everysk_lib-1.10.2.dist-info/RECORD +137 -0
  135. everysk_lib-1.10.2.dist-info/WHEEL +5 -0
  136. everysk_lib-1.10.2.dist-info/licenses/LICENSE.txt +9 -0
  137. everysk_lib-1.10.2.dist-info/top_level.txt +2 -0
@@ -0,0 +1,70 @@
1
+ ###############################################################################
2
+ #
3
+ # (C) Copyright 2023 EVERYSK TECHNOLOGIES
4
+ #
5
+ # This is an unpublished work containing confidential and proprietary
6
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
7
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
8
+ #
9
+ ###############################################################################
10
+ from typing import Any, Self
11
+
12
+
13
+ ## Do not use this class, use the constant Undefined that is already defined in the python builtins. ##
14
+ class UndefinedType:
15
+ """
16
+ The UndefinedType class is used to represent an undefined value in the Everysk framework.
17
+ This class is designed to be immutable and to always represent the same undefined value.
18
+ We use it as default values for function parameters and class attributes to indicate that
19
+ the value is not set and to differentiate it from None or other possible values.
20
+ """
21
+
22
+ default_error_message = 'This object is immutable.'
23
+ default_parse_string = '__UNDEFINED_VALUE__'
24
+ default_repr_string = '<Undefined value>'
25
+ block = False
26
+
27
+ def __init__(self) -> None:
28
+ if self.block:
29
+ raise NotImplementedError('Do not use this class, use the constant Undefined.')
30
+
31
+ def __bool__(self) -> bool:
32
+ """Undefined object is always False"""
33
+ return False
34
+
35
+ def __copy__(self) -> Self:
36
+ """To keep consistence, this object will always be the same."""
37
+ return self
38
+
39
+ def __delattr__(self, name: str) -> None:
40
+ """We could not delete attributes from this object."""
41
+ raise AttributeError(self.default_error_message)
42
+
43
+ def __deepcopy__(self, memo: dict | None = None) -> Self:
44
+ """To keep consistence, this object will always be the same."""
45
+ return self
46
+
47
+ def __eq__(self, value: object) -> bool:
48
+ """For an object created from the UndefinedType class to be equal to another, the classes must be equal."""
49
+ return isinstance(value, type(self))
50
+
51
+ def __getattr__(self, name: str) -> Any:
52
+ """Undefined object don't have attributes."""
53
+ raise AttributeError(self.default_error_message)
54
+
55
+ def __hash__(self) -> int:
56
+ """Must return an int that is used as hash for this object."""
57
+ return id(self)
58
+
59
+ def __repr__(self) -> str:
60
+ """Fixed to be the same every time."""
61
+ return self.default_repr_string
62
+
63
+ def __setattr__(self, name: str, value: Any) -> None:
64
+ """We can't set any attribute to this object."""
65
+ if self.block:
66
+ raise AttributeError(self.default_error_message)
67
+
68
+ def __str__(self) -> str:
69
+ """Fixed to be the same every time."""
70
+ return self.default_repr_string
@@ -0,0 +1,73 @@
1
+ ###############################################################################
2
+ #
3
+ # (C) Copyright 2025 EVERYSK TECHNOLOGIES
4
+ #
5
+ # This is an unpublished work containing confidential and proprietary
6
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
7
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
8
+ #
9
+ ###############################################################################
10
+ __all__ = ['TestCase', 'mock', 'skip', 'skipUnless', 'SkipTest', 'skipIf']
11
+
12
+ import difflib
13
+ import pprint
14
+ from time import time
15
+ from typing import Any
16
+ from unittest import TestCase as PythonTestCase, mock, skip, skipUnless, SkipTest, skipIf
17
+ from unittest.util import _common_shorten_repr
18
+ from warnings import warn
19
+
20
+ from everysk.config import settings
21
+ from everysk.core.object import BaseDict
22
+
23
+
24
+ ###############################################################################
25
+ # TestCase Class Implementation
26
+ ###############################################################################
27
+ class TestCase(PythonTestCase):
28
+
29
+ def _callTestMethod(self, method: callable) -> None:
30
+ # For some tests the time could not pass 1 second, gzip tests for example.
31
+ # So we use mock to fix the time for the tests.
32
+ original_time = time()
33
+ with mock.patch('time.time', return_value=original_time):
34
+ # We could not use super here because the stacklevel would be wrong
35
+ if method() is not None:
36
+ warn(
37
+ f'It is deprecated to return a value that is not None from a test case ({method})',
38
+ DeprecationWarning,
39
+ stacklevel=3
40
+ )
41
+
42
+ def assertDictEqual(self, d1: dict | BaseDict, d2: dict | BaseDict, msg: str = None):
43
+ # pylint: disable=protected-access
44
+ self.assertIsInstance(d1, (dict, BaseDict), 'First argument is not a dictionary')
45
+ self.assertIsInstance(d2, (dict, BaseDict), 'Second argument is not a dictionary')
46
+
47
+ # We need to ensure that both objects are of the same type to proceed
48
+ if isinstance(d1, dict) and isinstance(d2, BaseDict):
49
+ d1 = type(d2)(**d1)
50
+
51
+ elif isinstance(d2, dict) and isinstance(d1, BaseDict):
52
+ d2 = type(d1)(**d2)
53
+
54
+ if d1 != d2:
55
+ standardMsg = '%s != %s' % _common_shorten_repr(d1, d2) # pylint: disable=consider-using-f-string, invalid-name
56
+ diff = ('\n' + '\n'.join(difflib.ndiff(
57
+ pprint.pformat(d1).splitlines(),
58
+ pprint.pformat(d2).splitlines())))
59
+ standardMsg = self._truncateMessage(standardMsg, diff) # pylint: disable=invalid-name
60
+ self.fail(self._formatMessage(msg, standardMsg))
61
+
62
+
63
+ ###############################################################################
64
+ # EveryskMagicMock Class Implementation
65
+ ###############################################################################
66
+ class EveryskMagicMock(mock.MagicMock): # pylint: disable=too-many-ancestors
67
+
68
+ def __init__(self, *args: Any, **kw: Any) -> None:
69
+ super().__init__(*args, **kw)
70
+ # To avoid infinite recursion inside serialize.dumps we need to remove this method
71
+ delattr(self, settings.SERIALIZE_CONVERT_METHOD_NAME)
72
+
73
+ mock.MagicMock = EveryskMagicMock
@@ -0,0 +1,241 @@
1
+ ###############################################################################
2
+ #
3
+ # (C) Copyright 2023 EVERYSK TECHNOLOGIES
4
+ #
5
+ # This is an unpublished work containing confidential and proprietary
6
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
7
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
8
+ #
9
+ ###############################################################################
10
+ import traceback
11
+ from typing import Any
12
+ from uuid import uuid4
13
+
14
+ from google.api_core.exceptions import (
15
+ AlreadyExists,
16
+ DeadlineExceeded,
17
+ ServiceUnavailable,
18
+ TooManyRequests
19
+ )
20
+ from google.cloud.tasks_v2 import (
21
+ CloudTasksClient,
22
+ CreateTaskRequest,
23
+ HttpMethod,
24
+ PauseQueueRequest,
25
+ ResumeQueueRequest,
26
+ Task,
27
+ Queue
28
+ )
29
+ from google.protobuf import duration_pb2
30
+
31
+ from everysk.core.compress import compress, decompress
32
+ from everysk.config import settings
33
+ from everysk.core.fields import IntField, StrField
34
+ from everysk.core.log import Logger
35
+ from everysk.core.object import BaseObject
36
+ from everysk.core.string import import_from_string
37
+
38
+
39
+ log = Logger('everysk-workers')
40
+
41
+
42
+ ###############################################################################
43
+ # BaseGoogle Class Implementation
44
+ ###############################################################################
45
+ class BaseGoogle(BaseObject):
46
+ ## Private attributes
47
+ _gtask: CloudTasksClient = None
48
+
49
+ ## Public attributes
50
+ google_task_project = StrField(default=settings.EVERYSK_GOOGLE_CLOUD_PROJECT)
51
+ google_task_location = StrField(default=settings.EVERYSK_GOOGLE_CLOUD_LOCATION)
52
+ worker_id = StrField(required=True)
53
+
54
+ @property
55
+ def gtask(self) -> CloudTasksClient:
56
+ # pylint: disable=protected-access
57
+ if self.__class__._gtask is None:
58
+ self.__class__._gtask = CloudTasksClient()
59
+
60
+ return self.__class__._gtask
61
+
62
+
63
+ ###############################################################################
64
+ # TaskGoogle Class Implementation
65
+ ###############################################################################
66
+ class TaskGoogle(BaseGoogle):
67
+ ## Public attributes
68
+ google_task_name = StrField() # Must be a unique name if None is used, auto create this
69
+ timeout = IntField(default=600, min_size=15, max_size=1800) # https://cloud.google.com/tasks/docs/reference/rest/v2/projects.locations.queues.tasks
70
+ worker_url = StrField(required=True)
71
+
72
+ ## Private methods
73
+ def __init__(self, **kwargs) -> None:
74
+ super().__init__(**kwargs)
75
+ # This facilitate to init it over pickle
76
+ self._received_kwargs = kwargs
77
+ if self.google_task_name is None:
78
+ self.google_task_name = f'{self.__class__.__name__}-{uuid4()}'
79
+
80
+ ## GTask methods
81
+ def gtask_queue_path(self) -> str:
82
+ return self.gtask.queue_path(
83
+ project=self.google_task_project,
84
+ location=self.google_task_location,
85
+ queue=self.worker_id
86
+ )
87
+
88
+ def gtask_task_path(self) -> str:
89
+ return self.gtask.task_path(
90
+ project=self.google_task_project,
91
+ location=self.google_task_location,
92
+ queue=self.worker_id,
93
+ task=self.google_task_name
94
+ )
95
+
96
+ def gtask_create_task_request(self, body: dict) -> CreateTaskRequest:
97
+ # https://cloud.google.com/tasks/docs/creating-http-target-tasks#createtask_method
98
+ if self.timeout is not None:
99
+ deadline = duration_pb2.Duration() # pylint: disable=no-member
100
+ deadline.FromSeconds(self.timeout)
101
+
102
+ task = {
103
+ 'name': self.gtask_task_path(),
104
+ 'dispatch_deadline': deadline,
105
+ 'http_request': {
106
+ 'http_method': HttpMethod.POST,
107
+ 'url': f'{self.worker_url}/worker/{self.worker_id}',
108
+ 'headers': self.get_headers(),
109
+ 'body': compress(body, serialize='pickle')
110
+ }
111
+ }
112
+ return CreateTaskRequest(parent=self.gtask_queue_path(), task=task)
113
+
114
+ ## Public methods
115
+ def get_headers(self) -> dict:
116
+ """
117
+ Return the headers that must be used to receive the task.
118
+ Remember that body must be always a byte object, then on child
119
+ classes do like de example bellow.
120
+
121
+ Example:
122
+ >>> def get_headers(self) -> dict:
123
+ ... headers = super().get_headers()
124
+ ... headers['new_header'] = 'bla bla'
125
+ ... return headers
126
+ """
127
+ return {'Content-type': 'application/octet-stream'}
128
+
129
+ def run(self) -> str:
130
+ """ This must return a str object to be used on worker logs """
131
+ pass
132
+
133
+ def send_start(self) -> Queue:
134
+ resume_queue_request = ResumeQueueRequest(name=self.gtask_queue_path())
135
+ return self.gtask.resume_queue(request=resume_queue_request)
136
+
137
+ def send_pause(self) -> Queue:
138
+ pause_queue_request = PauseQueueRequest(name=self.gtask_queue_path())
139
+ return self.gtask.pause_queue(request=pause_queue_request)
140
+
141
+ def save(self, timeout: float = 30.0, retry_times: int = 0) -> Task:
142
+ """
143
+ Saves this task on Google Cloud Tasks to be executed.
144
+ We will only retry if the Task Error is in (DeadlineExceeded, ServiceUnavailable, TooManyRequests).
145
+ Be careful, if the task name is random retry could duplicate the task.
146
+ # https://everysk.atlassian.net/browse/COD-1546
147
+
148
+ Args:
149
+ timeout (float, optional): Time to wait until the task is done. Defaults to 30.0.
150
+ retry_times (int, optional): Retry times if the task fails. Defaults to 0.
151
+ """
152
+ # Timeout could not be greater than 30 seconds
153
+ timeout = min(timeout, 30.0)
154
+
155
+ body = {'cls': self.get_full_doted_class_path(), 'kwargs': self._received_kwargs}
156
+ task = None
157
+ try:
158
+ task = self.gtask.create_task(request=self.gtask_create_task_request(body), timeout=timeout)
159
+
160
+ except AlreadyExists:
161
+ log.debug('Google task already exists: %s', self.gtask_task_path())
162
+
163
+ except (DeadlineExceeded, ServiceUnavailable, TooManyRequests) as error:
164
+ if retry_times > 0:
165
+ retry_times = retry_times - 1
166
+ task = self.save(timeout=timeout, retry_times=retry_times)
167
+ else:
168
+ raise error
169
+
170
+ return task
171
+
172
+
173
+ ###############################################################################
174
+ # WorkerGoogle Class Implementation
175
+ ###############################################################################
176
+ class WorkerGoogle(BaseGoogle):
177
+ """
178
+ Example:
179
+ from flask import Flask, request
180
+ from everysk.core.fields import StrField
181
+ from everysk.core.workers import WorkerGoogle
182
+
183
+ WORKER_ID = 'worker-id'
184
+
185
+ class FirestoreSaveWorker(WorkerGoogle):
186
+ google_task_location: StrField(default='location', readonly=True)
187
+ google_task_project: StrField(default='project', readonly=True)
188
+ worker_id: StrField(default=WORKER_ID, readonly=True)
189
+
190
+ ## Flask app
191
+ app = Flask(__name__)
192
+
193
+ @app.route(f'/worker/{WORKER_ID}', methods=['POST'])
194
+ def firestore_save():
195
+ return FirestoreSaveWorker.worker_run(
196
+ headers=request.headers,
197
+ data=request.data
198
+ )
199
+
200
+ ## Main run function
201
+ if __name__ == "__main__":
202
+ app.run(host=settings.FLASK_HOST, port=settings.FLASK_PORT, debug=settings.DEBUG)
203
+ """
204
+
205
+ ## Public methods
206
+ def check_google_task(self, headers: dict) -> bool:
207
+ """ Check Google Task readers to ensure that the request come from then. """
208
+ queue_name = headers.get('X-Cloudtasks-Queuename', None)
209
+ user_agent = headers.get('User-Agent', None)
210
+ return queue_name == self.worker_id and user_agent == 'Google-Cloud-Tasks'
211
+
212
+ def run_task(self, cls: str, kwargs: dict) -> Any:
213
+ """
214
+ Run the task, if pause is activated from the Tread, stops
215
+ until the self.worker_start message arrives.
216
+ """
217
+ cls = import_from_string(cls)
218
+ task = cls(**kwargs)
219
+ return task.run()
220
+
221
+ @classmethod
222
+ def worker_run(cls, headers: dict, data: bytes, worker_id: str = None) -> None:
223
+ if worker_id is None:
224
+ worker = cls()
225
+ else:
226
+ worker = cls(worker_id=worker_id)
227
+
228
+ if not worker.check_google_task(headers):
229
+ message = {'error': True, 'message': f"Couldn't validate Google headers - {headers}"}
230
+ log.error(message['message'])
231
+ return message
232
+
233
+ try:
234
+ post_data = decompress(data, serialize='pickle')
235
+ result = worker.run_task(**post_data)
236
+ return {'error': False, 'result': result}
237
+
238
+ except Exception as error: #pylint: disable=broad-exception-caught
239
+ message = f'Worker {cls.worker_id} error: {str(error)}'
240
+ log.error('Worker %s error: %s', cls.worker_id, traceback.format_exc())
241
+ return {'error': True, 'message': message}
@@ -0,0 +1,23 @@
1
+ ###############################################################################
2
+ #
3
+ # (C) Copyright 2025 EVERYSK TECHNOLOGIES
4
+ #
5
+ # This is an unpublished work containing confidential and proprietary
6
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
7
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
8
+ #
9
+ ###############################################################################
10
+ from everysk.core.string import import_from_string
11
+
12
+
13
+ ###############################################################################
14
+ # Private Functions Implementation
15
+ ###############################################################################
16
+ def __getattr__(_name: str):
17
+ from everysk.config import settings # pylint: disable=import-outside-toplevel
18
+ modules = settings.EVERYSK_SDK_MODULES_PATH
19
+
20
+ if _name in modules:
21
+ return import_from_string(modules[_name])
22
+
23
+ raise AttributeError(f"cannot import name '{_name}' from everysk.sdk")
everysk/sdk/base.py ADDED
@@ -0,0 +1,98 @@
1
+ ###############################################################################
2
+ #
3
+ # (C) Copyright 2023 EVERYSK TECHNOLOGIES
4
+ #
5
+ # This is an unpublished work containing confidential and proprietary
6
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
7
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
8
+ #
9
+ ###############################################################################
10
+ import inspect
11
+ from typing import Any
12
+
13
+ from everysk.core.exceptions import HttpError, SDKError
14
+ from everysk.core.http import HttpSDKPOSTConnection, httpx
15
+ from everysk.core.object import BaseDict, BaseObject
16
+ from everysk.core.string import import_from_string
17
+
18
+
19
+ ###############################################################################
20
+ # Public Functions Implementation
21
+ ###############################################################################
22
+ def handler_input_args(input_args: Any) -> Any:
23
+ """
24
+ This function handles the input arguments and returns the dictionary.
25
+
26
+ Args:
27
+ input_args (Any): The input arguments to be handled.
28
+
29
+ Returns:
30
+ Any: The parsed object.
31
+ """
32
+ ret: Any = input_args
33
+ if isinstance(input_args, dict):
34
+ ret = BaseDict()
35
+ for key, value in input_args.items():
36
+ ret[key] = handler_input_args(value)
37
+
38
+ elif isinstance(input_args, list):
39
+ ret = type(input_args)()
40
+ for item in input_args:
41
+ ret.append(handler_input_args(item))
42
+
43
+ return ret
44
+
45
+
46
+ ###############################################################################
47
+ # BaseSDK Class Implementation
48
+ ###############################################################################
49
+ class BaseSDK(BaseObject):
50
+ """
51
+ A base class for SDK classes.
52
+
53
+ This class provides a base implementation for SDK classes.
54
+ """
55
+
56
+ @classmethod
57
+ def get_response(cls, **kwargs: dict) -> Any:
58
+ """
59
+ Get a response from an SDK method.
60
+
61
+ This method sends an HTTP POST request to a remote service and returns the response as a dictionary.
62
+
63
+ Args:
64
+ **kwargs (dict): Keyword arguments used to configure the HTTP request and SDK behavior.
65
+
66
+ Keyword Args:
67
+ class_name (str, optional): The name of the SDK class making the request. Defaults to the class name of the calling class.
68
+ method_name (str, optional): The name of the SDK method making the request. Defaults to the name of the calling function.
69
+ self_obj (object, optional): An instance of the calling SDK class, if applicable. Defaults to None.
70
+ params (dict, optional): Additional parameters to include in the HTTP request. Defaults to an empty dictionary.
71
+
72
+ Returns:
73
+ Any: The response from the remote service.
74
+
75
+ Raises:
76
+ SDKError: If there is an issue with the SDK operation.
77
+ """
78
+ # Set default values for keyword arguments if not provided
79
+ kwargs.setdefault('class_name', cls.__name__)
80
+ kwargs.setdefault('method_name', inspect.stack()[1].function)
81
+ kwargs.setdefault('self_obj', None)
82
+ kwargs.setdefault('params', {})
83
+
84
+ try:
85
+ response: httpx.Response = HttpSDKPOSTConnection(**kwargs).get_response_decode()
86
+ except HttpError as error:
87
+ raise SDKError(error.msg) from error
88
+
89
+ if (
90
+ response
91
+ and isinstance(response, (dict, BaseDict))
92
+ and 'error_message' in response
93
+ and 'error_module' in response
94
+ ):
95
+ error_module = import_from_string(response['error_module'])
96
+ raise error_module(response['error_message'])
97
+
98
+ return response