digitalkin 0.2.12__py3-none-any.whl → 0.2.13__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.
- digitalkin/__version__.py +1 -1
- digitalkin/grpc_servers/_base_server.py +15 -17
- digitalkin/grpc_servers/module_server.py +9 -10
- digitalkin/grpc_servers/module_servicer.py +107 -85
- digitalkin/grpc_servers/registry_server.py +3 -6
- digitalkin/grpc_servers/registry_servicer.py +18 -19
- digitalkin/grpc_servers/utils/grpc_client_wrapper.py +3 -5
- digitalkin/logger.py +45 -1
- digitalkin/models/module/module.py +1 -0
- digitalkin/modules/_base_module.py +44 -5
- digitalkin/modules/job_manager/base_job_manager.py +139 -0
- digitalkin/modules/job_manager/job_manager_models.py +44 -0
- digitalkin/modules/job_manager/single_job_manager.py +218 -0
- digitalkin/modules/job_manager/taskiq_broker.py +173 -0
- digitalkin/modules/job_manager/taskiq_job_manager.py +213 -0
- digitalkin/services/cost/default_cost.py +8 -4
- digitalkin/services/cost/grpc_cost.py +15 -7
- digitalkin/services/filesystem/default_filesystem.py +2 -4
- digitalkin/services/filesystem/grpc_filesystem.py +8 -5
- digitalkin/services/setup/__init__.py +1 -0
- digitalkin/services/setup/default_setup.py +10 -12
- digitalkin/services/setup/grpc_setup.py +8 -10
- digitalkin/services/storage/default_storage.py +11 -5
- digitalkin/services/storage/grpc_storage.py +23 -8
- digitalkin/utils/arg_parser.py +5 -48
- digitalkin/utils/development_mode_action.py +51 -0
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.13.dist-info}/METADATA +42 -11
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.13.dist-info}/RECORD +35 -28
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.13.dist-info}/WHEEL +1 -1
- modules/cpu_intensive_module.py +271 -0
- modules/minimal_llm_module.py +200 -56
- modules/storage_module.py +5 -6
- modules/text_transform_module.py +1 -1
- digitalkin/modules/job_manager.py +0 -177
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.13.dist-info}/licenses/LICENSE +0 -0
- {digitalkin-0.2.12.dist-info → digitalkin-0.2.13.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
"""Grpc filesystem."""
|
|
2
2
|
|
|
3
|
-
import logging
|
|
4
3
|
from collections.abc import Generator
|
|
5
4
|
from contextlib import contextmanager
|
|
6
5
|
from typing import Any
|
|
7
6
|
|
|
8
|
-
from digitalkin_proto.digitalkin.filesystem.v2 import
|
|
9
|
-
|
|
7
|
+
from digitalkin_proto.digitalkin.filesystem.v2 import (
|
|
8
|
+
filesystem_pb2,
|
|
9
|
+
filesystem_service_pb2_grpc,
|
|
10
|
+
)
|
|
11
|
+
from digitalkin_proto.digitalkin.filesystem.v2.filesystem_pb2 import (
|
|
12
|
+
FileType as FileTypeProto,
|
|
13
|
+
)
|
|
10
14
|
|
|
11
15
|
from digitalkin.grpc_servers.utils.exceptions import ServerError
|
|
12
16
|
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
13
17
|
from digitalkin.grpc_servers.utils.models import ClientConfig
|
|
18
|
+
from digitalkin.logger import logger
|
|
14
19
|
from digitalkin.services.filesystem.filesystem_strategy import (
|
|
15
20
|
FilesystemData,
|
|
16
21
|
FilesystemServiceError,
|
|
@@ -18,8 +23,6 @@ from digitalkin.services.filesystem.filesystem_strategy import (
|
|
|
18
23
|
FileType,
|
|
19
24
|
)
|
|
20
25
|
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
26
|
|
|
24
27
|
class GrpcFilesystem(FilesystemStrategy, GrpcClientWrapper):
|
|
25
28
|
"""Default state filesystem strategy."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""This module is responsible for handling the setup service."""
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
"""This module contains the abstract base class for setup strategies."""
|
|
2
2
|
|
|
3
|
-
import logging
|
|
4
3
|
import secrets
|
|
5
4
|
import string
|
|
6
5
|
from typing import Any
|
|
7
6
|
|
|
8
7
|
from pydantic import ValidationError
|
|
9
8
|
|
|
9
|
+
from digitalkin.logger import logger
|
|
10
10
|
from digitalkin.services.setup.grpc_setup import SetupData, SetupVersionData
|
|
11
11
|
from digitalkin.services.setup.setup_strategy import SetupServiceError, SetupStrategy
|
|
12
12
|
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
13
|
|
|
16
14
|
class DefaultSetup(SetupStrategy):
|
|
17
15
|
"""Abstract base class for setup strategies."""
|
|
@@ -49,7 +47,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
49
47
|
)
|
|
50
48
|
valid_data.id = setup_id
|
|
51
49
|
self.setups[setup_id] = valid_data
|
|
52
|
-
logger.
|
|
50
|
+
logger.debug("CREATE SETUP DATA %s:%s succesfull", setup_id, valid_data)
|
|
53
51
|
return setup_id
|
|
54
52
|
|
|
55
53
|
def get_setup(self, setup_dict: dict[str, Any]) -> SetupData:
|
|
@@ -64,7 +62,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
64
62
|
Returns:
|
|
65
63
|
Dict[str, Any]: Setup details including optional setup version.
|
|
66
64
|
"""
|
|
67
|
-
logger.
|
|
65
|
+
logger.debug("GET setup_id = %s", setup_dict["setup_id"])
|
|
68
66
|
if setup_dict["setup_id"] not in self.setups:
|
|
69
67
|
msg = f"GET setup_id = {setup_dict['setup_id']}: setup_id DOESN'T EXIST"
|
|
70
68
|
logger.error(msg)
|
|
@@ -84,7 +82,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
84
82
|
bool: Success status of the update operation.
|
|
85
83
|
"""
|
|
86
84
|
if setup_dict["setup_id"] not in self.setups:
|
|
87
|
-
logger.
|
|
85
|
+
logger.debug("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_dict["setup_id"])
|
|
88
86
|
return False
|
|
89
87
|
|
|
90
88
|
try:
|
|
@@ -106,7 +104,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
106
104
|
bool: Success status of deletion.
|
|
107
105
|
"""
|
|
108
106
|
if setup_dict["setup_id"] not in self.setups:
|
|
109
|
-
logger.
|
|
107
|
+
logger.debug("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_dict["setup_id"])
|
|
110
108
|
return False
|
|
111
109
|
del self.setups[setup_dict["setup_id"]]
|
|
112
110
|
return True
|
|
@@ -133,7 +131,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
133
131
|
if setup_version_dict["setup_id"] not in self.setup_versions:
|
|
134
132
|
self.setup_versions[setup_version_dict["setup_id"]] = {}
|
|
135
133
|
self.setup_versions[setup_version_dict["setup_id"]][valid_data.version] = valid_data
|
|
136
|
-
logger.
|
|
134
|
+
logger.debug("CREATE SETUP VERSION DATA %s:%s succesfull", setup_version_dict["setup_id"], valid_data)
|
|
137
135
|
return valid_data.version
|
|
138
136
|
|
|
139
137
|
def get_setup_version(self, setup_version_dict: dict[str, Any]) -> SetupVersionData:
|
|
@@ -148,7 +146,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
148
146
|
Returns:
|
|
149
147
|
Dict[str, Any]: Setup version details.
|
|
150
148
|
"""
|
|
151
|
-
logger.
|
|
149
|
+
logger.debug("GET setup_id = %s: version = %s", setup_version_dict["setup_id"], setup_version_dict["version"])
|
|
152
150
|
if setup_version_dict["setup_id"] not in self.setup_versions:
|
|
153
151
|
msg = f"GET setup_id = {setup_version_dict['setup_id']}: setup_id DOESN'T EXIST"
|
|
154
152
|
logger.error(msg)
|
|
@@ -189,11 +187,11 @@ class DefaultSetup(SetupStrategy):
|
|
|
189
187
|
bool: Success status of the update operation.
|
|
190
188
|
"""
|
|
191
189
|
if setup_version_dict["setup_id"] not in self.setup_versions:
|
|
192
|
-
logger.
|
|
190
|
+
logger.debug("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_version_dict["setup_id"])
|
|
193
191
|
return False
|
|
194
192
|
|
|
195
193
|
if setup_version_dict["version"] not in self.setup_versions["setup_id"]:
|
|
196
|
-
logger.
|
|
194
|
+
logger.debug("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_version_dict["setup_id"])
|
|
197
195
|
return False
|
|
198
196
|
|
|
199
197
|
try:
|
|
@@ -215,7 +213,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
215
213
|
bool: Success status of version deletion.
|
|
216
214
|
"""
|
|
217
215
|
if setup_version_dict["setup_id"] not in self.setup_versions:
|
|
218
|
-
logger.
|
|
216
|
+
logger.debug("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_version_dict["setup_id"])
|
|
219
217
|
return False
|
|
220
218
|
|
|
221
219
|
del self.setup_versions[setup_version_dict["setup_id"]][setup_version_dict["version"]]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Digital Kin Setup Service gRPC Client."""
|
|
2
2
|
|
|
3
|
-
import logging
|
|
4
3
|
from collections.abc import Generator
|
|
5
4
|
from contextlib import contextmanager
|
|
6
5
|
from typing import Any
|
|
@@ -17,10 +16,9 @@ from pydantic import ValidationError
|
|
|
17
16
|
from digitalkin.grpc_servers.utils.exceptions import ServerError
|
|
18
17
|
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
19
18
|
from digitalkin.grpc_servers.utils.models import ClientConfig
|
|
19
|
+
from digitalkin.logger import logger
|
|
20
20
|
from digitalkin.services.setup.setup_strategy import SetupData, SetupServiceError, SetupStrategy, SetupVersionData
|
|
21
21
|
|
|
22
|
-
logger = logging.getLogger(__name__)
|
|
23
|
-
|
|
24
22
|
|
|
25
23
|
class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
26
24
|
"""This class implements the gRPC setup service."""
|
|
@@ -32,7 +30,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
32
30
|
"""
|
|
33
31
|
channel = self._init_channel(config)
|
|
34
32
|
self.stub = setup_service_pb2_grpc.SetupServiceStub(channel)
|
|
35
|
-
logger.
|
|
33
|
+
logger.debug("Channel client 'setup' initialized succesfully")
|
|
36
34
|
|
|
37
35
|
@contextmanager
|
|
38
36
|
def _handle_grpc_errors(self, operation: str) -> Generator[Any, Any, Any]: # noqa: PLR6301
|
|
@@ -89,7 +87,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
89
87
|
current_setup_version=setup_pb2.SetupVersion(**valid_data.current_setup_version.model_dump()),
|
|
90
88
|
)
|
|
91
89
|
response = self.exec_grpc_query("CreateSetup", request)
|
|
92
|
-
logger.
|
|
90
|
+
logger.debug("Setup '%s' query sent successfully", valid_data.name)
|
|
93
91
|
return response
|
|
94
92
|
|
|
95
93
|
def get_setup(self, setup_dict: dict[str, Any]) -> SetupData:
|
|
@@ -146,7 +144,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
146
144
|
current_setup_version=current_setup_version,
|
|
147
145
|
)
|
|
148
146
|
response = self.exec_grpc_query("UpdateSetup", request)
|
|
149
|
-
logger.
|
|
147
|
+
logger.debug("Setup '%s' query sent successfully", valid_data.name)
|
|
150
148
|
return getattr(response, "success", False)
|
|
151
149
|
|
|
152
150
|
def delete_setup(self, setup_dict: dict[str, Any]) -> bool:
|
|
@@ -170,7 +168,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
170
168
|
raise ValidationError(msg)
|
|
171
169
|
request = setup_pb2.DeleteSetupRequest(setup_id=setup_id)
|
|
172
170
|
response = self.exec_grpc_query("DeleteSetup", request)
|
|
173
|
-
logger.
|
|
171
|
+
logger.debug("Setup '%s' query sent successfully", setup_id)
|
|
174
172
|
return getattr(response, "success", False)
|
|
175
173
|
|
|
176
174
|
def create_setup_version(self, setup_version_dict: dict[str, Any]) -> str:
|
|
@@ -196,7 +194,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
196
194
|
version=valid_data.version,
|
|
197
195
|
content=content_struct,
|
|
198
196
|
)
|
|
199
|
-
logger.
|
|
197
|
+
logger.debug(
|
|
200
198
|
"Setup Version '%s' for setup '%s' query sent successfully",
|
|
201
199
|
valid_data.version,
|
|
202
200
|
valid_data.setup_id,
|
|
@@ -275,7 +273,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
275
273
|
content=content_struct,
|
|
276
274
|
)
|
|
277
275
|
response = self.exec_grpc_query("UpdateSetupVersion", request)
|
|
278
|
-
logger.
|
|
276
|
+
logger.debug(
|
|
279
277
|
"Setup Version '%s' for setup '%s' query sent successfully",
|
|
280
278
|
valid_data.id,
|
|
281
279
|
valid_data.setup_id,
|
|
@@ -303,5 +301,5 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
303
301
|
raise ValidationError(msg)
|
|
304
302
|
request = setup_pb2.DeleteSetupVersionRequest(setup_version_id=setup_version_id)
|
|
305
303
|
response = self.exec_grpc_query("DeleteSetupVersion", request)
|
|
306
|
-
logger.
|
|
304
|
+
logger.debug("Setup Version '%s' query sent successfully", setup_version_id)
|
|
307
305
|
return getattr(response, "success", False)
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
import datetime
|
|
4
4
|
import json
|
|
5
|
-
import logging
|
|
6
5
|
import tempfile
|
|
7
6
|
from pathlib import Path
|
|
8
7
|
from typing import Any
|
|
9
8
|
|
|
10
9
|
from pydantic import BaseModel
|
|
11
10
|
|
|
12
|
-
from digitalkin.
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
from digitalkin.logger import logger
|
|
12
|
+
from digitalkin.services.storage.storage_strategy import (
|
|
13
|
+
DataType,
|
|
14
|
+
StorageRecord,
|
|
15
|
+
StorageStrategy,
|
|
16
|
+
)
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class DefaultStorage(StorageStrategy):
|
|
@@ -80,7 +82,11 @@ class DefaultStorage(StorageStrategy):
|
|
|
80
82
|
"""Atomically write `self.storage` back to disk as JSON."""
|
|
81
83
|
self.storage_file.parent.mkdir(parents=True, exist_ok=True)
|
|
82
84
|
with tempfile.NamedTemporaryFile(
|
|
83
|
-
mode="w",
|
|
85
|
+
mode="w",
|
|
86
|
+
encoding="utf-8",
|
|
87
|
+
delete=False,
|
|
88
|
+
dir=str(self.storage_file.parent),
|
|
89
|
+
suffix=".tmp",
|
|
84
90
|
) as temp:
|
|
85
91
|
try:
|
|
86
92
|
# Convert storage to a serializable format
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"""This module implements the default storage strategy."""
|
|
2
2
|
|
|
3
|
-
import logging
|
|
4
|
-
|
|
5
3
|
from digitalkin_proto.digitalkin.storage.v2 import data_pb2, storage_service_pb2_grpc
|
|
6
4
|
from google.protobuf import json_format
|
|
7
5
|
from google.protobuf.struct_pb2 import Struct
|
|
@@ -9,9 +7,13 @@ from pydantic import BaseModel
|
|
|
9
7
|
|
|
10
8
|
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
11
9
|
from digitalkin.grpc_servers.utils.models import ClientConfig
|
|
12
|
-
from digitalkin.
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
from digitalkin.logger import logger
|
|
11
|
+
from digitalkin.services.storage.storage_strategy import (
|
|
12
|
+
DataType,
|
|
13
|
+
StorageRecord,
|
|
14
|
+
StorageServiceError,
|
|
15
|
+
StorageStrategy,
|
|
16
|
+
)
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class GrpcStorage(StorageStrategy, GrpcClientWrapper):
|
|
@@ -73,7 +75,11 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
|
|
|
73
75
|
resp = self.exec_grpc_query("StoreRecord", req)
|
|
74
76
|
return self._build_record_from_proto(resp.stored_data)
|
|
75
77
|
except Exception as e:
|
|
76
|
-
logger.exception(
|
|
78
|
+
logger.exception(
|
|
79
|
+
"gRPC StoreRecord failed for %s:%s",
|
|
80
|
+
record.collection,
|
|
81
|
+
record.record_id,
|
|
82
|
+
)
|
|
77
83
|
raise StorageServiceError(str(e)) from e
|
|
78
84
|
|
|
79
85
|
def _read(self, collection: str, record_id: str) -> StorageRecord | None:
|
|
@@ -94,7 +100,12 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
|
|
|
94
100
|
logger.exception("gRPC ReadRecord failed for %s:%s", collection, record_id)
|
|
95
101
|
return None
|
|
96
102
|
|
|
97
|
-
def _update(
|
|
103
|
+
def _update(
|
|
104
|
+
self,
|
|
105
|
+
collection: str,
|
|
106
|
+
record_id: str,
|
|
107
|
+
data: BaseModel,
|
|
108
|
+
) -> StorageRecord | None:
|
|
98
109
|
"""Overwrite a document via gRPC.
|
|
99
110
|
|
|
100
111
|
Args:
|
|
@@ -138,7 +149,11 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
|
|
|
138
149
|
)
|
|
139
150
|
self.exec_grpc_query("RemoveRecord", req)
|
|
140
151
|
except Exception:
|
|
141
|
-
logger.exception(
|
|
152
|
+
logger.exception(
|
|
153
|
+
"gRPC RemoveRecord failed for %s:%s",
|
|
154
|
+
collection,
|
|
155
|
+
record_id,
|
|
156
|
+
)
|
|
142
157
|
return False
|
|
143
158
|
return True
|
|
144
159
|
|
digitalkin/utils/arg_parser.py
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
"""ArgParser and Action classes to ease command lines arguments settings."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import
|
|
5
|
-
from argparse import Action, ArgumentParser, Namespace, _HelpAction, _SubParsersAction # noqa: PLC2701
|
|
4
|
+
from argparse import ArgumentParser, Namespace, _HelpAction, _SubParsersAction # noqa: PLC2701
|
|
6
5
|
from collections.abc import Sequence
|
|
7
6
|
from typing import Any
|
|
8
7
|
|
|
9
|
-
from digitalkin.
|
|
8
|
+
from digitalkin.logger import logger
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
logger = logging.getLogger(__name__)
|
|
10
|
+
logger.setLevel(logging.INFO)
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
class ArgParser:
|
|
@@ -81,11 +79,9 @@ class ArgParser:
|
|
|
81
79
|
def _add_parser_args(self, parser: ArgumentParser) -> None:
|
|
82
80
|
parser.add_argument("-h", "--help", action=self.HelpAction, help="help usage")
|
|
83
81
|
|
|
84
|
-
|
|
85
|
-
def _add_exclusive_args(parser: ArgumentParser) -> None: ...
|
|
82
|
+
def _add_exclusive_args(self, parser: ArgumentParser) -> None: ...
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
def _add_subparser_args(parser: ArgumentParser) -> None: ...
|
|
84
|
+
def _add_subparser_args(self, parser: ArgumentParser) -> None: ...
|
|
89
85
|
|
|
90
86
|
def __init__(self, prog: str = "PROG") -> None:
|
|
91
87
|
"""Create prser and call abstract methods."""
|
|
@@ -94,42 +90,3 @@ class ArgParser:
|
|
|
94
90
|
self._add_exclusive_args(self.parser)
|
|
95
91
|
self._add_subparser_args(self.parser)
|
|
96
92
|
self.args, _ = self.parser.parse_known_args()
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
class DevelopmentModeMappingAction(Action):
|
|
100
|
-
"""."""
|
|
101
|
-
|
|
102
|
-
def __init__(
|
|
103
|
-
self,
|
|
104
|
-
env_var: str,
|
|
105
|
-
required: bool = True, # noqa: FBT001, FBT002
|
|
106
|
-
default: str | None = None,
|
|
107
|
-
**kwargs: dict[str, Any],
|
|
108
|
-
) -> None:
|
|
109
|
-
"""."""
|
|
110
|
-
default = ServicesMode(os.environ.get(env_var, default))
|
|
111
|
-
|
|
112
|
-
if required and default:
|
|
113
|
-
required = False
|
|
114
|
-
super().__init__(default=default, required=required, **kwargs) # type: ignore
|
|
115
|
-
|
|
116
|
-
def __call__(
|
|
117
|
-
self,
|
|
118
|
-
parser: ArgumentParser, # noqa: ARG002
|
|
119
|
-
namespace: Namespace,
|
|
120
|
-
values: str | Sequence[Any] | None,
|
|
121
|
-
option_string: str | None = None, # noqa: ARG002
|
|
122
|
-
) -> None:
|
|
123
|
-
"""Set the attribute to the corresponding class.
|
|
124
|
-
|
|
125
|
-
Raises:
|
|
126
|
-
TypeError: if the value is not a string.
|
|
127
|
-
"""
|
|
128
|
-
# Check if the value is a string and convert it to lowercase
|
|
129
|
-
if isinstance(values, str):
|
|
130
|
-
values = values.lower()
|
|
131
|
-
else:
|
|
132
|
-
msg = "values must be a string"
|
|
133
|
-
raise TypeError(msg)
|
|
134
|
-
mode = ServicesMode(values)
|
|
135
|
-
setattr(namespace, self.dest, mode)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""ArgParser and Action classes to ease command lines arguments settings."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from argparse import Action, ArgumentParser, Namespace
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from digitalkin.logger import logger
|
|
10
|
+
from digitalkin.services.services_models import ServicesMode
|
|
11
|
+
|
|
12
|
+
logger.setLevel(logging.INFO)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DevelopmentModeMappingAction(Action):
|
|
16
|
+
"""."""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
env_var: str,
|
|
21
|
+
required: bool = True, # noqa: FBT001, FBT002
|
|
22
|
+
default: str | None = None,
|
|
23
|
+
**kwargs: dict[str, Any],
|
|
24
|
+
) -> None:
|
|
25
|
+
"""."""
|
|
26
|
+
default = ServicesMode(os.environ.get(env_var, default))
|
|
27
|
+
|
|
28
|
+
if required and default:
|
|
29
|
+
required = False
|
|
30
|
+
super().__init__(default=default, required=required, **kwargs) # type: ignore
|
|
31
|
+
|
|
32
|
+
def __call__(
|
|
33
|
+
self,
|
|
34
|
+
parser: ArgumentParser, # noqa: ARG002
|
|
35
|
+
namespace: Namespace,
|
|
36
|
+
values: str | Sequence[Any] | None,
|
|
37
|
+
option_string: str | None = None, # noqa: ARG002
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Set the attribute to the corresponding class.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
TypeError: if the value is not a string.
|
|
43
|
+
"""
|
|
44
|
+
# Check if the value is a string and convert it to lowercase
|
|
45
|
+
if isinstance(values, str):
|
|
46
|
+
values = values.lower()
|
|
47
|
+
else:
|
|
48
|
+
msg = "values must be a string"
|
|
49
|
+
raise TypeError(msg)
|
|
50
|
+
mode = ServicesMode(values)
|
|
51
|
+
setattr(namespace, self.dest, mode)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: digitalkin
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.13
|
|
4
4
|
Summary: SDK to build kin used in DigitalKin
|
|
5
5
|
Author-email: "DigitalKin.ai" <contact@digitalkin.ai>
|
|
6
6
|
License: Attribution-NonCommercial-ShareAlike 4.0 International
|
|
@@ -456,25 +456,32 @@ Requires-Dist: digitalkin-proto>=0.1.10
|
|
|
456
456
|
Requires-Dist: grpcio-health-checking>=1.71.0
|
|
457
457
|
Requires-Dist: grpcio-reflection>=1.71.0
|
|
458
458
|
Requires-Dist: grpcio-status>=1.71.0
|
|
459
|
-
Requires-Dist: openai>=1.76.2
|
|
460
459
|
Requires-Dist: pydantic>=2.11.4
|
|
461
460
|
Provides-Extra: dev
|
|
462
|
-
Requires-Dist:
|
|
463
|
-
Requires-Dist:
|
|
464
|
-
Requires-Dist: pytest-cov>=6.1.0; extra == "dev"
|
|
465
|
-
Requires-Dist: typos>=1.31.2; extra == "dev"
|
|
466
|
-
Requires-Dist: ruff>=0.11.7; extra == "dev"
|
|
461
|
+
Requires-Dist: typos>=1.32.0; extra == "dev"
|
|
462
|
+
Requires-Dist: ruff>=0.11.9; extra == "dev"
|
|
467
463
|
Requires-Dist: mypy>=1.15.0; extra == "dev"
|
|
468
464
|
Requires-Dist: pyright>=1.1.400; extra == "dev"
|
|
469
465
|
Requires-Dist: pre-commit>=4.2.0; extra == "dev"
|
|
470
466
|
Requires-Dist: bump2version>=1.0.1; extra == "dev"
|
|
471
467
|
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
472
468
|
Requires-Dist: twine>=6.1.0; extra == "dev"
|
|
473
|
-
Requires-Dist: cryptography>=44.0.
|
|
474
|
-
Requires-Dist:
|
|
475
|
-
Requires-Dist: freezegun>=1.5.1; extra == "dev"
|
|
469
|
+
Requires-Dist: cryptography>=44.0.3; extra == "dev"
|
|
470
|
+
Requires-Dist: taskiq[reload]>=0.11.17; extra == "dev"
|
|
476
471
|
Provides-Extra: examples
|
|
477
|
-
Requires-Dist: openai>=1.
|
|
472
|
+
Requires-Dist: openai>=1.75.0; extra == "examples"
|
|
473
|
+
Provides-Extra: tests
|
|
474
|
+
Requires-Dist: freezegun>=1.5.1; extra == "tests"
|
|
475
|
+
Requires-Dist: hdrhistogram>=0.10.3; extra == "tests"
|
|
476
|
+
Requires-Dist: grpcio-testing>=1.71.0; extra == "tests"
|
|
477
|
+
Requires-Dist: psutil>=7.0.0; extra == "tests"
|
|
478
|
+
Requires-Dist: pytest>=8.3.4; extra == "tests"
|
|
479
|
+
Requires-Dist: pytest-asyncio>=0.26.0; extra == "tests"
|
|
480
|
+
Requires-Dist: pytest-cov>=6.1.0; extra == "tests"
|
|
481
|
+
Provides-Extra: taskiq
|
|
482
|
+
Requires-Dist: rstream>=0.20.9; extra == "taskiq"
|
|
483
|
+
Requires-Dist: taskiq-aio-pika>=0.4.2; extra == "taskiq"
|
|
484
|
+
Requires-Dist: taskiq-redis>=1.0.8; extra == "taskiq"
|
|
478
485
|
Dynamic: license-file
|
|
479
486
|
|
|
480
487
|
# DigitalKin Python SDK
|
|
@@ -509,6 +516,16 @@ To install the DigitalKin SDK, simply run:
|
|
|
509
516
|
pip install digitalkin
|
|
510
517
|
```
|
|
511
518
|
|
|
519
|
+
**Optional Taskiq Integration**: Asynchronous task execution powered by Taskiq, backed by RabbitMQ and Redis
|
|
520
|
+
To enable the Rabbitmq streaming capabilities, run:
|
|
521
|
+
|
|
522
|
+
```sh
|
|
523
|
+
sudo rabbitmq-plugins enable rabbitmq_stream
|
|
524
|
+
|
|
525
|
+
# Core + Taskiq integration (RabbitMQ broker)
|
|
526
|
+
pip install digitalkin[taskiq]
|
|
527
|
+
```
|
|
528
|
+
|
|
512
529
|
## 🛠️ Usage
|
|
513
530
|
|
|
514
531
|
### Basic Import
|
|
@@ -519,6 +536,20 @@ Start by importing the necessary modules:
|
|
|
519
536
|
import digitalkin
|
|
520
537
|
```
|
|
521
538
|
|
|
539
|
+
## Features
|
|
540
|
+
|
|
541
|
+
### Taskiq with RabbitMQ
|
|
542
|
+
|
|
543
|
+
TaskIQ intergration allows the module to scale for heavy CPU tasks by having the request's stateless module in a new instance.
|
|
544
|
+
|
|
545
|
+
- **Decoupled Scalability**: RabbitMQ brokers messages, letting producers and consumers scale independently.
|
|
546
|
+
- **Reliability**: Durable queues, acknowledgements, and dead-lettering ensure tasks aren’t lost.
|
|
547
|
+
- **Concurrency Control**: Taskiq’s worker pool manages parallel execution without custom schedulers.
|
|
548
|
+
- **Flexibility**: Built-in retries, exponential backoff, and Redis result-backend for resilient workflows.
|
|
549
|
+
- **Ecosystem**: Battle-tested `aio-pika` AMQP client plus Taskiq’s decorator-based API.
|
|
550
|
+
|
|
551
|
+
By combining Taskiq’s async API with RabbitMQ’s guarantees, you get a robust, production-ready queue with minimal boilerplate.
|
|
552
|
+
|
|
522
553
|
## 👷♂️ Development
|
|
523
554
|
|
|
524
555
|
### Prerequisites
|
|
@@ -7,33 +7,37 @@ base_server/mock/__init__.py,sha256=YZFT-F1l_TpvJYuIPX-7kTeE1CfOjhx9YmNRXVoi-jQ,
|
|
|
7
7
|
base_server/mock/mock_pb2.py,sha256=sETakcS3PAAm4E-hTCV1jIVaQTPEAIoVVHupB8Z_k7Y,1843
|
|
8
8
|
base_server/mock/mock_pb2_grpc.py,sha256=BbOT70H6q3laKgkHfOx1QdfmCS_HxCY4wCOX84YAdG4,3180
|
|
9
9
|
digitalkin/__init__.py,sha256=7LLBAba0th-3SGqcpqFO-lopWdUkVLKzLZiMtB-mW3M,162
|
|
10
|
-
digitalkin/__version__.py,sha256=
|
|
11
|
-
digitalkin/logger.py,sha256=
|
|
10
|
+
digitalkin/__version__.py,sha256=FYm4fUSZE0epsu7qiHq0IkVIvAs5ZzTEDWDQWZeryGs,191
|
|
11
|
+
digitalkin/logger.py,sha256=cFbIAZHOFx3nddOssRNYLXyqUPzR4CgDR_c-5wmB-og,1685
|
|
12
12
|
digitalkin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
digitalkin/grpc_servers/__init__.py,sha256=0cJBlwipSmFdXkyH3T0i6OJ1WpAtNsZgYX7JaSnkbtg,804
|
|
14
|
-
digitalkin/grpc_servers/_base_server.py,sha256=
|
|
15
|
-
digitalkin/grpc_servers/module_server.py,sha256=
|
|
16
|
-
digitalkin/grpc_servers/module_servicer.py,sha256=
|
|
17
|
-
digitalkin/grpc_servers/registry_server.py,sha256=
|
|
18
|
-
digitalkin/grpc_servers/registry_servicer.py,sha256=
|
|
14
|
+
digitalkin/grpc_servers/_base_server.py,sha256=NXnnZPjJqUDWoumhEbb7EOEWB7d8XYwpQs-l97NTe4k,18647
|
|
15
|
+
digitalkin/grpc_servers/module_server.py,sha256=tc4n8fu7bcMkwCI3CKkAKR4cZqyP_JTEW0lGtqsc5hs,10283
|
|
16
|
+
digitalkin/grpc_servers/module_servicer.py,sha256=I6S8qDhKOwDD1tofoUhAfhN8VH6A7hAM5UAlwu91_Is,14747
|
|
17
|
+
digitalkin/grpc_servers/registry_server.py,sha256=StY18DKYoPKQIU1SIzgito6D4_QA1aMVddZ8O2WGlHY,2223
|
|
18
|
+
digitalkin/grpc_servers/registry_servicer.py,sha256=dqsKGHZ0LnaIvGt4ipaAuigd37sbJBndT4MAT029GsY,16471
|
|
19
19
|
digitalkin/grpc_servers/utils/exceptions.py,sha256=I00OM8p8up20He4dU1fiHsvdLj1DymjR_UmoeUm2MSA,785
|
|
20
20
|
digitalkin/grpc_servers/utils/factory.py,sha256=jm6rFjiqmtSv7BIHNAOxsG9xXtSvWpx9TfzSQiX97MQ,5899
|
|
21
|
-
digitalkin/grpc_servers/utils/grpc_client_wrapper.py,sha256=
|
|
21
|
+
digitalkin/grpc_servers/utils/grpc_client_wrapper.py,sha256=GXRqCTCufwWd8sVMoClnl-JpeBjgmdlSCD0a3YMU9D0,2594
|
|
22
22
|
digitalkin/grpc_servers/utils/models.py,sha256=80F5oHiv8MOqMoDZJBXmJSRoVYJRyhaVcijQ2LinAig,8428
|
|
23
23
|
digitalkin/grpc_servers/utils/types.py,sha256=rQ78s4nAet2jy-NIDj_PUWriT0kuGHr_w6ELjmjgBao,539
|
|
24
24
|
digitalkin/models/__init__.py,sha256=hDHtUfswaNh8wo4NZaBItg9JqC0uNSRqXArNWSrGynY,163
|
|
25
25
|
digitalkin/models/module/__init__.py,sha256=ihvRlemJuFvU4armZIL-Vq-zaJx9UrjDoJAVPbEG8jw,345
|
|
26
|
-
digitalkin/models/module/module.py,sha256=
|
|
26
|
+
digitalkin/models/module/module.py,sha256=NWOwCeD_NH0NL89AF_NJ0SwE7G1n-HTcRalodLCDmpM,749
|
|
27
27
|
digitalkin/models/module/module_types.py,sha256=SxwzfDDnkyuQe50glVrxN6VPuJCkbB313FRyVZugIMw,312
|
|
28
28
|
digitalkin/models/services/__init__.py,sha256=HsW7MUGFPvH7Ri28WN4BHHBfEQk5dzU_9FOWAc-0lSE,56
|
|
29
29
|
digitalkin/models/services/cost.py,sha256=QTEuFD6xz62nob0z4ksE-INJWcZ-iFiuNW5mvXhpFes,1599
|
|
30
30
|
digitalkin/models/services/storage.py,sha256=cYTVIriGKiprF9OerhSxmc_jM6fUTVwmeon1yQCinkE,143
|
|
31
31
|
digitalkin/modules/__init__.py,sha256=ppYARmhvdVi55ofC0QZerIempSlcJYDeCXhcl4qXObw,278
|
|
32
|
-
digitalkin/modules/_base_module.py,sha256=
|
|
32
|
+
digitalkin/modules/_base_module.py,sha256=EwfCCIy3N1eBdBUj6KAdx0WzNRFJsyQDVCdA8Lwvtn4,10463
|
|
33
33
|
digitalkin/modules/archetype_module.py,sha256=T2Ehj7EpAC2MO9WQbJv39hqRw7rh3exhVZTEL3JPM8U,421
|
|
34
|
-
digitalkin/modules/job_manager.py,sha256=EB53_HZJZOkOR3MXidN8ZiJte8_kOJZ3hnOFVfm5v64,6243
|
|
35
34
|
digitalkin/modules/tool_module.py,sha256=86g0M1wHZ1ReIc7AkKfyjnlGN2QYJBGxrEQpKVlyrZI,421
|
|
36
35
|
digitalkin/modules/trigger_module.py,sha256=kVoI4Gdkw7WWUP5T6hSCNqw5FxibTxL6Tpq9KP7gg78,379
|
|
36
|
+
digitalkin/modules/job_manager/base_job_manager.py,sha256=I3bduyGDjCJ6RsbwQvLp_NA6ucP8MJJVoIKpEbaP9ss,4706
|
|
37
|
+
digitalkin/modules/job_manager/job_manager_models.py,sha256=onHy-DfInLZQveniMIWIKwTKSQjojz500JvHB54x93c,1129
|
|
38
|
+
digitalkin/modules/job_manager/single_job_manager.py,sha256=Dekcnn8wb4epqGrWFAZ86YvvII553Hw0xjipgAINl4A,7745
|
|
39
|
+
digitalkin/modules/job_manager/taskiq_broker.py,sha256=OnHZy-hAtVDU5FU4W9folZZKCrDrUk16VfHlfoECuiQ,5930
|
|
40
|
+
digitalkin/modules/job_manager/taskiq_job_manager.py,sha256=ODqC7Snf-Flo0ugotqicrTgjFu4wgll6bUu7CM3l7ZE,7459
|
|
37
41
|
digitalkin/services/__init__.py,sha256=LqGk_5DJy8Bzz62ajIq9jCeYNKQUIgtSCpafZk15FLc,910
|
|
38
42
|
digitalkin/services/base_strategy.py,sha256=QAQnJw1BbqcYMSzwlFyhHP5juBH2WKrZzWxqDr_sDHI,638
|
|
39
43
|
digitalkin/services/services_config.py,sha256=4hc7-rHgSigoS3SuV0V9FReD2Dz7XoMXcD6iMBP2KKM,7391
|
|
@@ -43,37 +47,40 @@ digitalkin/services/agent/agent_strategy.py,sha256=42Q9RciHX6tg3CgDQkbrlIx4h_TX0
|
|
|
43
47
|
digitalkin/services/agent/default_agent.py,sha256=4N_E_eQxJGOx1KVUUg5jNOje-3ncMxF3ePB-uDuGrJc,345
|
|
44
48
|
digitalkin/services/cost/__init__.py,sha256=Wi9ZB4LSXFsUYgkX-V1UJQkVXYDNDpp8q2dXccR2uRM,303
|
|
45
49
|
digitalkin/services/cost/cost_strategy.py,sha256=VhHeqi9WnE1yoDBBVp5qmqwIt5tTZHU6_Z_jld8CVeE,2535
|
|
46
|
-
digitalkin/services/cost/default_cost.py,sha256=
|
|
47
|
-
digitalkin/services/cost/grpc_cost.py,sha256=
|
|
50
|
+
digitalkin/services/cost/default_cost.py,sha256=mEd0VL_tMcGU41q0f9MFeBYeKZBenv0mIHuwgXlQ7uQ,3869
|
|
51
|
+
digitalkin/services/cost/grpc_cost.py,sha256=p_5mG72N7e4bxwBOD9DNokvLtinBILiqCfllmkqpmhw,6253
|
|
48
52
|
digitalkin/services/filesystem/__init__.py,sha256=BhwMl_BUvM0d65fmglkp0SVwn3RfYiUOKJgIMnOCaGM,381
|
|
49
|
-
digitalkin/services/filesystem/default_filesystem.py,sha256=
|
|
53
|
+
digitalkin/services/filesystem/default_filesystem.py,sha256=8pRO80GtJ3n7StNllvwsgM6vMurJso1Xj4bWBt_zbjw,7381
|
|
50
54
|
digitalkin/services/filesystem/filesystem_strategy.py,sha256=g5duep7Trc_NWq9WNtCrnheVxfMUvX6vJyx4W0hwwiY,2348
|
|
51
|
-
digitalkin/services/filesystem/grpc_filesystem.py,sha256=
|
|
55
|
+
digitalkin/services/filesystem/grpc_filesystem.py,sha256=IN2HX05lzUzsE9BZdp_nhEKYV2GNLJRQLduzFh1JN-w,8326
|
|
52
56
|
digitalkin/services/identity/__init__.py,sha256=InkeyLgFYYwItx8mePA8HpfacOMWZwwuc0G4pWtKq9s,270
|
|
53
57
|
digitalkin/services/identity/default_identity.py,sha256=Y2auZHrGSZTIN5D8HyjLvLcNbYFM1CNUE23x7p5VIGw,386
|
|
54
58
|
digitalkin/services/identity/identity_strategy.py,sha256=skappBbds1_qa0Gr24FGrNX1N0_OYhYT1Lh7dUaAirE,429
|
|
55
59
|
digitalkin/services/registry/__init__.py,sha256=Zl4QAkCe9tOmmKGBWVuLQVFepdZiL0ec3VDj27IeyYM,270
|
|
56
60
|
digitalkin/services/registry/default_registry.py,sha256=VnWkF6nHpFxUKuUbZLPqzXqdA6oXmyV_ySpeuOCf_ko,277
|
|
57
61
|
digitalkin/services/registry/registry_strategy.py,sha256=uBXgZIv25jeXbeVO8vWvlNPxxNYu7_KiCw2PoE6AWr8,423
|
|
58
|
-
digitalkin/services/setup/
|
|
59
|
-
digitalkin/services/setup/
|
|
62
|
+
digitalkin/services/setup/__init__.py,sha256=t6xcvEWqTbcRZstBFK9cESEqaZKvpW14VtYygxIqfYQ,65
|
|
63
|
+
digitalkin/services/setup/default_setup.py,sha256=9VM3KwsuQcFQQ08RoOHWOE_-9BsRW0YGRtDWYTbQGdA,8246
|
|
64
|
+
digitalkin/services/setup/grpc_setup.py,sha256=jLw9tfHMFhdVYXCIGC2ffx2HUgyNpgMi9G265nvkvMg,12440
|
|
60
65
|
digitalkin/services/setup/setup_strategy.py,sha256=ZnJ_HwWCkHCPrqKekSD5L9y3p8wMwfjQ8sj2hLZq6go,4004
|
|
61
66
|
digitalkin/services/snapshot/__init__.py,sha256=Uzlnzo0CYlSpVsdiI37hW7xQk8hu3YA1fOI6O6MSzB0,270
|
|
62
67
|
digitalkin/services/snapshot/default_snapshot.py,sha256=Mb8QwWRsHh9I_tN0ln_ZiFa1QCZxOVWmuVLemQOTWpc,1058
|
|
63
68
|
digitalkin/services/snapshot/snapshot_strategy.py,sha256=B1TU3V_k9A-OdqBkdyc41-ihnrW5Btcwd1KyQdHT46A,898
|
|
64
69
|
digitalkin/services/storage/__init__.py,sha256=T-ocYLLphudkQgzvG47jBOm5GQsRFRIGA88y7Ur4akg,341
|
|
65
|
-
digitalkin/services/storage/default_storage.py,sha256=
|
|
66
|
-
digitalkin/services/storage/grpc_storage.py,sha256=
|
|
70
|
+
digitalkin/services/storage/default_storage.py,sha256=m53sLOx0JVbua4weD_4GQBKK3c0UDf9HC5BnvSJAkvg,7933
|
|
71
|
+
digitalkin/services/storage/grpc_storage.py,sha256=EU2gcT2bOCSqOsnLwQcu3VOeOvdBlP1g0ALfBb07JxY,7172
|
|
67
72
|
digitalkin/services/storage/storage_strategy.py,sha256=vZWPk49AyJs7RwhSfUwDiTG1A7C4Ccd8y-VVPslyf0w,8734
|
|
68
73
|
digitalkin/utils/__init__.py,sha256=sJnY-ZUgsjMfojAjONC1VN14mhgIDnzyOlGkw21rRnM,28
|
|
69
|
-
digitalkin/utils/arg_parser.py,sha256=
|
|
74
|
+
digitalkin/utils/arg_parser.py,sha256=nvjI1pKDY1HfS0oGcMQPtdTQcggXLtpxXMbnMxNEKRU,3109
|
|
75
|
+
digitalkin/utils/development_mode_action.py,sha256=TqRuAF_A7bDD4twRB4PnZcRoNeaiAnEdxM5kvy4aoaA,1511
|
|
70
76
|
digitalkin/utils/llm_ready_schema.py,sha256=JjMug_lrQllqFoanaC091VgOqwAd-_YzcpqFlS7p778,2375
|
|
71
|
-
digitalkin-0.2.
|
|
77
|
+
digitalkin-0.2.13.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
|
|
72
78
|
modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
modules/
|
|
74
|
-
modules/
|
|
75
|
-
modules/
|
|
76
|
-
|
|
77
|
-
digitalkin-0.2.
|
|
78
|
-
digitalkin-0.2.
|
|
79
|
-
digitalkin-0.2.
|
|
79
|
+
modules/cpu_intensive_module.py,sha256=LUfgd1qFJ0HfsWMapSXUivgf5KGDpANKPORbcQBUjc4,8089
|
|
80
|
+
modules/minimal_llm_module.py,sha256=6cygPliUb4mroOrUo5YirZfQQ1IeOT3xUHzPpDC_0Tc,10045
|
|
81
|
+
modules/storage_module.py,sha256=KJA75oxXDUxZrLfoY5KxeyI8Gm1b3DxFuFj7LGOkeaQ,6389
|
|
82
|
+
modules/text_transform_module.py,sha256=Db_WbJi7_gWyoNvQEVhHQf5VurDsU-jd9LMAalG0oZY,7277
|
|
83
|
+
digitalkin-0.2.13.dist-info/METADATA,sha256=CUpDclUxsamv7icPsWN-ImippAec3_EQZUGm1cQGHFQ,30577
|
|
84
|
+
digitalkin-0.2.13.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
85
|
+
digitalkin-0.2.13.dist-info/top_level.txt,sha256=5_5e35inSM5YfWNZE21p5wGBojiVtQQML_WzbEk4BRU,31
|
|
86
|
+
digitalkin-0.2.13.dist-info/RECORD,,
|