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
everysk/sql/model.py ADDED
@@ -0,0 +1,376 @@
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
+ import inspect
11
+ from copy import deepcopy
12
+ from types import GenericAlias, UnionType
13
+ from typing import Any, Generic, Literal, Self, TypeVar, Union, get_args, get_origin
14
+
15
+ from everysk.core.datetime import Date, DateTime
16
+ from everysk.sql.connection import execute
17
+ from everysk.sql.query import Query
18
+
19
+ FT = TypeVar('FT')
20
+ MT = TypeVar('MT', bound='BaseModel')
21
+
22
+
23
+ class BaseModelMetaClass(type):
24
+ # Method called when a class is created in the Python runtime
25
+ def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> MT:
26
+ # Attributes that are inside annotations -> var: str or var: str = 'value'
27
+ # Attributes that are not inside annotations -> var = 'value'
28
+ # We need to get both
29
+ for key in attrs['__annotations__'].keys() | attrs.keys():
30
+ # Discard internal attributes
31
+ if not key.startswith('__'):
32
+ default_value = attrs.get(key)
33
+ if not inspect.isroutine(default_value) and not isinstance(default_value, (property, BaseModelField)):
34
+ # If the attribute is not inside annotations (var = 'value'), we add it
35
+ if key not in attrs['__annotations__']:
36
+ attrs['__annotations__'][key] = type(default_value)
37
+
38
+ # Get the type from the annotations
39
+ field_type = attrs['__annotations__'].get(key)
40
+ # Change the attribute to a BaseModelField descriptor
41
+ attrs[key] = BaseModelField(default=default_value, field_type=field_type)
42
+
43
+ obj: BaseModel = super().__new__(cls, name, bases, attrs)
44
+ obj._generate_attributes() # noqa: SLF001
45
+ obj._generate_fields() # noqa: SLF001
46
+ obj._generate_query() # noqa: SLF001
47
+ return obj
48
+
49
+ def __setattr__(cls: 'BaseModel', name: str, value: Any) -> None:
50
+ # Internal attributes are set normally
51
+ # They are __attributes__, __fields__, __query__
52
+ if name.startswith('__'):
53
+ return super().__setattr__(name, value)
54
+
55
+ if name in cls.__attributes__:
56
+ # Get the type that was already defined to validate the value
57
+ field_type = cls.__attributes__[name].field_type
58
+ else:
59
+ # If the attribute is not defined, we add it
60
+ field_type = type(value)
61
+ cls.__annotations__[name] = field_type
62
+ cls.__attributes__[name] = field_type
63
+ if not name.startswith('_'):
64
+ cls.__fields__[name] = field_type
65
+
66
+ # Change the attribute to a BaseModelField descriptor
67
+ value = BaseModelField(default=value, field_type=field_type, field_name=name)
68
+ return super().__setattr__(name, value)
69
+
70
+ def __delattr__(cls: 'BaseModel', name: str) -> None:
71
+ if name in cls.__attributes__:
72
+ del cls.__attributes__[name]
73
+
74
+ if name in cls.__fields__:
75
+ del cls.__fields__[name]
76
+
77
+ if name in cls.__annotations__:
78
+ del cls.__annotations__[name]
79
+
80
+ return super().__delattr__(name)
81
+
82
+
83
+ class BaseModelField(Generic[FT]):
84
+ # https://docs.python.org/3.12/howto/descriptor.html
85
+ default: FT | None
86
+ field_name: str
87
+ field_type: FT
88
+
89
+ def __init__(self, default: FT | None = None, *, field_type: FT, field_name: str | None = None) -> None:
90
+ if isinstance(field_type, GenericAlias):
91
+ # We need to get the origin of the generic type
92
+ field_type = get_origin(field_type)
93
+ # TypeError: typing.Union cannot be used with isinstance()
94
+ # The correct class of Unions is types.UnionType
95
+ elif isinstance(field_type, UnionType):
96
+ # We need to find if there are GenericAlias inside the Union
97
+ types = []
98
+ for _type in get_args(field_type):
99
+ if isinstance(_type, GenericAlias):
100
+ _type = get_origin(_type)
101
+ # We discard NoneType from the Union because it's normally used as optional
102
+ # This check is here because None is always the last type in the Union
103
+ if _type is type(None):
104
+ continue
105
+ types.append(_type)
106
+
107
+ # If there is only one type, we use it directly
108
+ if len(types) == 1:
109
+ field_type = types[0]
110
+ else:
111
+ field_type = Union[tuple(types)] # noqa: UP007
112
+
113
+ self.field_type = field_type
114
+ self.field_name = field_name
115
+ # We always validate the default value
116
+ if default is not None:
117
+ self.validate(default)
118
+
119
+ self.default = default
120
+
121
+ def __delete__(self, obj: 'BaseModel') -> None:
122
+ if self.field_name in obj:
123
+ del obj[self.field_name]
124
+
125
+ def __get__(self, obj: 'BaseModel', cls: type) -> FT:
126
+ # First we get the value from the dict, if not present we get the value from the default
127
+ if obj is None:
128
+ return self.default
129
+
130
+ return obj.get(self.field_name, self.default)
131
+
132
+ def __set__(self, obj: 'BaseModel', value: FT) -> None:
133
+ value = self.clean_value(value)
134
+
135
+ if obj._validate_fields: # noqa: SLF001
136
+ self.validate(value)
137
+
138
+ obj[self.field_name] = value
139
+
140
+ def __set_name__(self, cls: type, name: str) -> None:
141
+ self.field_name = name
142
+
143
+ ## Validation methods
144
+ def clean_value(self, value: object) -> object:
145
+ # The database value is datetime or date, we need to convert it to DateTime or Date
146
+ # Or we could store it as ISO format string and convert it back
147
+ if value:
148
+ # The result from the database could be a string, datetime or date
149
+ # We need to convert it to DateTime or Date
150
+ if self.field_type in (DateTime, Date):
151
+ if isinstance(value, str):
152
+ return self.field_type.fromisoformat(value)
153
+
154
+ return self.field_type.ensure(value)
155
+
156
+ # For sets and tuples, we save them as JSONB in the database that is a list
157
+ # when we get it back, we need to convert it to set or tuple
158
+ if self.field_type in (set, tuple):
159
+ return self.field_type(value)
160
+
161
+ return value
162
+
163
+ def _validate_instance(self, value: object) -> None:
164
+ if value and not isinstance(value, self.field_type):
165
+ name = self.field_name
166
+ type_name = self.field_type.__qualname__
167
+ received_name = type(value).__qualname__
168
+ msg = f'Field {name} must be of type {type_name}, got {received_name}.'
169
+ raise TypeError(msg)
170
+
171
+ def validate(self, value: object) -> None:
172
+ validate_func = getattr(self, f'_validate_{self.field_name}', self._validate_instance)
173
+ validate_func(value=value)
174
+
175
+
176
+ class BaseModel(dict, metaclass=BaseModelMetaClass):
177
+ # https://docs.python.org/3/reference/datamodel.html#slots
178
+ # These are class attributes that are not in the __dict__
179
+ __slots__ = ('__attributes__', '__dict__', '__fields__', '__query__')
180
+
181
+ ## Private attributes
182
+ _dsn: str = None
183
+ _primary_key: str = None
184
+ _schema: str = None
185
+ _table_name: str = None
186
+ _validate_fields: bool = True
187
+
188
+ ## Public attributes
189
+ # All public attributes are table fields and keys of the dict
190
+ created_on: DateTime = None
191
+ updated_on: DateTime = None
192
+
193
+ ## Internal methods
194
+ def __init__(self, *, validate_fields: bool | None = None, **kwargs) -> None:
195
+ # If validate_fields is None, we use the class attribute
196
+ if validate_fields is not None:
197
+ self._validate_fields = validate_fields
198
+
199
+ if self._validate_fields:
200
+ for key, value in kwargs.items():
201
+ self._validate(key, value)
202
+
203
+ # Set created_on if not provided
204
+ if 'created_on' not in kwargs:
205
+ kwargs['created_on'] = DateTime.now()
206
+
207
+ # We need to set all fields to None to complete the dict keys
208
+ fields = self._get_field_values(init_values=kwargs)
209
+ super().__init__(**fields)
210
+
211
+ def __repr__(self) -> str:
212
+ return self.__str__()
213
+
214
+ def __setitem__(self, key: str, value: Any) -> None:
215
+ if self._validate_fields:
216
+ self._validate(key, value)
217
+
218
+ return super().__setitem__(key, value)
219
+
220
+ def __str__(self) -> str:
221
+ # Use the class name and primary key for string representation
222
+ class_name = type(self).__name__
223
+ if self._primary_key is not None:
224
+ pk = getattr(self, self._primary_key, None)
225
+ if pk is not None:
226
+ return f'{class_name}({self._primary_key}={pk})'
227
+
228
+ return f'{class_name}()'
229
+
230
+ ## Private methods
231
+ def _get_field_values(self, *, init_values: dict[str, Any] | None = None) -> dict[str, Any]:
232
+ if init_values is None:
233
+ init_values = {}
234
+
235
+ # Get only fields that are not already in init_values
236
+ cls = type(self)
237
+ fields = cls._get_fields() - init_values.keys()
238
+ for field in fields:
239
+ value = getattr(self, field, None)
240
+ init_values[field] = value
241
+
242
+ return init_values
243
+
244
+ def _validate(self, key: str, value: Any) -> None:
245
+ if key in self._get_attributes():
246
+ field = self._get_attributes()[key]
247
+ value = field.clean_value(value)
248
+ field.validate(value)
249
+ else:
250
+ msg = f'Field {key} is not defined in {type(self).__name__}.'
251
+ raise KeyError(msg)
252
+
253
+ ## Class methods
254
+ @classmethod
255
+ def _execute(
256
+ cls,
257
+ query: str,
258
+ params: dict | None = None,
259
+ return_type: Literal['dict', 'list'] = 'list',
260
+ klass: type | None = None,
261
+ ) -> Any:
262
+ kwargs = {'query': query, 'params': params, 'return_type': return_type, 'dsn': cls._dsn, 'cls': klass}
263
+ return execute(**kwargs)
264
+
265
+ @classmethod
266
+ def _generate_attributes(cls) -> None:
267
+ cls.__attributes__ = {}
268
+ # We need to get all attributes from the class and its bases
269
+ # We stop at BaseModel (inclusive)
270
+ for base in cls.mro()[:-2]:
271
+ # Annotations are all attributes that are defined in the class
272
+ # In the __dict__ is the correct Field descriptor for each attribute
273
+ if base.__attributes__:
274
+ cls.__attributes__.update(base.__attributes__)
275
+ # If the base has the attributes, we don't need to get the others
276
+ break
277
+ # If we don't have the attributes in the base, we make then
278
+ keys = base.__annotations__.keys()
279
+ cls.__attributes__.update({key: base.__dict__[key] for key in keys})
280
+
281
+ @classmethod
282
+ def _generate_fields(cls) -> None:
283
+ # Fields are all attributes except those starting with _
284
+ cls.__fields__ = {
285
+ key: field.field_type for key, field in cls._get_attributes().items() if not key.startswith('_')
286
+ }
287
+
288
+ @classmethod
289
+ def _generate_query(cls) -> None:
290
+ cls.__query__ = Query(table_name=cls._table_name, primary_key=cls._primary_key, schema=cls._schema)
291
+
292
+ @classmethod
293
+ def _get_attributes(cls) -> dict[str, BaseModelField]:
294
+ if cls.__attributes__ is None:
295
+ cls._generate_attributes()
296
+
297
+ return cls.__attributes__
298
+
299
+ @classmethod
300
+ def _get_fields(cls) -> dict[str, type]:
301
+ if cls.__fields__ is None:
302
+ cls._generate_fields()
303
+
304
+ return cls.__fields__
305
+
306
+ @classmethod
307
+ def _get_query(cls) -> Query:
308
+ if cls.__query__ is None:
309
+ cls._generate_query()
310
+
311
+ return cls.__query__
312
+
313
+ @classmethod
314
+ def create_table(cls) -> None:
315
+ # First we create the table if it doesn't exist
316
+ sql = cls._get_query().parse_create_table(fields=cls._get_fields())
317
+ cls._execute(query=sql)
318
+ # Then we create the index on the primary key if it doesn't exist
319
+ sql = cls._get_query().parse_index(fields=cls._primary_key)
320
+ cls._execute(query=sql)
321
+
322
+ @classmethod
323
+ def loads(
324
+ cls,
325
+ fields: list | None = None,
326
+ order_by: str | None = None,
327
+ limit: int | None = None,
328
+ return_type: Literal['dict', 'list'] = 'list',
329
+ **conditions: dict,
330
+ ) -> list[Self] | dict[str, Self]:
331
+ if fields is None:
332
+ fields = set(cls._get_fields().keys())
333
+ sql, params = cls._get_query().parse_select(
334
+ fields=fields, order_by=order_by, limit=limit, conditions=conditions
335
+ )
336
+ return cls._execute(query=sql, params=params, return_type=return_type, klass=cls)
337
+
338
+ ## Instance methods
339
+ def delete(self) -> None:
340
+ cls = type(self)
341
+ sql = cls._get_query().parse_delete()
342
+ cls._execute(query=sql, params={'ids': [getattr(self, self._primary_key)]})
343
+
344
+ def load(self) -> Self:
345
+ cls = type(self)
346
+ conditions = {f'{self._primary_key}__eq': getattr(self, self._primary_key)}
347
+ sql, params = cls._get_query().parse_select(fields=cls._get_fields(), limit=1, conditions=conditions)
348
+ results = cls._execute(query=sql, params=params)
349
+
350
+ if not results:
351
+ msg = f'{cls.__name__} with {self._primary_key}={getattr(self, self._primary_key)} not found.'
352
+ raise ValueError(msg)
353
+
354
+ self.update(results[0])
355
+ return self
356
+
357
+ def save(self) -> Self:
358
+ self.updated_on = DateTime.now()
359
+ cls = type(self)
360
+ sql = cls._get_query().parse_insert_or_update(fields=cls._get_fields())
361
+ # We need to change some values so they can be used as params
362
+ # To avoid modifying the current instance, we create a copy of it
363
+ # The deepcopy creates a new instance of the same class so we need to change it
364
+ # to dict avoiding validation and other checks
365
+ params = dict(deepcopy(self))
366
+ params = cls._get_query().parse_insert_or_update_params(params=params)
367
+ cls._execute(query=sql, params=params)
368
+ return self
369
+
370
+ def update(self, *args, **kwargs) -> None:
371
+ dct = dict(*args, **kwargs)
372
+ if self._validate_fields:
373
+ for key, value in dct.items():
374
+ self._validate(key, value)
375
+
376
+ super().update(dct)