dtlpy 1.114.17__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 -311
- 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 -296
- dtlpy/entities/collection.py +38 -38
- dtlpy/entities/command.py +169 -169
- dtlpy/entities/compute.py +449 -442
- dtlpy/entities/dataset.py +1299 -1285
- dtlpy/entities/directory_tree.py +44 -44
- dtlpy/entities/dpk.py +470 -470
- dtlpy/entities/driver.py +235 -223
- dtlpy/entities/execution.py +397 -397
- dtlpy/entities/feature.py +124 -124
- dtlpy/entities/feature_set.py +145 -145
- dtlpy/entities/filters.py +798 -645
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +959 -953
- 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 -499
- 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 -958
- 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 -1086
- 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 -158
- dtlpy/repositories/compositions.py +61 -61
- dtlpy/repositories/computes.py +439 -435
- dtlpy/repositories/datasets.py +1504 -1291
- dtlpy/repositories/downloader.py +976 -903
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -470
- dtlpy/repositories/executions.py +815 -817
- dtlpy/repositories/feature_sets.py +226 -226
- dtlpy/repositories/features.py +255 -238
- dtlpy/repositories/integrations.py +484 -484
- dtlpy/repositories/items.py +912 -909
- dtlpy/repositories/messages.py +94 -94
- dtlpy/repositories/models.py +1000 -988
- 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 -651
- 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 -1782
- 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.114.17.data → dtlpy-1.116.6.data}/scripts/dlp +1 -1
- dtlpy-1.116.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.114.17.data → dtlpy-1.116.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/METADATA +186 -183
- dtlpy-1.116.6.dist-info/RECORD +239 -0
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.114.17.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.114.17.data/scripts/dlp.bat +0 -2
- dtlpy-1.114.17.dist-info/RECORD +0 -240
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/top_level.txt +0 -0
|
@@ -1,278 +1,278 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import datetime
|
|
4
|
-
from dtlpy import entities, miscellaneous, exceptions
|
|
5
|
-
from ..services.api_client import ApiClient
|
|
6
|
-
|
|
7
|
-
logger = logging.getLogger(name='dtlpy')
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class TimesSeries:
|
|
11
|
-
"""
|
|
12
|
-
Time series Repository
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def __init__(self, client_api: ApiClient, project: entities.Project = None):
|
|
16
|
-
self._client_api = client_api
|
|
17
|
-
self._project = project
|
|
18
|
-
|
|
19
|
-
############
|
|
20
|
-
# entities #
|
|
21
|
-
############
|
|
22
|
-
@property
|
|
23
|
-
def project(self) -> entities.Project:
|
|
24
|
-
if self._project is None:
|
|
25
|
-
raise exceptions.PlatformException(
|
|
26
|
-
error='2001',
|
|
27
|
-
message='Missing "project". need to set a Project entity or use project.times_series repository')
|
|
28
|
-
assert isinstance(self._project, entities.Project)
|
|
29
|
-
return self._project
|
|
30
|
-
|
|
31
|
-
@project.setter
|
|
32
|
-
def project(self, project: entities.Project):
|
|
33
|
-
if not isinstance(project, entities.Project):
|
|
34
|
-
raise ValueError('Must input a valid Project entity')
|
|
35
|
-
self._project = project
|
|
36
|
-
|
|
37
|
-
############
|
|
38
|
-
# methods #
|
|
39
|
-
############
|
|
40
|
-
def create(self, series_name) -> entities.TimeSeries:
|
|
41
|
-
"""
|
|
42
|
-
Create a new time series
|
|
43
|
-
|
|
44
|
-
:param str series_name: name
|
|
45
|
-
:return: TimeSeries object
|
|
46
|
-
"""
|
|
47
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
48
|
-
path='/projects/{}/timeSeries'.format(self.project.id),
|
|
49
|
-
json_req={'name': series_name})
|
|
50
|
-
if success:
|
|
51
|
-
ts = entities.TimeSeries.from_json(_json=response.json(),
|
|
52
|
-
project=self.project)
|
|
53
|
-
else:
|
|
54
|
-
raise exceptions.PlatformException(response)
|
|
55
|
-
assert isinstance(ts, entities.TimeSeries)
|
|
56
|
-
return ts
|
|
57
|
-
|
|
58
|
-
def list(self) -> miscellaneous.List[entities.TimeSeries]:
|
|
59
|
-
"""
|
|
60
|
-
List all time series for project
|
|
61
|
-
|
|
62
|
-
:return:
|
|
63
|
-
"""
|
|
64
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
65
|
-
path='/projects/{}/timeSeries'.format(self.project.id))
|
|
66
|
-
if success:
|
|
67
|
-
tss = miscellaneous.List([entities.TimeSeries.from_json(_json=_json, project=self.project)
|
|
68
|
-
for _json in response.json()])
|
|
69
|
-
else:
|
|
70
|
-
raise exceptions.PlatformException(response)
|
|
71
|
-
return tss
|
|
72
|
-
|
|
73
|
-
def get(self, series_name=None, series_id=None) -> entities.TimeSeries:
|
|
74
|
-
"""
|
|
75
|
-
Get time series entity
|
|
76
|
-
|
|
77
|
-
:param str series_name: by name
|
|
78
|
-
:param str series_id: by id
|
|
79
|
-
:return:
|
|
80
|
-
"""
|
|
81
|
-
if series_id is not None:
|
|
82
|
-
# get series
|
|
83
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
84
|
-
path='/projects/{}/timeSeries/{}'.format(self.project.id,
|
|
85
|
-
series_id))
|
|
86
|
-
if success:
|
|
87
|
-
ts = entities.TimeSeries.from_json(_json=response.json(),
|
|
88
|
-
project=self.project)
|
|
89
|
-
else:
|
|
90
|
-
raise exceptions.PlatformException(response)
|
|
91
|
-
# verify input service name is same as the given id
|
|
92
|
-
if series_name is not None and ts.name != series_name:
|
|
93
|
-
logger.warning(
|
|
94
|
-
"Mismatch found in timeSeries.get: series_name is different then timeSeries.name:"
|
|
95
|
-
" {!r} != {!r}".format(
|
|
96
|
-
series_name,
|
|
97
|
-
ts.name))
|
|
98
|
-
elif series_name is not None:
|
|
99
|
-
tss = self.list()
|
|
100
|
-
ts = [ts for ts in tss if ts.name == series_name]
|
|
101
|
-
if not ts:
|
|
102
|
-
# empty list
|
|
103
|
-
raise exceptions.PlatformException(error='404',
|
|
104
|
-
message='Time Series not found. Name: {}'.format(series_name))
|
|
105
|
-
elif len(ts) > 1:
|
|
106
|
-
raise exceptions.PlatformException(error='400',
|
|
107
|
-
message='More than one Time Series with same name.')
|
|
108
|
-
else:
|
|
109
|
-
ts = ts[0]
|
|
110
|
-
else:
|
|
111
|
-
raise exceptions.PlatformException(error='400',
|
|
112
|
-
message='Must choose by "series_id" or "series_name"')
|
|
113
|
-
assert isinstance(ts, entities.TimeSeries)
|
|
114
|
-
return ts
|
|
115
|
-
|
|
116
|
-
def delete(self, series_id=None, series=None):
|
|
117
|
-
"""
|
|
118
|
-
Delete a Time Series
|
|
119
|
-
|
|
120
|
-
:param str series_id: optional - search by id
|
|
121
|
-
:param series: optional - TimeSeries object
|
|
122
|
-
:return: True
|
|
123
|
-
:rtype: bool
|
|
124
|
-
"""
|
|
125
|
-
if series_id is not None:
|
|
126
|
-
pass
|
|
127
|
-
elif series is not None and isinstance(series, entities.TimeSeries):
|
|
128
|
-
series_id = series.id
|
|
129
|
-
else:
|
|
130
|
-
msg = 'Must choose by at least one of: "series_id", "series"'
|
|
131
|
-
logger.error(msg)
|
|
132
|
-
raise ValueError(msg)
|
|
133
|
-
success, response = self._client_api.gen_request(req_type='delete',
|
|
134
|
-
path='/projects/{}/timeSeries/{}'.format(self.project.id,
|
|
135
|
-
series_id))
|
|
136
|
-
if not success:
|
|
137
|
-
raise exceptions.PlatformException(response)
|
|
138
|
-
logger.info('Time series id {} deleted successfully'.format(series_id))
|
|
139
|
-
return True
|
|
140
|
-
|
|
141
|
-
#########
|
|
142
|
-
# Table #
|
|
143
|
-
#########
|
|
144
|
-
def delete_samples(self, series_id, filters):
|
|
145
|
-
"""
|
|
146
|
-
Delete samples from table
|
|
147
|
-
|
|
148
|
-
:param str series_id: time series id
|
|
149
|
-
:param dtlpy.entities.filters.Filters filters: query to delete by
|
|
150
|
-
:return:
|
|
151
|
-
"""
|
|
152
|
-
filters = self._validate_query(query=filters)
|
|
153
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
154
|
-
path='/projects/{}/timeSeries/{}/remove'.format(
|
|
155
|
-
self.project.id,
|
|
156
|
-
series_id),
|
|
157
|
-
json_req=filters)
|
|
158
|
-
if not success:
|
|
159
|
-
raise exceptions.PlatformException(response)
|
|
160
|
-
return True
|
|
161
|
-
|
|
162
|
-
@staticmethod
|
|
163
|
-
def _validate_query(query):
|
|
164
|
-
default_start_time = 0
|
|
165
|
-
default_end_time = datetime.datetime.now().timestamp() * 1000
|
|
166
|
-
|
|
167
|
-
if query is None:
|
|
168
|
-
query = dict(startTime=default_start_time, endTime=default_end_time)
|
|
169
|
-
else:
|
|
170
|
-
query['startTime'] = query.get('startTime', default_start_time)
|
|
171
|
-
query['endTime'] = query.get('endTime', default_end_time)
|
|
172
|
-
|
|
173
|
-
return query
|
|
174
|
-
|
|
175
|
-
def get_samples(self, series_id, filters=None) -> pd.DataFrame:
|
|
176
|
-
"""
|
|
177
|
-
Get Series table
|
|
178
|
-
|
|
179
|
-
:param str series_id: TimeSeries id
|
|
180
|
-
:param dtlpy.entities.filters.Filters filters: match filters to get specific data from series
|
|
181
|
-
:return:
|
|
182
|
-
"""
|
|
183
|
-
filters = self._validate_query(query=filters)
|
|
184
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
185
|
-
path='/projects/{}/timeSeries/{}/query'.format(self.project.id,
|
|
186
|
-
series_id),
|
|
187
|
-
json_req=filters)
|
|
188
|
-
if success:
|
|
189
|
-
res = response.json()['samples']
|
|
190
|
-
if isinstance(res, dict):
|
|
191
|
-
df = pd.DataFrame([res])
|
|
192
|
-
elif isinstance(res, list):
|
|
193
|
-
df = pd.DataFrame(res)
|
|
194
|
-
else:
|
|
195
|
-
raise ValueError('unknown return type for time series: {}'.format(type(res)))
|
|
196
|
-
else:
|
|
197
|
-
raise exceptions.PlatformException(response)
|
|
198
|
-
return df
|
|
199
|
-
|
|
200
|
-
def add_samples(self, series_id, data):
|
|
201
|
-
"""
|
|
202
|
-
Add samples to series
|
|
203
|
-
|
|
204
|
-
:param str series_id: TimeSeries id
|
|
205
|
-
:param data: list or dictionary of samples
|
|
206
|
-
:return:
|
|
207
|
-
"""
|
|
208
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
209
|
-
path='/projects/{}/timeSeries/{}/add'.format(self.project.id,
|
|
210
|
-
series_id),
|
|
211
|
-
json_req=data)
|
|
212
|
-
|
|
213
|
-
if not success:
|
|
214
|
-
raise exceptions.PlatformException(response)
|
|
215
|
-
return response.json()
|
|
216
|
-
|
|
217
|
-
######################
|
|
218
|
-
# Samples Operations #
|
|
219
|
-
######################
|
|
220
|
-
def get_sample(self, series_id, sample_id) -> pd.DataFrame:
|
|
221
|
-
"""
|
|
222
|
-
Get single sample from series
|
|
223
|
-
|
|
224
|
-
:param str series_id: TimeSeries id
|
|
225
|
-
:param str sample_id: id of sample line
|
|
226
|
-
:return:
|
|
227
|
-
"""
|
|
228
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
229
|
-
path='/projects/{}/timeSeries/{}/samples/{}'.format(
|
|
230
|
-
self.project.id,
|
|
231
|
-
series_id,
|
|
232
|
-
sample_id))
|
|
233
|
-
if success:
|
|
234
|
-
res = response.json()
|
|
235
|
-
if isinstance(res, dict):
|
|
236
|
-
df = pd.DataFrame([res])
|
|
237
|
-
elif isinstance(res, list):
|
|
238
|
-
df = pd.DataFrame(res)
|
|
239
|
-
else:
|
|
240
|
-
raise ValueError('unknown return type for time series: {}'.format(type(res)))
|
|
241
|
-
else:
|
|
242
|
-
raise exceptions.PlatformException(response)
|
|
243
|
-
return df
|
|
244
|
-
|
|
245
|
-
def update_sample(self, series_id, sample_id, data):
|
|
246
|
-
"""
|
|
247
|
-
Add data to existing sample
|
|
248
|
-
|
|
249
|
-
:param str series_id: time series id
|
|
250
|
-
:param str sample_id: sample line id
|
|
251
|
-
:param dict data: dictionary
|
|
252
|
-
:return:
|
|
253
|
-
"""
|
|
254
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
255
|
-
path='/projects/{}/timeSeries/{}/samples/{}'.format(
|
|
256
|
-
self.project.id,
|
|
257
|
-
series_id,
|
|
258
|
-
sample_id),
|
|
259
|
-
json_req=data)
|
|
260
|
-
if not success:
|
|
261
|
-
raise exceptions.PlatformException(response)
|
|
262
|
-
|
|
263
|
-
def delete_sample(self, series_id, sample_id):
|
|
264
|
-
"""
|
|
265
|
-
Delete single samples form time series
|
|
266
|
-
|
|
267
|
-
:param str series_id:
|
|
268
|
-
:param str sample_id:
|
|
269
|
-
:return:
|
|
270
|
-
"""
|
|
271
|
-
success, response = self._client_api.gen_request(req_type='delete',
|
|
272
|
-
path='/projects/{}/timeSeries/{}/samples/{}'.format(
|
|
273
|
-
self.project.id,
|
|
274
|
-
series_id,
|
|
275
|
-
sample_id))
|
|
276
|
-
if not success:
|
|
277
|
-
raise exceptions.PlatformException(response)
|
|
278
|
-
return True
|
|
1
|
+
import logging
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import datetime
|
|
4
|
+
from dtlpy import entities, miscellaneous, exceptions
|
|
5
|
+
from ..services.api_client import ApiClient
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(name='dtlpy')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TimesSeries:
|
|
11
|
+
"""
|
|
12
|
+
Time series Repository
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, client_api: ApiClient, project: entities.Project = None):
|
|
16
|
+
self._client_api = client_api
|
|
17
|
+
self._project = project
|
|
18
|
+
|
|
19
|
+
############
|
|
20
|
+
# entities #
|
|
21
|
+
############
|
|
22
|
+
@property
|
|
23
|
+
def project(self) -> entities.Project:
|
|
24
|
+
if self._project is None:
|
|
25
|
+
raise exceptions.PlatformException(
|
|
26
|
+
error='2001',
|
|
27
|
+
message='Missing "project". need to set a Project entity or use project.times_series repository')
|
|
28
|
+
assert isinstance(self._project, entities.Project)
|
|
29
|
+
return self._project
|
|
30
|
+
|
|
31
|
+
@project.setter
|
|
32
|
+
def project(self, project: entities.Project):
|
|
33
|
+
if not isinstance(project, entities.Project):
|
|
34
|
+
raise ValueError('Must input a valid Project entity')
|
|
35
|
+
self._project = project
|
|
36
|
+
|
|
37
|
+
############
|
|
38
|
+
# methods #
|
|
39
|
+
############
|
|
40
|
+
def create(self, series_name) -> entities.TimeSeries:
|
|
41
|
+
"""
|
|
42
|
+
Create a new time series
|
|
43
|
+
|
|
44
|
+
:param str series_name: name
|
|
45
|
+
:return: TimeSeries object
|
|
46
|
+
"""
|
|
47
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
48
|
+
path='/projects/{}/timeSeries'.format(self.project.id),
|
|
49
|
+
json_req={'name': series_name})
|
|
50
|
+
if success:
|
|
51
|
+
ts = entities.TimeSeries.from_json(_json=response.json(),
|
|
52
|
+
project=self.project)
|
|
53
|
+
else:
|
|
54
|
+
raise exceptions.PlatformException(response)
|
|
55
|
+
assert isinstance(ts, entities.TimeSeries)
|
|
56
|
+
return ts
|
|
57
|
+
|
|
58
|
+
def list(self) -> miscellaneous.List[entities.TimeSeries]:
|
|
59
|
+
"""
|
|
60
|
+
List all time series for project
|
|
61
|
+
|
|
62
|
+
:return:
|
|
63
|
+
"""
|
|
64
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
65
|
+
path='/projects/{}/timeSeries'.format(self.project.id))
|
|
66
|
+
if success:
|
|
67
|
+
tss = miscellaneous.List([entities.TimeSeries.from_json(_json=_json, project=self.project)
|
|
68
|
+
for _json in response.json()])
|
|
69
|
+
else:
|
|
70
|
+
raise exceptions.PlatformException(response)
|
|
71
|
+
return tss
|
|
72
|
+
|
|
73
|
+
def get(self, series_name=None, series_id=None) -> entities.TimeSeries:
|
|
74
|
+
"""
|
|
75
|
+
Get time series entity
|
|
76
|
+
|
|
77
|
+
:param str series_name: by name
|
|
78
|
+
:param str series_id: by id
|
|
79
|
+
:return:
|
|
80
|
+
"""
|
|
81
|
+
if series_id is not None:
|
|
82
|
+
# get series
|
|
83
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
84
|
+
path='/projects/{}/timeSeries/{}'.format(self.project.id,
|
|
85
|
+
series_id))
|
|
86
|
+
if success:
|
|
87
|
+
ts = entities.TimeSeries.from_json(_json=response.json(),
|
|
88
|
+
project=self.project)
|
|
89
|
+
else:
|
|
90
|
+
raise exceptions.PlatformException(response)
|
|
91
|
+
# verify input service name is same as the given id
|
|
92
|
+
if series_name is not None and ts.name != series_name:
|
|
93
|
+
logger.warning(
|
|
94
|
+
"Mismatch found in timeSeries.get: series_name is different then timeSeries.name:"
|
|
95
|
+
" {!r} != {!r}".format(
|
|
96
|
+
series_name,
|
|
97
|
+
ts.name))
|
|
98
|
+
elif series_name is not None:
|
|
99
|
+
tss = self.list()
|
|
100
|
+
ts = [ts for ts in tss if ts.name == series_name]
|
|
101
|
+
if not ts:
|
|
102
|
+
# empty list
|
|
103
|
+
raise exceptions.PlatformException(error='404',
|
|
104
|
+
message='Time Series not found. Name: {}'.format(series_name))
|
|
105
|
+
elif len(ts) > 1:
|
|
106
|
+
raise exceptions.PlatformException(error='400',
|
|
107
|
+
message='More than one Time Series with same name.')
|
|
108
|
+
else:
|
|
109
|
+
ts = ts[0]
|
|
110
|
+
else:
|
|
111
|
+
raise exceptions.PlatformException(error='400',
|
|
112
|
+
message='Must choose by "series_id" or "series_name"')
|
|
113
|
+
assert isinstance(ts, entities.TimeSeries)
|
|
114
|
+
return ts
|
|
115
|
+
|
|
116
|
+
def delete(self, series_id=None, series=None):
|
|
117
|
+
"""
|
|
118
|
+
Delete a Time Series
|
|
119
|
+
|
|
120
|
+
:param str series_id: optional - search by id
|
|
121
|
+
:param series: optional - TimeSeries object
|
|
122
|
+
:return: True
|
|
123
|
+
:rtype: bool
|
|
124
|
+
"""
|
|
125
|
+
if series_id is not None:
|
|
126
|
+
pass
|
|
127
|
+
elif series is not None and isinstance(series, entities.TimeSeries):
|
|
128
|
+
series_id = series.id
|
|
129
|
+
else:
|
|
130
|
+
msg = 'Must choose by at least one of: "series_id", "series"'
|
|
131
|
+
logger.error(msg)
|
|
132
|
+
raise ValueError(msg)
|
|
133
|
+
success, response = self._client_api.gen_request(req_type='delete',
|
|
134
|
+
path='/projects/{}/timeSeries/{}'.format(self.project.id,
|
|
135
|
+
series_id))
|
|
136
|
+
if not success:
|
|
137
|
+
raise exceptions.PlatformException(response)
|
|
138
|
+
logger.info('Time series id {} deleted successfully'.format(series_id))
|
|
139
|
+
return True
|
|
140
|
+
|
|
141
|
+
#########
|
|
142
|
+
# Table #
|
|
143
|
+
#########
|
|
144
|
+
def delete_samples(self, series_id, filters):
|
|
145
|
+
"""
|
|
146
|
+
Delete samples from table
|
|
147
|
+
|
|
148
|
+
:param str series_id: time series id
|
|
149
|
+
:param dtlpy.entities.filters.Filters filters: query to delete by
|
|
150
|
+
:return:
|
|
151
|
+
"""
|
|
152
|
+
filters = self._validate_query(query=filters)
|
|
153
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
154
|
+
path='/projects/{}/timeSeries/{}/remove'.format(
|
|
155
|
+
self.project.id,
|
|
156
|
+
series_id),
|
|
157
|
+
json_req=filters)
|
|
158
|
+
if not success:
|
|
159
|
+
raise exceptions.PlatformException(response)
|
|
160
|
+
return True
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def _validate_query(query):
|
|
164
|
+
default_start_time = 0
|
|
165
|
+
default_end_time = datetime.datetime.now().timestamp() * 1000
|
|
166
|
+
|
|
167
|
+
if query is None:
|
|
168
|
+
query = dict(startTime=default_start_time, endTime=default_end_time)
|
|
169
|
+
else:
|
|
170
|
+
query['startTime'] = query.get('startTime', default_start_time)
|
|
171
|
+
query['endTime'] = query.get('endTime', default_end_time)
|
|
172
|
+
|
|
173
|
+
return query
|
|
174
|
+
|
|
175
|
+
def get_samples(self, series_id, filters=None) -> pd.DataFrame:
|
|
176
|
+
"""
|
|
177
|
+
Get Series table
|
|
178
|
+
|
|
179
|
+
:param str series_id: TimeSeries id
|
|
180
|
+
:param dtlpy.entities.filters.Filters filters: match filters to get specific data from series
|
|
181
|
+
:return:
|
|
182
|
+
"""
|
|
183
|
+
filters = self._validate_query(query=filters)
|
|
184
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
185
|
+
path='/projects/{}/timeSeries/{}/query'.format(self.project.id,
|
|
186
|
+
series_id),
|
|
187
|
+
json_req=filters)
|
|
188
|
+
if success:
|
|
189
|
+
res = response.json()['samples']
|
|
190
|
+
if isinstance(res, dict):
|
|
191
|
+
df = pd.DataFrame([res])
|
|
192
|
+
elif isinstance(res, list):
|
|
193
|
+
df = pd.DataFrame(res)
|
|
194
|
+
else:
|
|
195
|
+
raise ValueError('unknown return type for time series: {}'.format(type(res)))
|
|
196
|
+
else:
|
|
197
|
+
raise exceptions.PlatformException(response)
|
|
198
|
+
return df
|
|
199
|
+
|
|
200
|
+
def add_samples(self, series_id, data):
|
|
201
|
+
"""
|
|
202
|
+
Add samples to series
|
|
203
|
+
|
|
204
|
+
:param str series_id: TimeSeries id
|
|
205
|
+
:param data: list or dictionary of samples
|
|
206
|
+
:return:
|
|
207
|
+
"""
|
|
208
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
209
|
+
path='/projects/{}/timeSeries/{}/add'.format(self.project.id,
|
|
210
|
+
series_id),
|
|
211
|
+
json_req=data)
|
|
212
|
+
|
|
213
|
+
if not success:
|
|
214
|
+
raise exceptions.PlatformException(response)
|
|
215
|
+
return response.json()
|
|
216
|
+
|
|
217
|
+
######################
|
|
218
|
+
# Samples Operations #
|
|
219
|
+
######################
|
|
220
|
+
def get_sample(self, series_id, sample_id) -> pd.DataFrame:
|
|
221
|
+
"""
|
|
222
|
+
Get single sample from series
|
|
223
|
+
|
|
224
|
+
:param str series_id: TimeSeries id
|
|
225
|
+
:param str sample_id: id of sample line
|
|
226
|
+
:return:
|
|
227
|
+
"""
|
|
228
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
229
|
+
path='/projects/{}/timeSeries/{}/samples/{}'.format(
|
|
230
|
+
self.project.id,
|
|
231
|
+
series_id,
|
|
232
|
+
sample_id))
|
|
233
|
+
if success:
|
|
234
|
+
res = response.json()
|
|
235
|
+
if isinstance(res, dict):
|
|
236
|
+
df = pd.DataFrame([res])
|
|
237
|
+
elif isinstance(res, list):
|
|
238
|
+
df = pd.DataFrame(res)
|
|
239
|
+
else:
|
|
240
|
+
raise ValueError('unknown return type for time series: {}'.format(type(res)))
|
|
241
|
+
else:
|
|
242
|
+
raise exceptions.PlatformException(response)
|
|
243
|
+
return df
|
|
244
|
+
|
|
245
|
+
def update_sample(self, series_id, sample_id, data):
|
|
246
|
+
"""
|
|
247
|
+
Add data to existing sample
|
|
248
|
+
|
|
249
|
+
:param str series_id: time series id
|
|
250
|
+
:param str sample_id: sample line id
|
|
251
|
+
:param dict data: dictionary
|
|
252
|
+
:return:
|
|
253
|
+
"""
|
|
254
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
255
|
+
path='/projects/{}/timeSeries/{}/samples/{}'.format(
|
|
256
|
+
self.project.id,
|
|
257
|
+
series_id,
|
|
258
|
+
sample_id),
|
|
259
|
+
json_req=data)
|
|
260
|
+
if not success:
|
|
261
|
+
raise exceptions.PlatformException(response)
|
|
262
|
+
|
|
263
|
+
def delete_sample(self, series_id, sample_id):
|
|
264
|
+
"""
|
|
265
|
+
Delete single samples form time series
|
|
266
|
+
|
|
267
|
+
:param str series_id:
|
|
268
|
+
:param str sample_id:
|
|
269
|
+
:return:
|
|
270
|
+
"""
|
|
271
|
+
success, response = self._client_api.gen_request(req_type='delete',
|
|
272
|
+
path='/projects/{}/timeSeries/{}/samples/{}'.format(
|
|
273
|
+
self.project.id,
|
|
274
|
+
series_id,
|
|
275
|
+
sample_id))
|
|
276
|
+
if not success:
|
|
277
|
+
raise exceptions.PlatformException(response)
|
|
278
|
+
return True
|