dtlpy 1.115.44__py3-none-any.whl → 1.116.6__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.
- dtlpy/__init__.py +491 -491
- dtlpy/__version__.py +1 -1
- dtlpy/assets/__init__.py +26 -26
- dtlpy/assets/code_server/config.yaml +2 -2
- dtlpy/assets/code_server/installation.sh +24 -24
- dtlpy/assets/code_server/launch.json +13 -13
- dtlpy/assets/code_server/settings.json +2 -2
- dtlpy/assets/main.py +53 -53
- dtlpy/assets/main_partial.py +18 -18
- dtlpy/assets/mock.json +11 -11
- dtlpy/assets/model_adapter.py +83 -83
- dtlpy/assets/package.json +61 -61
- dtlpy/assets/package_catalog.json +29 -29
- dtlpy/assets/package_gitignore +307 -307
- dtlpy/assets/service_runners/__init__.py +33 -33
- dtlpy/assets/service_runners/converter.py +96 -96
- dtlpy/assets/service_runners/multi_method.py +49 -49
- dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
- dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
- dtlpy/assets/service_runners/multi_method_item.py +52 -52
- dtlpy/assets/service_runners/multi_method_json.py +52 -52
- dtlpy/assets/service_runners/single_method.py +37 -37
- dtlpy/assets/service_runners/single_method_annotation.py +43 -43
- dtlpy/assets/service_runners/single_method_dataset.py +43 -43
- dtlpy/assets/service_runners/single_method_item.py +41 -41
- dtlpy/assets/service_runners/single_method_json.py +42 -42
- dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
- dtlpy/assets/voc_annotation_template.xml +23 -23
- dtlpy/caches/base_cache.py +32 -32
- dtlpy/caches/cache.py +473 -473
- dtlpy/caches/dl_cache.py +201 -201
- dtlpy/caches/filesystem_cache.py +89 -89
- dtlpy/caches/redis_cache.py +84 -84
- dtlpy/dlp/__init__.py +20 -20
- dtlpy/dlp/cli_utilities.py +367 -367
- dtlpy/dlp/command_executor.py +764 -764
- dtlpy/dlp/dlp +1 -1
- dtlpy/dlp/dlp.bat +1 -1
- dtlpy/dlp/dlp.py +128 -128
- dtlpy/dlp/parser.py +651 -651
- dtlpy/entities/__init__.py +83 -83
- dtlpy/entities/analytic.py +347 -347
- dtlpy/entities/annotation.py +1879 -1879
- dtlpy/entities/annotation_collection.py +699 -699
- dtlpy/entities/annotation_definitions/__init__.py +20 -20
- dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
- dtlpy/entities/annotation_definitions/box.py +195 -195
- dtlpy/entities/annotation_definitions/classification.py +67 -67
- dtlpy/entities/annotation_definitions/comparison.py +72 -72
- dtlpy/entities/annotation_definitions/cube.py +204 -204
- dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
- dtlpy/entities/annotation_definitions/description.py +32 -32
- dtlpy/entities/annotation_definitions/ellipse.py +124 -124
- dtlpy/entities/annotation_definitions/free_text.py +62 -62
- dtlpy/entities/annotation_definitions/gis.py +69 -69
- dtlpy/entities/annotation_definitions/note.py +139 -139
- dtlpy/entities/annotation_definitions/point.py +117 -117
- dtlpy/entities/annotation_definitions/polygon.py +182 -182
- dtlpy/entities/annotation_definitions/polyline.py +111 -111
- dtlpy/entities/annotation_definitions/pose.py +92 -92
- dtlpy/entities/annotation_definitions/ref_image.py +86 -86
- dtlpy/entities/annotation_definitions/segmentation.py +240 -240
- dtlpy/entities/annotation_definitions/subtitle.py +34 -34
- dtlpy/entities/annotation_definitions/text.py +85 -85
- dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
- dtlpy/entities/app.py +220 -220
- dtlpy/entities/app_module.py +107 -107
- dtlpy/entities/artifact.py +174 -174
- dtlpy/entities/assignment.py +399 -399
- dtlpy/entities/base_entity.py +214 -214
- dtlpy/entities/bot.py +113 -113
- dtlpy/entities/codebase.py +292 -292
- dtlpy/entities/collection.py +38 -38
- dtlpy/entities/command.py +169 -169
- dtlpy/entities/compute.py +449 -449
- dtlpy/entities/dataset.py +1299 -1299
- dtlpy/entities/directory_tree.py +44 -44
- dtlpy/entities/dpk.py +470 -470
- dtlpy/entities/driver.py +235 -235
- dtlpy/entities/execution.py +397 -397
- dtlpy/entities/feature.py +124 -124
- dtlpy/entities/feature_set.py +145 -145
- dtlpy/entities/filters.py +798 -798
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +959 -959
- dtlpy/entities/label.py +123 -123
- dtlpy/entities/links.py +85 -85
- dtlpy/entities/message.py +175 -175
- dtlpy/entities/model.py +684 -684
- dtlpy/entities/node.py +1005 -1005
- dtlpy/entities/ontology.py +810 -803
- dtlpy/entities/organization.py +287 -287
- dtlpy/entities/package.py +657 -657
- dtlpy/entities/package_defaults.py +5 -5
- dtlpy/entities/package_function.py +185 -185
- dtlpy/entities/package_module.py +113 -113
- dtlpy/entities/package_slot.py +118 -118
- dtlpy/entities/paged_entities.py +299 -299
- dtlpy/entities/pipeline.py +624 -624
- dtlpy/entities/pipeline_execution.py +279 -279
- dtlpy/entities/project.py +394 -394
- dtlpy/entities/prompt_item.py +505 -505
- dtlpy/entities/recipe.py +301 -301
- dtlpy/entities/reflect_dict.py +102 -102
- dtlpy/entities/resource_execution.py +138 -138
- dtlpy/entities/service.py +963 -963
- dtlpy/entities/service_driver.py +117 -117
- dtlpy/entities/setting.py +294 -294
- dtlpy/entities/task.py +495 -495
- dtlpy/entities/time_series.py +143 -143
- dtlpy/entities/trigger.py +426 -426
- dtlpy/entities/user.py +118 -118
- dtlpy/entities/webhook.py +124 -124
- dtlpy/examples/__init__.py +19 -19
- dtlpy/examples/add_labels.py +135 -135
- dtlpy/examples/add_metadata_to_item.py +21 -21
- dtlpy/examples/annotate_items_using_model.py +65 -65
- dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
- dtlpy/examples/annotations_convert_to_voc.py +9 -9
- dtlpy/examples/annotations_convert_to_yolo.py +9 -9
- dtlpy/examples/convert_annotation_types.py +51 -51
- dtlpy/examples/converter.py +143 -143
- dtlpy/examples/copy_annotations.py +22 -22
- dtlpy/examples/copy_folder.py +31 -31
- dtlpy/examples/create_annotations.py +51 -51
- dtlpy/examples/create_video_annotations.py +83 -83
- dtlpy/examples/delete_annotations.py +26 -26
- dtlpy/examples/filters.py +113 -113
- dtlpy/examples/move_item.py +23 -23
- dtlpy/examples/play_video_annotation.py +13 -13
- dtlpy/examples/show_item_and_mask.py +53 -53
- dtlpy/examples/triggers.py +49 -49
- dtlpy/examples/upload_batch_of_items.py +20 -20
- dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
- dtlpy/examples/upload_items_with_modalities.py +43 -43
- dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
- dtlpy/examples/upload_yolo_format_annotations.py +70 -70
- dtlpy/exceptions.py +125 -125
- dtlpy/miscellaneous/__init__.py +20 -20
- dtlpy/miscellaneous/dict_differ.py +95 -95
- dtlpy/miscellaneous/git_utils.py +217 -217
- dtlpy/miscellaneous/json_utils.py +14 -14
- dtlpy/miscellaneous/list_print.py +105 -105
- dtlpy/miscellaneous/zipping.py +130 -130
- dtlpy/ml/__init__.py +20 -20
- dtlpy/ml/base_feature_extractor_adapter.py +27 -27
- dtlpy/ml/base_model_adapter.py +1257 -1230
- dtlpy/ml/metrics.py +461 -461
- dtlpy/ml/predictions_utils.py +274 -274
- dtlpy/ml/summary_writer.py +57 -57
- dtlpy/ml/train_utils.py +60 -60
- dtlpy/new_instance.py +252 -252
- dtlpy/repositories/__init__.py +56 -56
- dtlpy/repositories/analytics.py +85 -85
- dtlpy/repositories/annotations.py +916 -916
- dtlpy/repositories/apps.py +383 -383
- dtlpy/repositories/artifacts.py +452 -452
- dtlpy/repositories/assignments.py +599 -599
- dtlpy/repositories/bots.py +213 -213
- dtlpy/repositories/codebases.py +559 -559
- dtlpy/repositories/collections.py +332 -332
- dtlpy/repositories/commands.py +152 -152
- dtlpy/repositories/compositions.py +61 -61
- dtlpy/repositories/computes.py +439 -439
- dtlpy/repositories/datasets.py +1504 -1504
- dtlpy/repositories/downloader.py +976 -923
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -482
- dtlpy/repositories/executions.py +815 -815
- dtlpy/repositories/feature_sets.py +226 -226
- dtlpy/repositories/features.py +255 -255
- dtlpy/repositories/integrations.py +484 -484
- dtlpy/repositories/items.py +912 -912
- dtlpy/repositories/messages.py +94 -94
- dtlpy/repositories/models.py +1000 -1000
- dtlpy/repositories/nodes.py +80 -80
- dtlpy/repositories/ontologies.py +511 -511
- dtlpy/repositories/organizations.py +525 -525
- dtlpy/repositories/packages.py +1941 -1941
- dtlpy/repositories/pipeline_executions.py +451 -451
- dtlpy/repositories/pipelines.py +640 -640
- dtlpy/repositories/projects.py +539 -539
- dtlpy/repositories/recipes.py +419 -399
- dtlpy/repositories/resource_executions.py +137 -137
- dtlpy/repositories/schema.py +120 -120
- dtlpy/repositories/service_drivers.py +213 -213
- dtlpy/repositories/services.py +1704 -1704
- dtlpy/repositories/settings.py +339 -339
- dtlpy/repositories/tasks.py +1477 -1477
- dtlpy/repositories/times_series.py +278 -278
- dtlpy/repositories/triggers.py +536 -536
- dtlpy/repositories/upload_element.py +257 -257
- dtlpy/repositories/uploader.py +661 -661
- dtlpy/repositories/webhooks.py +249 -249
- dtlpy/services/__init__.py +22 -22
- dtlpy/services/aihttp_retry.py +131 -131
- dtlpy/services/api_client.py +1785 -1785
- dtlpy/services/api_reference.py +40 -40
- dtlpy/services/async_utils.py +133 -133
- dtlpy/services/calls_counter.py +44 -44
- dtlpy/services/check_sdk.py +68 -68
- dtlpy/services/cookie.py +115 -115
- dtlpy/services/create_logger.py +156 -156
- dtlpy/services/events.py +84 -84
- dtlpy/services/logins.py +235 -235
- dtlpy/services/reporter.py +256 -256
- dtlpy/services/service_defaults.py +91 -91
- dtlpy/utilities/__init__.py +20 -20
- dtlpy/utilities/annotations/__init__.py +16 -16
- dtlpy/utilities/annotations/annotation_converters.py +269 -269
- dtlpy/utilities/base_package_runner.py +285 -264
- dtlpy/utilities/converter.py +1650 -1650
- dtlpy/utilities/dataset_generators/__init__.py +1 -1
- dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
- dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
- dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
- dtlpy/utilities/local_development/__init__.py +1 -1
- dtlpy/utilities/local_development/local_session.py +179 -179
- dtlpy/utilities/reports/__init__.py +2 -2
- dtlpy/utilities/reports/figures.py +343 -343
- dtlpy/utilities/reports/report.py +71 -71
- dtlpy/utilities/videos/__init__.py +17 -17
- dtlpy/utilities/videos/video_player.py +598 -598
- dtlpy/utilities/videos/videos.py +470 -470
- {dtlpy-1.115.44.data → dtlpy-1.116.6.data}/scripts/dlp +1 -1
- dtlpy-1.116.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.115.44.data → dtlpy-1.116.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/METADATA +186 -186
- dtlpy-1.116.6.dist-info/RECORD +239 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/licenses/LICENSE +200 -200
- tests/features/environment.py +551 -551
- dtlpy/assets/__pycache__/__init__.cpython-310.pyc +0 -0
- dtlpy-1.115.44.data/scripts/dlp.bat +0 -2
- dtlpy-1.115.44.dist-info/RECORD +0 -240
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/top_level.txt +0 -0
dtlpy/services/api_reference.py
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
class ApiReference(object):
|
|
2
|
-
|
|
3
|
-
def __init__(self):
|
|
4
|
-
self.references = {'paths': dict()}
|
|
5
|
-
|
|
6
|
-
def add(self, path, method):
|
|
7
|
-
def wrapper(f):
|
|
8
|
-
if path not in self.references['paths']:
|
|
9
|
-
self.references['paths'][path] = dict()
|
|
10
|
-
if method not in self.references['paths'][path]:
|
|
11
|
-
self.references['paths'][path][method] = dict()
|
|
12
|
-
|
|
13
|
-
docstring = f.__doc__
|
|
14
|
-
docstring = docstring.split('\n')
|
|
15
|
-
in_code = False
|
|
16
|
-
|
|
17
|
-
code_list = list()
|
|
18
|
-
docs_list = list()
|
|
19
|
-
for i_line in range(len(docstring)):
|
|
20
|
-
if '.. code-block::' in docstring[i_line]:
|
|
21
|
-
in_code = True
|
|
22
|
-
continue
|
|
23
|
-
if '**Example**' in docstring[i_line]:
|
|
24
|
-
continue
|
|
25
|
-
if docstring[i_line].startswith(' ') and not docstring[i_line].startswith(' '):
|
|
26
|
-
in_code = False
|
|
27
|
-
if in_code:
|
|
28
|
-
code_list.append('{}'.format(docstring[i_line].strip()))
|
|
29
|
-
else:
|
|
30
|
-
docs_list.append('# {}'.format(docstring[i_line].strip()))
|
|
31
|
-
# assert False
|
|
32
|
-
docstring = '\n'.join(code_list + docs_list)
|
|
33
|
-
self.references['paths'][path][method]['x-codeSamples'] = [{"lang": "Python",
|
|
34
|
-
"source": docstring}]
|
|
35
|
-
return f
|
|
36
|
-
|
|
37
|
-
return wrapper
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
api_reference = ApiReference()
|
|
1
|
+
class ApiReference(object):
|
|
2
|
+
|
|
3
|
+
def __init__(self):
|
|
4
|
+
self.references = {'paths': dict()}
|
|
5
|
+
|
|
6
|
+
def add(self, path, method):
|
|
7
|
+
def wrapper(f):
|
|
8
|
+
if path not in self.references['paths']:
|
|
9
|
+
self.references['paths'][path] = dict()
|
|
10
|
+
if method not in self.references['paths'][path]:
|
|
11
|
+
self.references['paths'][path][method] = dict()
|
|
12
|
+
|
|
13
|
+
docstring = f.__doc__
|
|
14
|
+
docstring = docstring.split('\n')
|
|
15
|
+
in_code = False
|
|
16
|
+
|
|
17
|
+
code_list = list()
|
|
18
|
+
docs_list = list()
|
|
19
|
+
for i_line in range(len(docstring)):
|
|
20
|
+
if '.. code-block::' in docstring[i_line]:
|
|
21
|
+
in_code = True
|
|
22
|
+
continue
|
|
23
|
+
if '**Example**' in docstring[i_line]:
|
|
24
|
+
continue
|
|
25
|
+
if docstring[i_line].startswith(' ') and not docstring[i_line].startswith(' '):
|
|
26
|
+
in_code = False
|
|
27
|
+
if in_code:
|
|
28
|
+
code_list.append('{}'.format(docstring[i_line].strip()))
|
|
29
|
+
else:
|
|
30
|
+
docs_list.append('# {}'.format(docstring[i_line].strip()))
|
|
31
|
+
# assert False
|
|
32
|
+
docstring = '\n'.join(code_list + docs_list)
|
|
33
|
+
self.references['paths'][path][method]['x-codeSamples'] = [{"lang": "Python",
|
|
34
|
+
"source": docstring}]
|
|
35
|
+
return f
|
|
36
|
+
|
|
37
|
+
return wrapper
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
api_reference = ApiReference()
|
dtlpy/services/async_utils.py
CHANGED
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
import asyncio
|
|
3
|
-
import logging
|
|
4
|
-
import io
|
|
5
|
-
|
|
6
|
-
logger = logging.getLogger(name='dtlpy')
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class AsyncThreadEventLoop(threading.Thread):
|
|
10
|
-
"""Thread class with a stop() method. The thread itself has to check
|
|
11
|
-
regularly for the stopped() condition."""
|
|
12
|
-
|
|
13
|
-
def __init__(self, loop, n, *args, **kwargs):
|
|
14
|
-
super(AsyncThreadEventLoop, self).__init__(*args, **kwargs)
|
|
15
|
-
self.loop = loop
|
|
16
|
-
self.n = n
|
|
17
|
-
self._count = 0
|
|
18
|
-
self._semaphores = dict()
|
|
19
|
-
|
|
20
|
-
def count_up(self):
|
|
21
|
-
self._count += 1
|
|
22
|
-
|
|
23
|
-
def count_down(self):
|
|
24
|
-
self._count -= 1
|
|
25
|
-
|
|
26
|
-
def run(self):
|
|
27
|
-
def exception_handler(loop, context):
|
|
28
|
-
logger.debug(
|
|
29
|
-
"[Asyc] EventLoop: caught the following exception: {}".format(context['message']))
|
|
30
|
-
|
|
31
|
-
self.loop.set_exception_handler(exception_handler)
|
|
32
|
-
asyncio.set_event_loop(self.loop)
|
|
33
|
-
self.loop.run_forever()
|
|
34
|
-
logger.debug('Ended event loop with bounded semaphore to {}'.format(self.n))
|
|
35
|
-
|
|
36
|
-
def semaphore(self, name, n=None):
|
|
37
|
-
if n is None:
|
|
38
|
-
n = self.n
|
|
39
|
-
else:
|
|
40
|
-
n = min(n, self.n)
|
|
41
|
-
if name not in self._semaphores:
|
|
42
|
-
self._semaphores[name] = asyncio.BoundedSemaphore(n)
|
|
43
|
-
return self._semaphores[name]
|
|
44
|
-
|
|
45
|
-
def stop(self):
|
|
46
|
-
self.loop.call_soon_threadsafe(self.loop.stop) # here
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class AsyncResponse:
|
|
50
|
-
def __init__(self, text, _json, async_resp):
|
|
51
|
-
self.text = text
|
|
52
|
-
self._json = _json
|
|
53
|
-
self.async_resp = async_resp
|
|
54
|
-
|
|
55
|
-
def json(self):
|
|
56
|
-
return self._json
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def status_code(self):
|
|
60
|
-
return self.async_resp.status
|
|
61
|
-
|
|
62
|
-
@property
|
|
63
|
-
def reason(self):
|
|
64
|
-
return self.async_resp.reason
|
|
65
|
-
|
|
66
|
-
@property
|
|
67
|
-
def ok(self):
|
|
68
|
-
return self.async_resp.status < 400
|
|
69
|
-
|
|
70
|
-
@property
|
|
71
|
-
def request(self):
|
|
72
|
-
return self.async_resp.request_info
|
|
73
|
-
|
|
74
|
-
@property
|
|
75
|
-
def headers(self):
|
|
76
|
-
return self.async_resp.headers
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class DummyErrorResponse:
|
|
80
|
-
def __init__(self, error, trace):
|
|
81
|
-
self.status = 3001 # SDK Error
|
|
82
|
-
self.reason = trace
|
|
83
|
-
self.error = error
|
|
84
|
-
self.request_info = {}
|
|
85
|
-
self.headers = {}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
class AsyncResponseError(AsyncResponse):
|
|
89
|
-
def __init__(self, error, trace):
|
|
90
|
-
async_resp = DummyErrorResponse(error=error, trace=trace)
|
|
91
|
-
_json = {'error': error}
|
|
92
|
-
text = error
|
|
93
|
-
super().__init__(async_resp=async_resp,
|
|
94
|
-
_json=_json,
|
|
95
|
-
text=text)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
class AsyncUploadStream(io.IOBase):
|
|
99
|
-
def __init__(self, buffer, callback=None, name='', chunk_timeout=10, max_retries=3):
|
|
100
|
-
self.buffer = buffer
|
|
101
|
-
self.buffer.seek(0)
|
|
102
|
-
self.callback = callback
|
|
103
|
-
self._name = name
|
|
104
|
-
self.chunk_timeout = chunk_timeout
|
|
105
|
-
self.max_retries = max_retries
|
|
106
|
-
|
|
107
|
-
@property
|
|
108
|
-
def name(self):
|
|
109
|
-
return self._name
|
|
110
|
-
|
|
111
|
-
async def async_read(self, size):
|
|
112
|
-
retries = 0
|
|
113
|
-
while retries < self.max_retries:
|
|
114
|
-
try:
|
|
115
|
-
import sys
|
|
116
|
-
if sys.version_info < (3, 9):
|
|
117
|
-
loop = asyncio.get_event_loop()
|
|
118
|
-
data = await asyncio.wait_for(loop.run_in_executor(None, self.buffer.read, size),
|
|
119
|
-
timeout=self.chunk_timeout)
|
|
120
|
-
else:
|
|
121
|
-
data = await asyncio.wait_for(asyncio.to_thread(self.buffer.read, size), timeout=self.chunk_timeout)
|
|
122
|
-
if self.callback is not None:
|
|
123
|
-
self.callback(size)
|
|
124
|
-
return data
|
|
125
|
-
except asyncio.TimeoutError:
|
|
126
|
-
retries += 1
|
|
127
|
-
logger.warning(
|
|
128
|
-
f"Chunk read timed out after {self.chunk_timeout} seconds. Retrying {retries}/{self.max_retries}...")
|
|
129
|
-
|
|
130
|
-
raise Exception(f"Chunk read failed after {self.max_retries} retries due to timeouts")
|
|
131
|
-
|
|
132
|
-
def read(self, size):
|
|
133
|
-
return asyncio.run(self.async_read(size))
|
|
1
|
+
import threading
|
|
2
|
+
import asyncio
|
|
3
|
+
import logging
|
|
4
|
+
import io
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(name='dtlpy')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AsyncThreadEventLoop(threading.Thread):
|
|
10
|
+
"""Thread class with a stop() method. The thread itself has to check
|
|
11
|
+
regularly for the stopped() condition."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, loop, n, *args, **kwargs):
|
|
14
|
+
super(AsyncThreadEventLoop, self).__init__(*args, **kwargs)
|
|
15
|
+
self.loop = loop
|
|
16
|
+
self.n = n
|
|
17
|
+
self._count = 0
|
|
18
|
+
self._semaphores = dict()
|
|
19
|
+
|
|
20
|
+
def count_up(self):
|
|
21
|
+
self._count += 1
|
|
22
|
+
|
|
23
|
+
def count_down(self):
|
|
24
|
+
self._count -= 1
|
|
25
|
+
|
|
26
|
+
def run(self):
|
|
27
|
+
def exception_handler(loop, context):
|
|
28
|
+
logger.debug(
|
|
29
|
+
"[Asyc] EventLoop: caught the following exception: {}".format(context['message']))
|
|
30
|
+
|
|
31
|
+
self.loop.set_exception_handler(exception_handler)
|
|
32
|
+
asyncio.set_event_loop(self.loop)
|
|
33
|
+
self.loop.run_forever()
|
|
34
|
+
logger.debug('Ended event loop with bounded semaphore to {}'.format(self.n))
|
|
35
|
+
|
|
36
|
+
def semaphore(self, name, n=None):
|
|
37
|
+
if n is None:
|
|
38
|
+
n = self.n
|
|
39
|
+
else:
|
|
40
|
+
n = min(n, self.n)
|
|
41
|
+
if name not in self._semaphores:
|
|
42
|
+
self._semaphores[name] = asyncio.BoundedSemaphore(n)
|
|
43
|
+
return self._semaphores[name]
|
|
44
|
+
|
|
45
|
+
def stop(self):
|
|
46
|
+
self.loop.call_soon_threadsafe(self.loop.stop) # here
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class AsyncResponse:
|
|
50
|
+
def __init__(self, text, _json, async_resp):
|
|
51
|
+
self.text = text
|
|
52
|
+
self._json = _json
|
|
53
|
+
self.async_resp = async_resp
|
|
54
|
+
|
|
55
|
+
def json(self):
|
|
56
|
+
return self._json
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def status_code(self):
|
|
60
|
+
return self.async_resp.status
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def reason(self):
|
|
64
|
+
return self.async_resp.reason
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def ok(self):
|
|
68
|
+
return self.async_resp.status < 400
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def request(self):
|
|
72
|
+
return self.async_resp.request_info
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def headers(self):
|
|
76
|
+
return self.async_resp.headers
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class DummyErrorResponse:
|
|
80
|
+
def __init__(self, error, trace):
|
|
81
|
+
self.status = 3001 # SDK Error
|
|
82
|
+
self.reason = trace
|
|
83
|
+
self.error = error
|
|
84
|
+
self.request_info = {}
|
|
85
|
+
self.headers = {}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class AsyncResponseError(AsyncResponse):
|
|
89
|
+
def __init__(self, error, trace):
|
|
90
|
+
async_resp = DummyErrorResponse(error=error, trace=trace)
|
|
91
|
+
_json = {'error': error}
|
|
92
|
+
text = error
|
|
93
|
+
super().__init__(async_resp=async_resp,
|
|
94
|
+
_json=_json,
|
|
95
|
+
text=text)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class AsyncUploadStream(io.IOBase):
|
|
99
|
+
def __init__(self, buffer, callback=None, name='', chunk_timeout=10, max_retries=3):
|
|
100
|
+
self.buffer = buffer
|
|
101
|
+
self.buffer.seek(0)
|
|
102
|
+
self.callback = callback
|
|
103
|
+
self._name = name
|
|
104
|
+
self.chunk_timeout = chunk_timeout
|
|
105
|
+
self.max_retries = max_retries
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def name(self):
|
|
109
|
+
return self._name
|
|
110
|
+
|
|
111
|
+
async def async_read(self, size):
|
|
112
|
+
retries = 0
|
|
113
|
+
while retries < self.max_retries:
|
|
114
|
+
try:
|
|
115
|
+
import sys
|
|
116
|
+
if sys.version_info < (3, 9):
|
|
117
|
+
loop = asyncio.get_event_loop()
|
|
118
|
+
data = await asyncio.wait_for(loop.run_in_executor(None, self.buffer.read, size),
|
|
119
|
+
timeout=self.chunk_timeout)
|
|
120
|
+
else:
|
|
121
|
+
data = await asyncio.wait_for(asyncio.to_thread(self.buffer.read, size), timeout=self.chunk_timeout)
|
|
122
|
+
if self.callback is not None:
|
|
123
|
+
self.callback(size)
|
|
124
|
+
return data
|
|
125
|
+
except asyncio.TimeoutError:
|
|
126
|
+
retries += 1
|
|
127
|
+
logger.warning(
|
|
128
|
+
f"Chunk read timed out after {self.chunk_timeout} seconds. Retrying {retries}/{self.max_retries}...")
|
|
129
|
+
|
|
130
|
+
raise Exception(f"Chunk read failed after {self.max_retries} retries due to timeouts")
|
|
131
|
+
|
|
132
|
+
def read(self, size):
|
|
133
|
+
return asyncio.run(self.async_read(size))
|
dtlpy/services/calls_counter.py
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
from .cookie import CookieIO
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class CallsCounter:
|
|
5
|
-
def __init__(self, filepath):
|
|
6
|
-
self.io = CookieIO(filepath)
|
|
7
|
-
self.state = 'off'
|
|
8
|
-
self.number = 0
|
|
9
|
-
self.load()
|
|
10
|
-
|
|
11
|
-
def add(self):
|
|
12
|
-
if self.state == 'on':
|
|
13
|
-
self.load()
|
|
14
|
-
self.number += 1
|
|
15
|
-
self.save()
|
|
16
|
-
|
|
17
|
-
def reset(self):
|
|
18
|
-
self.number = 0
|
|
19
|
-
self.save()
|
|
20
|
-
|
|
21
|
-
def save(self):
|
|
22
|
-
self.io.put('calls_counter', {'state': self.state,
|
|
23
|
-
'number': self.number})
|
|
24
|
-
|
|
25
|
-
def on(self):
|
|
26
|
-
self.state = 'on'
|
|
27
|
-
self.save()
|
|
28
|
-
|
|
29
|
-
def off(self):
|
|
30
|
-
self.state = 'off'
|
|
31
|
-
self.save()
|
|
32
|
-
|
|
33
|
-
def on_exit(self):
|
|
34
|
-
self.save()
|
|
35
|
-
|
|
36
|
-
def load(self):
|
|
37
|
-
calls = self.io.get('calls_counter')
|
|
38
|
-
if calls is None:
|
|
39
|
-
# not set in cookie - set default
|
|
40
|
-
calls = {'state': 'off',
|
|
41
|
-
'number': 0}
|
|
42
|
-
self.io.put('calls_counter', calls)
|
|
43
|
-
self.state = calls['state']
|
|
44
|
-
self.number = calls['number']
|
|
1
|
+
from .cookie import CookieIO
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CallsCounter:
|
|
5
|
+
def __init__(self, filepath):
|
|
6
|
+
self.io = CookieIO(filepath)
|
|
7
|
+
self.state = 'off'
|
|
8
|
+
self.number = 0
|
|
9
|
+
self.load()
|
|
10
|
+
|
|
11
|
+
def add(self):
|
|
12
|
+
if self.state == 'on':
|
|
13
|
+
self.load()
|
|
14
|
+
self.number += 1
|
|
15
|
+
self.save()
|
|
16
|
+
|
|
17
|
+
def reset(self):
|
|
18
|
+
self.number = 0
|
|
19
|
+
self.save()
|
|
20
|
+
|
|
21
|
+
def save(self):
|
|
22
|
+
self.io.put('calls_counter', {'state': self.state,
|
|
23
|
+
'number': self.number})
|
|
24
|
+
|
|
25
|
+
def on(self):
|
|
26
|
+
self.state = 'on'
|
|
27
|
+
self.save()
|
|
28
|
+
|
|
29
|
+
def off(self):
|
|
30
|
+
self.state = 'off'
|
|
31
|
+
self.save()
|
|
32
|
+
|
|
33
|
+
def on_exit(self):
|
|
34
|
+
self.save()
|
|
35
|
+
|
|
36
|
+
def load(self):
|
|
37
|
+
calls = self.io.get('calls_counter')
|
|
38
|
+
if calls is None:
|
|
39
|
+
# not set in cookie - set default
|
|
40
|
+
calls = {'state': 'off',
|
|
41
|
+
'number': 0}
|
|
42
|
+
self.io.put('calls_counter', calls)
|
|
43
|
+
self.state = calls['state']
|
|
44
|
+
self.number = calls['number']
|
dtlpy/services/check_sdk.py
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import logging
|
|
3
|
-
import threading
|
|
4
|
-
import traceback
|
|
5
|
-
import jwt
|
|
6
|
-
|
|
7
|
-
logger = logging.getLogger(name='dtlpy')
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def check_in_thread(version, client_api):
|
|
11
|
-
try:
|
|
12
|
-
# check for a valid token
|
|
13
|
-
if client_api.token_expired():
|
|
14
|
-
# wait for user to maybe login in the next 2 minutes
|
|
15
|
-
time.sleep(120)
|
|
16
|
-
# check for a valid token again
|
|
17
|
-
if client_api.token_expired():
|
|
18
|
-
# return if cant find a valid token
|
|
19
|
-
logger.debug('Cant check_sdk without a valid token.')
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
# try read token for email
|
|
23
|
-
try:
|
|
24
|
-
payload = jwt.decode(client_api.token, algorithms=['HS256'],
|
|
25
|
-
verify=False, options={'verify_signature': False})
|
|
26
|
-
user_email = payload['email']
|
|
27
|
-
except Exception:
|
|
28
|
-
user_email = 'na'
|
|
29
|
-
logger.debug('SDK info: user: {}, version: {}'.format(user_email, version))
|
|
30
|
-
return_type, resp = client_api.gen_request(req_type='POST',
|
|
31
|
-
path='/sdk/check',
|
|
32
|
-
data={'version': version,
|
|
33
|
-
'email': user_email},
|
|
34
|
-
log_error=False)
|
|
35
|
-
if resp.ok:
|
|
36
|
-
resp = resp.json()
|
|
37
|
-
client_api.cookie_io.put(key='check_version_status',
|
|
38
|
-
value={'level': resp['level'],
|
|
39
|
-
'msg': resp['msg']})
|
|
40
|
-
else:
|
|
41
|
-
client_api.cookie_io.put(key='check_version_status',
|
|
42
|
-
value={'level': 'debug',
|
|
43
|
-
'msg': 'unknown'})
|
|
44
|
-
except Exception:
|
|
45
|
-
logger.debug(traceback.format_exc())
|
|
46
|
-
logger.debug('Error in check sdk manager.')
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def check(version, client_api):
|
|
50
|
-
worker = threading.Thread(target=check_in_thread,
|
|
51
|
-
kwargs={'version': version,
|
|
52
|
-
'client_api': client_api})
|
|
53
|
-
worker.daemon = True
|
|
54
|
-
worker.start()
|
|
55
|
-
status = client_api.cookie_io.get('check_version_status')
|
|
56
|
-
if status is not None:
|
|
57
|
-
level = status['level']
|
|
58
|
-
msg = status['msg']
|
|
59
|
-
if level.lower() == 'debug':
|
|
60
|
-
logger.debug(msg=msg)
|
|
61
|
-
elif level.lower() == 'info':
|
|
62
|
-
logger.info(msg=msg)
|
|
63
|
-
elif level.lower() == 'warning':
|
|
64
|
-
logger.warning(msg=msg)
|
|
65
|
-
elif level.lower() == 'error':
|
|
66
|
-
logger.error(msg=msg)
|
|
67
|
-
else:
|
|
68
|
-
logger.debug(msg='unknown')
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
3
|
+
import threading
|
|
4
|
+
import traceback
|
|
5
|
+
import jwt
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(name='dtlpy')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def check_in_thread(version, client_api):
|
|
11
|
+
try:
|
|
12
|
+
# check for a valid token
|
|
13
|
+
if client_api.token_expired():
|
|
14
|
+
# wait for user to maybe login in the next 2 minutes
|
|
15
|
+
time.sleep(120)
|
|
16
|
+
# check for a valid token again
|
|
17
|
+
if client_api.token_expired():
|
|
18
|
+
# return if cant find a valid token
|
|
19
|
+
logger.debug('Cant check_sdk without a valid token.')
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
# try read token for email
|
|
23
|
+
try:
|
|
24
|
+
payload = jwt.decode(client_api.token, algorithms=['HS256'],
|
|
25
|
+
verify=False, options={'verify_signature': False})
|
|
26
|
+
user_email = payload['email']
|
|
27
|
+
except Exception:
|
|
28
|
+
user_email = 'na'
|
|
29
|
+
logger.debug('SDK info: user: {}, version: {}'.format(user_email, version))
|
|
30
|
+
return_type, resp = client_api.gen_request(req_type='POST',
|
|
31
|
+
path='/sdk/check',
|
|
32
|
+
data={'version': version,
|
|
33
|
+
'email': user_email},
|
|
34
|
+
log_error=False)
|
|
35
|
+
if resp.ok:
|
|
36
|
+
resp = resp.json()
|
|
37
|
+
client_api.cookie_io.put(key='check_version_status',
|
|
38
|
+
value={'level': resp['level'],
|
|
39
|
+
'msg': resp['msg']})
|
|
40
|
+
else:
|
|
41
|
+
client_api.cookie_io.put(key='check_version_status',
|
|
42
|
+
value={'level': 'debug',
|
|
43
|
+
'msg': 'unknown'})
|
|
44
|
+
except Exception:
|
|
45
|
+
logger.debug(traceback.format_exc())
|
|
46
|
+
logger.debug('Error in check sdk manager.')
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def check(version, client_api):
|
|
50
|
+
worker = threading.Thread(target=check_in_thread,
|
|
51
|
+
kwargs={'version': version,
|
|
52
|
+
'client_api': client_api})
|
|
53
|
+
worker.daemon = True
|
|
54
|
+
worker.start()
|
|
55
|
+
status = client_api.cookie_io.get('check_version_status')
|
|
56
|
+
if status is not None:
|
|
57
|
+
level = status['level']
|
|
58
|
+
msg = status['msg']
|
|
59
|
+
if level.lower() == 'debug':
|
|
60
|
+
logger.debug(msg=msg)
|
|
61
|
+
elif level.lower() == 'info':
|
|
62
|
+
logger.info(msg=msg)
|
|
63
|
+
elif level.lower() == 'warning':
|
|
64
|
+
logger.warning(msg=msg)
|
|
65
|
+
elif level.lower() == 'error':
|
|
66
|
+
logger.error(msg=msg)
|
|
67
|
+
else:
|
|
68
|
+
logger.debug(msg='unknown')
|