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.
- everysk/__init__.py +30 -0
- everysk/_version.py +683 -0
- everysk/api/__init__.py +61 -0
- everysk/api/api_requestor.py +167 -0
- everysk/api/api_resources/__init__.py +23 -0
- everysk/api/api_resources/api_resource.py +371 -0
- everysk/api/api_resources/calculation.py +779 -0
- everysk/api/api_resources/custom_index.py +42 -0
- everysk/api/api_resources/datastore.py +81 -0
- everysk/api/api_resources/file.py +42 -0
- everysk/api/api_resources/market_data.py +223 -0
- everysk/api/api_resources/parser.py +66 -0
- everysk/api/api_resources/portfolio.py +43 -0
- everysk/api/api_resources/private_security.py +42 -0
- everysk/api/api_resources/report.py +65 -0
- everysk/api/api_resources/report_template.py +39 -0
- everysk/api/api_resources/tests.py +115 -0
- everysk/api/api_resources/worker_execution.py +64 -0
- everysk/api/api_resources/workflow.py +65 -0
- everysk/api/api_resources/workflow_execution.py +93 -0
- everysk/api/api_resources/workspace.py +42 -0
- everysk/api/http_client.py +63 -0
- everysk/api/tests.py +32 -0
- everysk/api/utils.py +262 -0
- everysk/config.py +451 -0
- everysk/core/_tests/serialize/test_json.py +336 -0
- everysk/core/_tests/serialize/test_orjson.py +295 -0
- everysk/core/_tests/serialize/test_pickle.py +48 -0
- everysk/core/cloud_function/main.py +78 -0
- everysk/core/cloud_function/tests.py +86 -0
- everysk/core/compress.py +245 -0
- everysk/core/datetime/__init__.py +12 -0
- everysk/core/datetime/calendar.py +144 -0
- everysk/core/datetime/date.py +424 -0
- everysk/core/datetime/date_expression.py +299 -0
- everysk/core/datetime/date_mixin.py +1475 -0
- everysk/core/datetime/date_settings.py +30 -0
- everysk/core/datetime/datetime.py +713 -0
- everysk/core/exceptions.py +435 -0
- everysk/core/fields.py +1176 -0
- everysk/core/firestore.py +555 -0
- everysk/core/fixtures/_settings.py +29 -0
- everysk/core/fixtures/other/_settings.py +18 -0
- everysk/core/fixtures/user_agents.json +88 -0
- everysk/core/http.py +691 -0
- everysk/core/lists.py +92 -0
- everysk/core/log.py +709 -0
- everysk/core/number.py +37 -0
- everysk/core/object.py +1469 -0
- everysk/core/redis.py +1021 -0
- everysk/core/retry.py +51 -0
- everysk/core/serialize.py +674 -0
- everysk/core/sftp.py +414 -0
- everysk/core/signing.py +53 -0
- everysk/core/slack.py +127 -0
- everysk/core/string.py +199 -0
- everysk/core/tests.py +240 -0
- everysk/core/threads.py +199 -0
- everysk/core/undefined.py +70 -0
- everysk/core/unittests.py +73 -0
- everysk/core/workers.py +241 -0
- everysk/sdk/__init__.py +23 -0
- everysk/sdk/base.py +98 -0
- everysk/sdk/brutils/cnpj.py +391 -0
- everysk/sdk/brutils/cnpj_pd.py +129 -0
- everysk/sdk/engines/__init__.py +26 -0
- everysk/sdk/engines/cache.py +185 -0
- everysk/sdk/engines/compliance.py +37 -0
- everysk/sdk/engines/cryptography.py +69 -0
- everysk/sdk/engines/expression.cp312-win_amd64.pyd +0 -0
- everysk/sdk/engines/expression.pyi +55 -0
- everysk/sdk/engines/helpers.cp312-win_amd64.pyd +0 -0
- everysk/sdk/engines/helpers.pyi +26 -0
- everysk/sdk/engines/lock.py +120 -0
- everysk/sdk/engines/market_data.py +244 -0
- everysk/sdk/engines/settings.py +19 -0
- everysk/sdk/entities/__init__.py +23 -0
- everysk/sdk/entities/base.py +784 -0
- everysk/sdk/entities/base_list.py +131 -0
- everysk/sdk/entities/custom_index/base.py +209 -0
- everysk/sdk/entities/custom_index/settings.py +29 -0
- everysk/sdk/entities/datastore/base.py +160 -0
- everysk/sdk/entities/datastore/settings.py +17 -0
- everysk/sdk/entities/fields.py +375 -0
- everysk/sdk/entities/file/base.py +215 -0
- everysk/sdk/entities/file/settings.py +63 -0
- everysk/sdk/entities/portfolio/base.py +248 -0
- everysk/sdk/entities/portfolio/securities.py +241 -0
- everysk/sdk/entities/portfolio/security.py +580 -0
- everysk/sdk/entities/portfolio/settings.py +97 -0
- everysk/sdk/entities/private_security/base.py +226 -0
- everysk/sdk/entities/private_security/settings.py +17 -0
- everysk/sdk/entities/query.py +603 -0
- everysk/sdk/entities/report/base.py +214 -0
- everysk/sdk/entities/report/settings.py +23 -0
- everysk/sdk/entities/script.py +310 -0
- everysk/sdk/entities/secrets/base.py +128 -0
- everysk/sdk/entities/secrets/script.py +119 -0
- everysk/sdk/entities/secrets/settings.py +17 -0
- everysk/sdk/entities/settings.py +48 -0
- everysk/sdk/entities/tags.py +174 -0
- everysk/sdk/entities/worker_execution/base.py +307 -0
- everysk/sdk/entities/worker_execution/settings.py +63 -0
- everysk/sdk/entities/workflow_execution/base.py +113 -0
- everysk/sdk/entities/workflow_execution/settings.py +32 -0
- everysk/sdk/entities/workspace/base.py +99 -0
- everysk/sdk/entities/workspace/settings.py +27 -0
- everysk/sdk/settings.py +67 -0
- everysk/sdk/tests.py +105 -0
- everysk/sdk/worker_base.py +47 -0
- everysk/server/__init__.py +9 -0
- everysk/server/applications.py +63 -0
- everysk/server/endpoints.py +516 -0
- everysk/server/example_api.py +69 -0
- everysk/server/middlewares.py +80 -0
- everysk/server/requests.py +62 -0
- everysk/server/responses.py +119 -0
- everysk/server/routing.py +64 -0
- everysk/server/settings.py +36 -0
- everysk/server/tests.py +36 -0
- everysk/settings.py +98 -0
- everysk/sql/__init__.py +9 -0
- everysk/sql/connection.py +232 -0
- everysk/sql/model.py +376 -0
- everysk/sql/query.py +417 -0
- everysk/sql/row_factory.py +63 -0
- everysk/sql/settings.py +49 -0
- everysk/sql/utils.py +129 -0
- everysk/tests.py +23 -0
- everysk/utils.py +81 -0
- everysk/version.py +15 -0
- everysk_lib-1.10.2.dist-info/.gitignore +5 -0
- everysk_lib-1.10.2.dist-info/METADATA +326 -0
- everysk_lib-1.10.2.dist-info/RECORD +137 -0
- everysk_lib-1.10.2.dist-info/WHEEL +5 -0
- everysk_lib-1.10.2.dist-info/licenses/LICENSE.txt +9 -0
- everysk_lib-1.10.2.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,119 @@
|
|
|
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 base64
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from inspect import isclass
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import six
|
|
16
|
+
|
|
17
|
+
from everysk.config import settings
|
|
18
|
+
from everysk.core.exceptions import FieldValueError, WorkerError
|
|
19
|
+
from everysk.core.object import BaseDict
|
|
20
|
+
from everysk.core.string import import_from_string
|
|
21
|
+
from everysk.sdk.base import BaseSDK
|
|
22
|
+
from everysk.sdk.entities import File
|
|
23
|
+
from everysk.sdk.entities.base import QueryMetaClass
|
|
24
|
+
|
|
25
|
+
###############################################################################
|
|
26
|
+
# Class Implementation
|
|
27
|
+
###############################################################################
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SecretsScript(BaseDict, BaseSDK):
|
|
31
|
+
_klass: Callable = None
|
|
32
|
+
|
|
33
|
+
def __init__(self, _klass: Callable) -> None:
|
|
34
|
+
super().__init__(_klass=None)
|
|
35
|
+
|
|
36
|
+
if _klass is not None and not isclass(_klass):
|
|
37
|
+
try:
|
|
38
|
+
_klass = import_from_string(settings.EVERYSK_SDK_ENTITIES_MODULES_PATH[_klass])
|
|
39
|
+
except KeyError:
|
|
40
|
+
raise FieldValueError(
|
|
41
|
+
f"The _klass value '{_klass}' must be a class or a string with the class name."
|
|
42
|
+
) from KeyError
|
|
43
|
+
|
|
44
|
+
self._klass = _klass
|
|
45
|
+
|
|
46
|
+
def _process__klass(self, value: Any) -> Any:
|
|
47
|
+
"""
|
|
48
|
+
This method is used to process the '_klass' attribute.
|
|
49
|
+
"""
|
|
50
|
+
return value.__name__
|
|
51
|
+
|
|
52
|
+
def _from_base_64(self, file_data: str) -> str:
|
|
53
|
+
"""
|
|
54
|
+
Decodes the base 64 string data to normal sting.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
file_data (str or bytes): The input data to be decoded. This can be a string or bytes.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
str: The decoded version of the input data as a string.
|
|
61
|
+
"""
|
|
62
|
+
return six.ensure_str(base64.b64decode(six.ensure_str(file_data)))
|
|
63
|
+
|
|
64
|
+
def _get_secrets_from_file(self, query: str | BaseDict | list[str], variant: str, workspace: str) -> str:
|
|
65
|
+
secrets_file = File.script.fetch(query, variant, workspace)
|
|
66
|
+
|
|
67
|
+
if not secrets_file:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
return self._from_base_64(secrets_file.data)
|
|
71
|
+
|
|
72
|
+
def normalize(self, value: str | BaseDict | list[str], variant: str, workspace: str = None) -> str:
|
|
73
|
+
normalized_value: str = None
|
|
74
|
+
|
|
75
|
+
if variant == 'selectSecrets':
|
|
76
|
+
from everysk.sdk.entities import Secrets
|
|
77
|
+
|
|
78
|
+
normalized_value = Secrets.value_from_path(value)
|
|
79
|
+
|
|
80
|
+
elif variant in {'metaString', 'password'}:
|
|
81
|
+
normalized_value = value
|
|
82
|
+
|
|
83
|
+
elif variant in {'selectFile', 'tagLatest', 'linkLatest'}:
|
|
84
|
+
normalized_value = self._get_secrets_from_file(value, variant, workspace)
|
|
85
|
+
|
|
86
|
+
elif variant == 'previousWorkers':
|
|
87
|
+
if isinstance(value, str) and not File.validate_id(value):
|
|
88
|
+
normalized_value = value
|
|
89
|
+
|
|
90
|
+
else:
|
|
91
|
+
normalized_value = self._get_secrets_from_file(value, variant, workspace)
|
|
92
|
+
|
|
93
|
+
else:
|
|
94
|
+
raise WorkerError(f'Unsupported secrets variant `{variant}`')
|
|
95
|
+
|
|
96
|
+
return normalized_value
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class SecretsScriptMetaClass(QueryMetaClass):
|
|
100
|
+
"""
|
|
101
|
+
Metaclass for the Script class that allows for the script attribute to be accessed
|
|
102
|
+
directly from the entity class.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
To access the script attribute from the entity class:
|
|
106
|
+
>>> MyClass.script
|
|
107
|
+
Script()
|
|
108
|
+
|
|
109
|
+
Notes:
|
|
110
|
+
This metaclass overrides the __getatrribute__ method to enable direct access
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
def __getattribute__(cls, __name: str) -> Any:
|
|
114
|
+
"""
|
|
115
|
+
Get the script attribute from the entity class.
|
|
116
|
+
"""
|
|
117
|
+
if __name == 'script':
|
|
118
|
+
return SecretsScript(cls)
|
|
119
|
+
return super().__getattribute__(__name)
|
|
@@ -0,0 +1,17 @@
|
|
|
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 everysk.core.fields import IntField, RegexField, StrField
|
|
11
|
+
|
|
12
|
+
###############################################################################
|
|
13
|
+
# Settings Implementation
|
|
14
|
+
###############################################################################
|
|
15
|
+
SECRETS_ID_PREFIX = StrField(default='scrt_', readonly=True)
|
|
16
|
+
SECRETS_ID_REGEX = RegexField(default=r'^scrt_[a-zA-Z0-9]{25}', readonly=True)
|
|
17
|
+
SECRETS_ID_MAX_LENGTH = IntField(default=30, readonly=True) # len(SECRETS_ID_PREFIX) + ENTITY_ID_LENGTH
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
|
|
11
|
+
###############################################################################
|
|
12
|
+
# Imports
|
|
13
|
+
###############################################################################
|
|
14
|
+
from everysk.core.fields import IntField, StrField, SetField, ListField
|
|
15
|
+
|
|
16
|
+
###############################################################################
|
|
17
|
+
# Settings Implementation
|
|
18
|
+
###############################################################################
|
|
19
|
+
ENTITY_NAME_MAX_LENGTH = IntField(default=200, readonly=True)
|
|
20
|
+
ENTITY_NAME_MIN_LENGTH = IntField(default=1, readonly=True)
|
|
21
|
+
|
|
22
|
+
ENTITY_DESCRIPTION_MAX_LEN = IntField(default=500, readonly=True)
|
|
23
|
+
ENTITY_DESCRIPTION_MIN_LEN = IntField(default=0, readonly=True)
|
|
24
|
+
|
|
25
|
+
ENTITY_MAX_TAG_LENGTH = IntField(default=252, readonly=True)
|
|
26
|
+
ENTITY_MIN_TAG_LENGTH = IntField(default=1, readonly=True)
|
|
27
|
+
ENTITY_MAX_TAG_SIZE = IntField(default=32, readonly=True)
|
|
28
|
+
ENTITY_MIN_TAG_SIZE = IntField(default=0, readonly=True)
|
|
29
|
+
|
|
30
|
+
ENTITY_DEFAULT_VERSION = StrField(default='v1', readonly=True)
|
|
31
|
+
ENTITY_ID_LENGTH = IntField(default=25, readonly=True)
|
|
32
|
+
|
|
33
|
+
ENTITY_MAX_TAG_SIZE = IntField(default=32, readonly=True)
|
|
34
|
+
ENTITY_MIN_TAG_SIZE = IntField(default=0, readonly=True)
|
|
35
|
+
|
|
36
|
+
ENTITY_LINK_UID_MAX_LENGTH = IntField(default=128, readonly=True)
|
|
37
|
+
ENTITY_LINK_UID_MIN_LENGTH = IntField(default=1, readonly=True)
|
|
38
|
+
|
|
39
|
+
DEFAULT_QUERY_OFFSET = IntField(default=0, readonly=True)
|
|
40
|
+
DEFAULT_QUERY_PAGE_SIZE = IntField(default=20, readonly=True)
|
|
41
|
+
DEFAULT_QUERY_LIMIT = IntField(default=None)
|
|
42
|
+
|
|
43
|
+
ENTITY_RETRIEVE_BATCH_SIZE = IntField(default=1000, readonly=True)
|
|
44
|
+
|
|
45
|
+
QUERY_OPERATORS = SetField(default={'<=', '>=', '<', '>', '=', '!=', 'IN', 'NOT_IN'}, readonly=True)
|
|
46
|
+
|
|
47
|
+
ENTITY_BASE_CURRENCY_DEFAULT_LIST = SetField(default={'USD', 'EUR', 'GBP', 'JPY', 'CNY', 'AUD', 'CAD', 'CHF', 'CNH', 'HKD', 'NZD', 'BRL'}, readonly=True)
|
|
48
|
+
ENTITY_ALLOWED_QUERY_ATTRIBUTES_FOR_ALL_OPERATORS = ListField(default=['name', 'date', 'link_uid', 'created_on', 'updated_on'], readonly=True)
|
|
@@ -0,0 +1,174 @@
|
|
|
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 types import NoneType
|
|
11
|
+
from typing import Any, Self
|
|
12
|
+
from collections.abc import Iterable
|
|
13
|
+
|
|
14
|
+
from six import string_types
|
|
15
|
+
|
|
16
|
+
from everysk.config import settings
|
|
17
|
+
from everysk.core.datetime import DateTime, Date
|
|
18
|
+
from everysk.core.exceptions import FieldValueError
|
|
19
|
+
from everysk.core.number import is_float_convertible
|
|
20
|
+
from everysk.core.string import normalize_string, to_string
|
|
21
|
+
from everysk.sdk.entities.base_list import EntityList
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
###############################################################################
|
|
25
|
+
# Tags Class Implementation
|
|
26
|
+
###############################################################################
|
|
27
|
+
class Tags(EntityList):
|
|
28
|
+
"""
|
|
29
|
+
A specialized list for handling tags.
|
|
30
|
+
|
|
31
|
+
This class is a subclass of EntityList and provides specific validation for tags, including
|
|
32
|
+
size limits and pattern matching.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
min_size (int): The minimum allowed size for the list (default is 1).
|
|
36
|
+
max_size (int): The maximum allowed size for the list (default is the value from settings).
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
To create a Tags for handling tags:
|
|
40
|
+
tags = Tags()
|
|
41
|
+
"""
|
|
42
|
+
min_size: int = 1
|
|
43
|
+
max_size: int = settings.ENTITY_MAX_TAG_LENGTH
|
|
44
|
+
|
|
45
|
+
def __init__(self, *args):
|
|
46
|
+
"""
|
|
47
|
+
Initialize the Tags.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
*args: Optional initial elements to populate the list.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
To create an Tags with initial elements:
|
|
54
|
+
>>> my_list = Tags(['tag1', 'tag2', 'tag3'])
|
|
55
|
+
"""
|
|
56
|
+
if args:
|
|
57
|
+
try:
|
|
58
|
+
args = (list(dict.fromkeys(self.unify(args[0]))), )
|
|
59
|
+
except TypeError:
|
|
60
|
+
raise FieldValueError('Unsupported format in Tags.') from TypeError
|
|
61
|
+
super().__init__(*args)
|
|
62
|
+
|
|
63
|
+
def _validate(self, value: Any) -> str:
|
|
64
|
+
"""
|
|
65
|
+
Validate a tag value.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
value (str): The tag value to be validated.
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
FieldValueError: If the tag value is invalid based on the specified criteria.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
str: The validated tag value.
|
|
75
|
+
|
|
76
|
+
Criteria:
|
|
77
|
+
- The value must be a string.
|
|
78
|
+
- The value's length must be between min_size ({min_size}) and max_size ({max_size}).
|
|
79
|
+
- The value must consist of only lowercase letters, digits, and underscores.
|
|
80
|
+
- The value cannot be empty.
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
FieldValueError: If the tag value does not meet the specified criteria.
|
|
84
|
+
"""
|
|
85
|
+
if isinstance(value, list) or isinstance(value, dict):
|
|
86
|
+
raise FieldValueError(f'Unsupported format in Tags: {type(value)}')
|
|
87
|
+
elif value == '' or value is Undefined:
|
|
88
|
+
value = str(None)
|
|
89
|
+
elif is_float_convertible(value) or value.__class__ in [NoneType, bool]:
|
|
90
|
+
value = str(value)
|
|
91
|
+
elif value.__class__ in [DateTime, Date]:
|
|
92
|
+
value = value.strftime('%Y%m%d')
|
|
93
|
+
elif not isinstance(value, string_types):
|
|
94
|
+
raise FieldValueError(f'Unsupported format in Tags: {type(value)}')
|
|
95
|
+
|
|
96
|
+
value = to_string(''.join(x if x.isalnum() else '_' for x in normalize_string(value))).lower()
|
|
97
|
+
|
|
98
|
+
if (
|
|
99
|
+
self.min_size is not None and self.min_size > len(value) or
|
|
100
|
+
self.max_size is not None and self.max_size < len(value)
|
|
101
|
+
):
|
|
102
|
+
raise FieldValueError(f"Tags: '{value}' size it's not between {self.min_size} and {self.max_size}")
|
|
103
|
+
|
|
104
|
+
return value
|
|
105
|
+
|
|
106
|
+
def insert(self, __index: int, __object: Any) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Insert an object at a specified index if the object does not exist with validation.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
__index (int): The index at which to insert the object.
|
|
112
|
+
__object: The object to be inserted.
|
|
113
|
+
"""
|
|
114
|
+
__object = self._validate(__object)
|
|
115
|
+
if __object not in self:
|
|
116
|
+
super().insert(__index, __object)
|
|
117
|
+
|
|
118
|
+
def append(self, __object: Any) -> None:
|
|
119
|
+
"""
|
|
120
|
+
Append an object to the list if the object does not exist with validation.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
__object: The object to be appended.
|
|
124
|
+
"""
|
|
125
|
+
__object = self._validate(__object)
|
|
126
|
+
if __object not in self:
|
|
127
|
+
super().append(__object)
|
|
128
|
+
|
|
129
|
+
def extend(self, __iterable: Iterable) -> None:
|
|
130
|
+
"""
|
|
131
|
+
Extend the list with values from an iterable if the value does not exist with validation.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
__iterable (Iterable): An iterable containing values to be added to the list.
|
|
135
|
+
"""
|
|
136
|
+
order_values: dict = {}
|
|
137
|
+
for value in __iterable:
|
|
138
|
+
value: str = self._validate(value)
|
|
139
|
+
if value not in self:
|
|
140
|
+
order_values[value] = None
|
|
141
|
+
super().extend(list(order_values.keys()))
|
|
142
|
+
|
|
143
|
+
@classmethod
|
|
144
|
+
def unify(cls, tag_set: Any, reference_tags: list[Any] = None) -> Self:
|
|
145
|
+
"""
|
|
146
|
+
Unify a set of tags with a reference set of tags.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
tag_set (list): The set of tags to be unified.
|
|
150
|
+
reference_tags (list): The reference set of tags.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
list: The unified set of tags.
|
|
154
|
+
|
|
155
|
+
Example:
|
|
156
|
+
To unify a set of tags with a reference set of tags:
|
|
157
|
+
>>> unified_tags = Tags.unify_tags([['tag1', 'tag2'], ['tag3', 'tag4']], ['tag5', 'tag6'])
|
|
158
|
+
"""
|
|
159
|
+
unified_tags: Self = cls()
|
|
160
|
+
|
|
161
|
+
if not tag_set:
|
|
162
|
+
return unified_tags
|
|
163
|
+
elif isinstance(tag_set, (int, float)):
|
|
164
|
+
tag_set = [tag_set]
|
|
165
|
+
|
|
166
|
+
for tags in tag_set:
|
|
167
|
+
if tags is not False and not tags and reference_tags:
|
|
168
|
+
unified_tags.extend(reference_tags)
|
|
169
|
+
elif isinstance(tags, list):
|
|
170
|
+
unified_tags.extend(cls.unify(tags, reference_tags))
|
|
171
|
+
else:
|
|
172
|
+
unified_tags.append(tags)
|
|
173
|
+
|
|
174
|
+
return unified_tags
|
|
@@ -0,0 +1,307 @@
|
|
|
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 typing import Any, Self
|
|
11
|
+
|
|
12
|
+
from everysk.config import settings
|
|
13
|
+
from everysk.core.datetime import DateTime
|
|
14
|
+
from everysk.core.fields import BoolField, DateTimeField, DictField, FloatField, IntField, ListField, StrField
|
|
15
|
+
from everysk.core.object import BaseDict
|
|
16
|
+
from everysk.sdk.entities.base import BaseEntity
|
|
17
|
+
from everysk.sdk.entities.query import Query
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
###############################################################################
|
|
21
|
+
# Result Class Implementation
|
|
22
|
+
###############################################################################
|
|
23
|
+
class Result(BaseDict):
|
|
24
|
+
status = StrField(default='ERROR', choices=('OK', 'ERROR', 'UNKNOW'))
|
|
25
|
+
data: list | dict | None = None
|
|
26
|
+
log = ListField()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
###############################################################################
|
|
30
|
+
# ResultField Class Implementation
|
|
31
|
+
###############################################################################
|
|
32
|
+
class ResultField(DictField):
|
|
33
|
+
attr_type: Result | BaseDict | dict = Result | BaseDict | dict
|
|
34
|
+
|
|
35
|
+
def clean_value(self, value: Any) -> Result | None:
|
|
36
|
+
"""
|
|
37
|
+
This method cleans the value of the field.
|
|
38
|
+
|
|
39
|
+
Args:s
|
|
40
|
+
value (Any): The value to be cleaned.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Securities: The cleaned value.
|
|
44
|
+
"""
|
|
45
|
+
if isinstance(value, dict):
|
|
46
|
+
value = Result(**value)
|
|
47
|
+
|
|
48
|
+
return super().clean_value(value)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
###############################################################################
|
|
52
|
+
# ParallelInfo Class Implementation
|
|
53
|
+
###############################################################################
|
|
54
|
+
class ParallelInfo(BaseDict):
|
|
55
|
+
index = IntField(default=settings.WORKER_EXECUTION_UNFORKED_PARALLEL_INDEX, required_lazy=True)
|
|
56
|
+
length = IntField(default=settings.WORKER_EXECUTION_UNFORKED_PARALLEL_LENGTH, required_lazy=True)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
###############################################################################
|
|
60
|
+
# ParallelInfoField Class Implementation
|
|
61
|
+
###############################################################################
|
|
62
|
+
class ParallelInfoField(DictField):
|
|
63
|
+
attr_type: ParallelInfo | BaseDict | dict = ParallelInfo | BaseDict | dict
|
|
64
|
+
|
|
65
|
+
def __init__(
|
|
66
|
+
self,
|
|
67
|
+
default: Any = None,
|
|
68
|
+
*,
|
|
69
|
+
required: bool = False,
|
|
70
|
+
readonly: bool = False,
|
|
71
|
+
required_lazy: bool = True,
|
|
72
|
+
empty_is_none: bool = False,
|
|
73
|
+
**kwargs,
|
|
74
|
+
) -> None:
|
|
75
|
+
if default is None:
|
|
76
|
+
default = ParallelInfo()
|
|
77
|
+
super().__init__(
|
|
78
|
+
default=default,
|
|
79
|
+
required=required,
|
|
80
|
+
readonly=readonly,
|
|
81
|
+
required_lazy=required_lazy,
|
|
82
|
+
empty_is_none=empty_is_none,
|
|
83
|
+
**kwargs,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def clean_value(self, value: Any) -> Result | None:
|
|
87
|
+
"""
|
|
88
|
+
This method cleans the value of the field.
|
|
89
|
+
|
|
90
|
+
Args:s
|
|
91
|
+
value (Any): The value to be cleaned.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Securities: The cleaned value.
|
|
95
|
+
"""
|
|
96
|
+
if isinstance(value, (dict, BaseDict)):
|
|
97
|
+
value = ParallelInfo(**value)
|
|
98
|
+
|
|
99
|
+
return super().clean_value(value)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
###############################################################################
|
|
103
|
+
# InputParams Class Implementation
|
|
104
|
+
###############################################################################
|
|
105
|
+
class InputParams(BaseDict):
|
|
106
|
+
worker_id = StrField(empty_is_none=True)
|
|
107
|
+
workflow_id = StrField(regex=settings.WORKFLOW_ID_REGEX, empty_is_none=True)
|
|
108
|
+
|
|
109
|
+
worker_execution_id = StrField(regex=settings.WORKER_EXECUTION_ID_REGEX, empty_is_none=True)
|
|
110
|
+
workflow_execution_id = StrField(regex=settings.WORKFLOW_EXECUTION_ID_REGEX, empty_is_none=True)
|
|
111
|
+
|
|
112
|
+
workspace = StrField(empty_is_none=True)
|
|
113
|
+
worker_type = StrField(default=Undefined, choices=settings.WORKER_TEMPLATE_TYPES)
|
|
114
|
+
script_inputs = DictField()
|
|
115
|
+
inputs_info = DictField()
|
|
116
|
+
parallel_info = ParallelInfoField()
|
|
117
|
+
|
|
118
|
+
def to_dict(self, add_class_path: bool = False, recursion: bool = False) -> dict:
|
|
119
|
+
"""
|
|
120
|
+
This method is used to convert the object to a dictionary.
|
|
121
|
+
"""
|
|
122
|
+
dct: dict = super().to_dict(add_class_path=add_class_path, recursion=recursion)
|
|
123
|
+
|
|
124
|
+
if isinstance(dct['parallel_info'], ParallelInfo):
|
|
125
|
+
dct['parallel_info'] = dct['parallel_info'].to_dict(add_class_path=add_class_path, recursion=recursion)
|
|
126
|
+
|
|
127
|
+
return dct
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
###############################################################################
|
|
131
|
+
# InputParamsField Class Implementation
|
|
132
|
+
###############################################################################
|
|
133
|
+
class InputParamsField(DictField):
|
|
134
|
+
attr_type: InputParams | BaseDict | dict = InputParams | BaseDict | dict
|
|
135
|
+
|
|
136
|
+
def clean_value(self, value: Any) -> InputParams | None:
|
|
137
|
+
"""
|
|
138
|
+
This method cleans the value of the field.
|
|
139
|
+
|
|
140
|
+
Args:s
|
|
141
|
+
value (Any): The value to be cleaned.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Securities: The cleaned value.
|
|
145
|
+
"""
|
|
146
|
+
if isinstance(value, dict):
|
|
147
|
+
value = InputParams(**value)
|
|
148
|
+
|
|
149
|
+
return super().clean_value(value)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
###############################################################################
|
|
153
|
+
# WorkerExecution Class Implementation
|
|
154
|
+
###############################################################################
|
|
155
|
+
class WorkerExecution(BaseEntity):
|
|
156
|
+
id = StrField(regex=settings.WORKER_EXECUTION_ID_REGEX, required_lazy=True, empty_is_none=True)
|
|
157
|
+
|
|
158
|
+
result = ResultField()
|
|
159
|
+
storage = BoolField(default=False)
|
|
160
|
+
input_params = InputParamsField(required_lazy=True)
|
|
161
|
+
storage_input_params = BoolField(default=False)
|
|
162
|
+
|
|
163
|
+
parallel_info = ParallelInfoField()
|
|
164
|
+
status = StrField(default=settings.WORKER_EXECUTION_STATUS_PREPARING, choices=settings.WORKER_EXECUTION_STATUS_LIST)
|
|
165
|
+
execution_type = StrField(default=Undefined, choices=settings.WORKER_EXECUTION_TYPE_LIST, required_lazy=True)
|
|
166
|
+
start_time = DateTimeField()
|
|
167
|
+
end_time = DateTimeField()
|
|
168
|
+
duration = FloatField(default=0.0)
|
|
169
|
+
cpu_time = FloatField(default=0.0)
|
|
170
|
+
process_cpu_time = FloatField(default=0.0)
|
|
171
|
+
|
|
172
|
+
workflow_execution_id = StrField(regex=settings.WORKFLOW_EXECUTION_ID_REGEX, required_lazy=True, empty_is_none=True)
|
|
173
|
+
workflow_id = StrField(regex=settings.WORKFLOW_ID_REGEX, required_lazy=True, empty_is_none=True)
|
|
174
|
+
workflow_name = StrField(required_lazy=True, empty_is_none=True)
|
|
175
|
+
worker_id = StrField(regex=settings.WORKER_ID_REGEX, required_lazy=True, empty_is_none=True)
|
|
176
|
+
worker_name = StrField(required_lazy=True, empty_is_none=True)
|
|
177
|
+
worker_type = StrField(default=Undefined, choices=settings.WORKER_TEMPLATE_TYPES)
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def get_id_prefix() -> str:
|
|
181
|
+
"""
|
|
182
|
+
Returns the prefix of the Worker Execution id field value.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
str: The prefix of the Worker Execution id field value.
|
|
186
|
+
|
|
187
|
+
Usage:
|
|
188
|
+
>>> WorkerExecution.get_id_prefix()
|
|
189
|
+
'wkex_'
|
|
190
|
+
|
|
191
|
+
Notes:
|
|
192
|
+
The prefix is typically used to distinguish Worker Execution IDs from other types of IDs.
|
|
193
|
+
"""
|
|
194
|
+
return settings.WORKER_EXECUTION_ID_PREFIX
|
|
195
|
+
|
|
196
|
+
def generate_id(self) -> str:
|
|
197
|
+
"""
|
|
198
|
+
Generate a unique ID for an entity instance.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
str: The generated unique ID.
|
|
202
|
+
|
|
203
|
+
Example:
|
|
204
|
+
To generate a unique ID for an entity instance:
|
|
205
|
+
>>> unique_id = MyEntity().generate_id()
|
|
206
|
+
"""
|
|
207
|
+
raise NotImplementedError
|
|
208
|
+
|
|
209
|
+
def to_dict(self, add_class_path: bool = False, recursion: bool = False) -> dict:
|
|
210
|
+
"""
|
|
211
|
+
This method is used to convert the object to a dictionary.
|
|
212
|
+
"""
|
|
213
|
+
dct: dict = super().to_dict(add_class_path=add_class_path, recursion=recursion)
|
|
214
|
+
|
|
215
|
+
if isinstance(dct['parallel_info'], ParallelInfo):
|
|
216
|
+
dct['parallel_info'] = dct['parallel_info'].to_dict(add_class_path=add_class_path, recursion=recursion)
|
|
217
|
+
|
|
218
|
+
if isinstance(dct['result'], Result):
|
|
219
|
+
dct['result'] = dct['result'].to_dict(add_class_path=add_class_path, recursion=recursion)
|
|
220
|
+
|
|
221
|
+
if isinstance(dct['input_params'], InputParams):
|
|
222
|
+
dct['input_params'] = dct['input_params'].to_dict(add_class_path=add_class_path, recursion=recursion)
|
|
223
|
+
|
|
224
|
+
if add_class_path is False:
|
|
225
|
+
if self.duration is None:
|
|
226
|
+
now = DateTime.now()
|
|
227
|
+
start = self.start_time if self.start_time else now
|
|
228
|
+
end = self.end_time if self.end_time else now
|
|
229
|
+
dct['duration'] = (end - start).total_seconds()
|
|
230
|
+
|
|
231
|
+
dct['started'] = self.start_time.timestamp() if self.start_time else None
|
|
232
|
+
dct['trigger'] = self.execution_type
|
|
233
|
+
|
|
234
|
+
if dct['result'] is not None:
|
|
235
|
+
dct['result'] = dct.get('result', {}).get('data', None)
|
|
236
|
+
|
|
237
|
+
dct.pop('execution_type')
|
|
238
|
+
dct.pop('start_time')
|
|
239
|
+
dct.pop('end_time')
|
|
240
|
+
dct.pop('storage')
|
|
241
|
+
dct.pop('storage_input_params')
|
|
242
|
+
|
|
243
|
+
return dct
|
|
244
|
+
|
|
245
|
+
def _check_entity_to_query(self) -> bool:
|
|
246
|
+
"""
|
|
247
|
+
Check the entity object to query.
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
bool: True if the entity object is valid.
|
|
251
|
+
"""
|
|
252
|
+
return True
|
|
253
|
+
|
|
254
|
+
def _check_query(self, query: Query) -> bool:
|
|
255
|
+
"""
|
|
256
|
+
Check the query object.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
query (Query): The query object.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
bool: True if the query object is valid.
|
|
263
|
+
"""
|
|
264
|
+
return True
|
|
265
|
+
|
|
266
|
+
def _mount_query(self, query: Query) -> Query:
|
|
267
|
+
"""
|
|
268
|
+
Mount the query object.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
query (Query): The query object.
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
Query: The query object.
|
|
275
|
+
"""
|
|
276
|
+
if self.workflow_execution_id is not None:
|
|
277
|
+
query = query.where('workflow_execution_id', self.workflow_execution_id)
|
|
278
|
+
|
|
279
|
+
return query
|
|
280
|
+
|
|
281
|
+
@classmethod
|
|
282
|
+
def get_input_params(cls, entity_id: str) -> InputParams:
|
|
283
|
+
"""
|
|
284
|
+
Get the input_params of a Worker Execution with the given ID.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
entity_id (str): The ID of the Worker Execution.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
InputParams: The input_params of the Worker Execution.
|
|
291
|
+
|
|
292
|
+
Raises:
|
|
293
|
+
ValueError: If the entity ID is invalid.
|
|
294
|
+
ValueError: If the entity is not found.
|
|
295
|
+
"""
|
|
296
|
+
if cls.validate_id(entity_id) is False:
|
|
297
|
+
raise ValueError(f'Invalid Entity ID: {entity_id}')
|
|
298
|
+
|
|
299
|
+
entity: Self | None = cls.retrieve(entity_id)
|
|
300
|
+
|
|
301
|
+
if entity is None:
|
|
302
|
+
raise ValueError(f'Entity not found. Entity ID: {entity_id}')
|
|
303
|
+
|
|
304
|
+
if entity.input_params.worker_execution_id is None:
|
|
305
|
+
entity.input_params.worker_execution_id = entity.id # pylint: disable=attribute-defined-outside-init
|
|
306
|
+
|
|
307
|
+
return entity.input_params
|