dtlpy 1.113.10__py3-none-any.whl → 1.114.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.
- dtlpy/__init__.py +488 -488
- dtlpy/__version__.py +1 -1
- dtlpy/assets/__init__.py +26 -26
- dtlpy/assets/__pycache__/__init__.cpython-38.pyc +0 -0
- 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 +311 -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 +296 -296
- dtlpy/entities/collection.py +38 -38
- dtlpy/entities/command.py +169 -169
- dtlpy/entities/compute.py +442 -442
- dtlpy/entities/dataset.py +1285 -1285
- dtlpy/entities/directory_tree.py +44 -44
- dtlpy/entities/dpk.py +470 -470
- dtlpy/entities/driver.py +222 -222
- dtlpy/entities/execution.py +397 -397
- dtlpy/entities/feature.py +124 -124
- dtlpy/entities/feature_set.py +145 -145
- dtlpy/entities/filters.py +641 -641
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +953 -953
- dtlpy/entities/label.py +123 -123
- dtlpy/entities/links.py +85 -85
- dtlpy/entities/message.py +175 -175
- dtlpy/entities/model.py +694 -691
- dtlpy/entities/node.py +1005 -1005
- dtlpy/entities/ontology.py +803 -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 +290 -267
- dtlpy/entities/pipeline.py +593 -593
- dtlpy/entities/pipeline_execution.py +279 -279
- dtlpy/entities/project.py +394 -394
- dtlpy/entities/prompt_item.py +499 -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 +958 -958
- dtlpy/entities/service_driver.py +117 -117
- dtlpy/entities/setting.py +294 -294
- dtlpy/entities/task.py +491 -491
- 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 +945 -940
- 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 -348
- dtlpy/repositories/commands.py +158 -158
- dtlpy/repositories/compositions.py +61 -61
- dtlpy/repositories/computes.py +434 -406
- dtlpy/repositories/datasets.py +1291 -1291
- dtlpy/repositories/downloader.py +895 -895
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +266 -266
- dtlpy/repositories/executions.py +817 -817
- dtlpy/repositories/feature_sets.py +226 -226
- dtlpy/repositories/features.py +238 -238
- dtlpy/repositories/integrations.py +484 -484
- dtlpy/repositories/items.py +909 -915
- dtlpy/repositories/messages.py +94 -94
- dtlpy/repositories/models.py +877 -867
- 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 +448 -448
- dtlpy/repositories/pipelines.py +642 -642
- dtlpy/repositories/projects.py +539 -539
- dtlpy/repositories/recipes.py +399 -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 +1124 -1124
- dtlpy/repositories/times_series.py +278 -278
- dtlpy/repositories/triggers.py +536 -536
- dtlpy/repositories/upload_element.py +257 -257
- dtlpy/repositories/uploader.py +651 -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 +1782 -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 +264 -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.113.10.data → dtlpy-1.114.13.data}/scripts/dlp +1 -1
- dtlpy-1.114.13.data/scripts/dlp.bat +2 -0
- {dtlpy-1.113.10.data → dtlpy-1.114.13.data}/scripts/dlp.py +128 -128
- {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/LICENSE +200 -200
- {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/METADATA +172 -172
- dtlpy-1.114.13.dist-info/RECORD +240 -0
- {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/WHEEL +1 -1
- tests/features/environment.py +551 -550
- dtlpy-1.113.10.data/scripts/dlp.bat +0 -2
- dtlpy-1.113.10.dist-info/RECORD +0 -244
- tests/assets/__init__.py +0 -0
- tests/assets/models_flow/__init__.py +0 -0
- tests/assets/models_flow/failedmain.py +0 -52
- tests/assets/models_flow/main.py +0 -62
- tests/assets/models_flow/main_model.py +0 -54
- {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/top_level.txt +0 -0
dtlpy/entities/filters.py
CHANGED
|
@@ -1,641 +1,641 @@
|
|
|
1
|
-
import urllib.parse
|
|
2
|
-
import logging
|
|
3
|
-
import json
|
|
4
|
-
import os
|
|
5
|
-
import io
|
|
6
|
-
from enum import Enum
|
|
7
|
-
|
|
8
|
-
from .. import exceptions, entities
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger(name='dtlpy')
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class FiltersKnownFields(str, Enum):
|
|
14
|
-
DIR = "dir"
|
|
15
|
-
ANNOTATED = "annotated"
|
|
16
|
-
FILENAME = "filename"
|
|
17
|
-
CREATED_AT = "createdAt"
|
|
18
|
-
UPDATED_AT = "updatedAt"
|
|
19
|
-
LABEL = "label"
|
|
20
|
-
NAME = "name"
|
|
21
|
-
HIDDEN = "hidden"
|
|
22
|
-
TYPE = 'type'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class FiltersResource(str, Enum):
|
|
26
|
-
ITEM = "items"
|
|
27
|
-
ANNOTATION = "annotations"
|
|
28
|
-
EXECUTION = "executions"
|
|
29
|
-
PACKAGE = "packages"
|
|
30
|
-
DPK = "dpks"
|
|
31
|
-
APP = "apps"
|
|
32
|
-
SERVICE = "services"
|
|
33
|
-
TRIGGER = "triggers"
|
|
34
|
-
MODEL = "models"
|
|
35
|
-
WEBHOOK = "webhooks"
|
|
36
|
-
RECIPE = 'recipe'
|
|
37
|
-
DATASET = 'datasets'
|
|
38
|
-
ONTOLOGY = 'ontology'
|
|
39
|
-
TASK = 'tasks'
|
|
40
|
-
PIPELINE = 'pipeline'
|
|
41
|
-
PIPELINE_EXECUTION = 'pipelineState'
|
|
42
|
-
COMPOSITION = 'composition'
|
|
43
|
-
FEATURE = 'feature_vectors'
|
|
44
|
-
FEATURE_SET = 'feature_sets'
|
|
45
|
-
ORGANIZATIONS = 'organizations'
|
|
46
|
-
DRIVERS = 'drivers'
|
|
47
|
-
SETTINGS = 'setting'
|
|
48
|
-
RESOURCE_EXECUTION = 'resourceExecution'
|
|
49
|
-
METRICS = 'metrics',
|
|
50
|
-
SERVICE_DRIVER = 'serviceDrivers',
|
|
51
|
-
COMPUTE = 'compute'
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class FiltersOperations(str, Enum):
|
|
55
|
-
OR = "or"
|
|
56
|
-
AND = "and"
|
|
57
|
-
IN = "in"
|
|
58
|
-
NOT_EQUAL = "ne"
|
|
59
|
-
EQUAL = "eq"
|
|
60
|
-
GREATER_THAN = "gt"
|
|
61
|
-
LESS_THAN = "lt"
|
|
62
|
-
EXISTS = "exists"
|
|
63
|
-
MATCH = "match"
|
|
64
|
-
NIN = 'nin'
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class FiltersMethod(str, Enum):
|
|
68
|
-
OR = "or"
|
|
69
|
-
AND = "and"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class FiltersOrderByDirection(str, Enum):
|
|
73
|
-
DESCENDING = "descending"
|
|
74
|
-
ASCENDING = "ascending"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class Filters:
|
|
78
|
-
"""
|
|
79
|
-
Filters entity to filter items from pages in platform
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
def __init__(
|
|
83
|
-
self,
|
|
84
|
-
field=None,
|
|
85
|
-
values=None,
|
|
86
|
-
operator: FiltersOperations = None,
|
|
87
|
-
method: FiltersMethod = None,
|
|
88
|
-
custom_filter=None,
|
|
89
|
-
resource: FiltersResource = FiltersResource.ITEM,
|
|
90
|
-
use_defaults=True,
|
|
91
|
-
context=None,
|
|
92
|
-
page_size=None,
|
|
93
|
-
):
|
|
94
|
-
if page_size is None:
|
|
95
|
-
if resource in [FiltersResource.EXECUTION,
|
|
96
|
-
FiltersResource.PIPELINE_EXECUTION,
|
|
97
|
-
FiltersResource.DPK]:
|
|
98
|
-
page_size = 100
|
|
99
|
-
else:
|
|
100
|
-
page_size = 1000
|
|
101
|
-
|
|
102
|
-
self.or_filter_list = list()
|
|
103
|
-
self.and_filter_list = list()
|
|
104
|
-
self._unique_fields = list()
|
|
105
|
-
self.custom_filter = custom_filter
|
|
106
|
-
self.known_operators = ['or', 'and', 'in', 'ne', 'eq', 'gt', 'lt', 'exists']
|
|
107
|
-
self._resource = resource
|
|
108
|
-
self.page = 0
|
|
109
|
-
self.page_size = page_size
|
|
110
|
-
self.method = FiltersMethod.AND
|
|
111
|
-
self.sort = dict()
|
|
112
|
-
self.join = None
|
|
113
|
-
self.recursive = True
|
|
114
|
-
|
|
115
|
-
# system only - task and assignment attributes
|
|
116
|
-
self._user_query = 'true'
|
|
117
|
-
self._ref_task = False
|
|
118
|
-
self._ref_assignment = False
|
|
119
|
-
self._ref_op = None
|
|
120
|
-
self._ref_assignment_id = None
|
|
121
|
-
self._ref_task_id = None
|
|
122
|
-
self._system_space = None
|
|
123
|
-
|
|
124
|
-
self._use_defaults = use_defaults
|
|
125
|
-
self.__add_defaults()
|
|
126
|
-
self.context = context
|
|
127
|
-
|
|
128
|
-
if field is not None:
|
|
129
|
-
self.add(field=field, values=values, operator=operator, method=method)
|
|
130
|
-
|
|
131
|
-
def __validate_page_size(self):
|
|
132
|
-
max_page_size = self.__max_page_size
|
|
133
|
-
if self.page_size > max_page_size:
|
|
134
|
-
logger.warning('Cannot list {} with page size greater than {}. Changing page_size to {}.'.format(
|
|
135
|
-
self.resource, max_page_size, max_page_size
|
|
136
|
-
))
|
|
137
|
-
self.page_size = max_page_size
|
|
138
|
-
|
|
139
|
-
@property
|
|
140
|
-
def __max_page_size(self):
|
|
141
|
-
page_size = 1000
|
|
142
|
-
if self.resource in [FiltersResource.EXECUTION, FiltersResource.PIPELINE_EXECUTION]:
|
|
143
|
-
page_size = 100
|
|
144
|
-
return page_size
|
|
145
|
-
|
|
146
|
-
@property
|
|
147
|
-
def resource(self):
|
|
148
|
-
return f'{self._resource.value}' if isinstance(self._resource, FiltersResource) else f'{self._resource}'
|
|
149
|
-
|
|
150
|
-
@resource.setter
|
|
151
|
-
def resource(self, resource):
|
|
152
|
-
self._resource = resource
|
|
153
|
-
self.reset()
|
|
154
|
-
self.__add_defaults()
|
|
155
|
-
|
|
156
|
-
@property
|
|
157
|
-
def system_space(self):
|
|
158
|
-
return self._system_space
|
|
159
|
-
|
|
160
|
-
@system_space.setter
|
|
161
|
-
def system_space(self, val: bool):
|
|
162
|
-
self._system_space = val
|
|
163
|
-
|
|
164
|
-
def reset(self):
|
|
165
|
-
self.or_filter_list = list()
|
|
166
|
-
self.and_filter_list = list()
|
|
167
|
-
self._unique_fields = list()
|
|
168
|
-
self.custom_filter = None
|
|
169
|
-
self.page = 0
|
|
170
|
-
self.page_size = 1000
|
|
171
|
-
self.method = FiltersMethod.AND
|
|
172
|
-
self.sort = dict()
|
|
173
|
-
self.join = None
|
|
174
|
-
self.recursive = True
|
|
175
|
-
self._nullify_refs()
|
|
176
|
-
|
|
177
|
-
def _nullify_refs(self):
|
|
178
|
-
self._ref_task = False
|
|
179
|
-
self._ref_assignment = False
|
|
180
|
-
self._ref_op = None
|
|
181
|
-
self._ref_assignment_id = None
|
|
182
|
-
self._ref_task_id = None
|
|
183
|
-
|
|
184
|
-
def add(self, field, values, operator: FiltersOperations = None, method: FiltersMethod = None):
|
|
185
|
-
"""
|
|
186
|
-
Add filter
|
|
187
|
-
|
|
188
|
-
:param str field: Metadata field / attribute
|
|
189
|
-
:param values: field values
|
|
190
|
-
:param dl.FiltersOperations operator: optional - in, gt, lt, eq, ne
|
|
191
|
-
:param dl.FiltersMethod method: Optional - or/and
|
|
192
|
-
|
|
193
|
-
**Example**:
|
|
194
|
-
|
|
195
|
-
.. code-block:: python
|
|
196
|
-
|
|
197
|
-
filter.add(field='metadata.user', values=['1','2'], operator=dl.FiltersOperations.IN)
|
|
198
|
-
"""
|
|
199
|
-
if method is None:
|
|
200
|
-
method = self.method
|
|
201
|
-
if 'metadata.system.refs.metadata' in field and self.resource == FiltersResource.ITEM:
|
|
202
|
-
logger.warning('Filtering by metadata.system.refs.metadata may cause incorrect results. please use match operator')
|
|
203
|
-
|
|
204
|
-
# create SingleFilter object and add to self.filter_list
|
|
205
|
-
if method == FiltersMethod.OR:
|
|
206
|
-
self.or_filter_list.append(SingleFilter(field=field, values=values, operator=operator))
|
|
207
|
-
elif method == FiltersMethod.AND:
|
|
208
|
-
self.__override(field=field, values=values, operator=operator)
|
|
209
|
-
else:
|
|
210
|
-
raise exceptions.PlatformException(error='400',
|
|
211
|
-
message='Unknown method {}, please select from: or/and'.format(method))
|
|
212
|
-
|
|
213
|
-
def __override(self, field, values, operator=None):
|
|
214
|
-
if field in self._unique_fields:
|
|
215
|
-
for i_single_filter, single_filter in enumerate(self.and_filter_list):
|
|
216
|
-
if single_filter.field == field:
|
|
217
|
-
self.and_filter_list.pop(i_single_filter)
|
|
218
|
-
self.and_filter_list.append(
|
|
219
|
-
SingleFilter(field=field, values=values, operator=operator)
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
def generate_url_query_params(self, url):
|
|
223
|
-
"""
|
|
224
|
-
generate url query params
|
|
225
|
-
|
|
226
|
-
:param str url:
|
|
227
|
-
"""
|
|
228
|
-
url = '{}?'.format(url)
|
|
229
|
-
for f in self.and_filter_list:
|
|
230
|
-
if isinstance(f.values, list):
|
|
231
|
-
url = '{}{}={}&'.format(url, f.field, ','.join(f.values))
|
|
232
|
-
else:
|
|
233
|
-
url = '{}{}={}&'.format(url, f.field, f.values)
|
|
234
|
-
return '{}&pageOffset={}&pageSize={}'.format(url, self.page, self.page_size)
|
|
235
|
-
|
|
236
|
-
def has_field(self, field):
|
|
237
|
-
"""
|
|
238
|
-
is filter has field
|
|
239
|
-
|
|
240
|
-
:param str field: field to check
|
|
241
|
-
:return: Ture is have it
|
|
242
|
-
:rtype: bool
|
|
243
|
-
"""
|
|
244
|
-
for single_filter in self.or_filter_list:
|
|
245
|
-
if single_filter.field == field:
|
|
246
|
-
return True
|
|
247
|
-
|
|
248
|
-
for single_filter in self.and_filter_list:
|
|
249
|
-
if single_filter.field == field:
|
|
250
|
-
return True
|
|
251
|
-
|
|
252
|
-
return False
|
|
253
|
-
|
|
254
|
-
def pop(self, field):
|
|
255
|
-
"""
|
|
256
|
-
Pop filed
|
|
257
|
-
|
|
258
|
-
:param str field: field to pop
|
|
259
|
-
"""
|
|
260
|
-
for single_filter in self.or_filter_list:
|
|
261
|
-
if single_filter.field == field:
|
|
262
|
-
self.or_filter_list.remove(single_filter)
|
|
263
|
-
|
|
264
|
-
for single_filter in self.and_filter_list:
|
|
265
|
-
if single_filter.field == field:
|
|
266
|
-
self.and_filter_list.remove(single_filter)
|
|
267
|
-
|
|
268
|
-
def pop_join(self, field):
|
|
269
|
-
"""
|
|
270
|
-
Pop join
|
|
271
|
-
|
|
272
|
-
:param str field: field to pop
|
|
273
|
-
"""
|
|
274
|
-
if self.join is not None:
|
|
275
|
-
for single_filter in self.join['filter']['$and']:
|
|
276
|
-
if field in single_filter:
|
|
277
|
-
self.join['filter']['$and'].remove(single_filter)
|
|
278
|
-
|
|
279
|
-
def add_join(self, field,
|
|
280
|
-
values,
|
|
281
|
-
operator: FiltersOperations = None,
|
|
282
|
-
method: FiltersMethod = FiltersMethod.AND
|
|
283
|
-
):
|
|
284
|
-
"""
|
|
285
|
-
join a query to the filter
|
|
286
|
-
|
|
287
|
-
:param str field: Metadata field / attribute
|
|
288
|
-
:param str or list values: field values
|
|
289
|
-
:param dl.FiltersOperations operator: optional - in, gt, lt, eq, ne
|
|
290
|
-
:param method: optional - str - FiltersMethod.AND, FiltersMethod.OR
|
|
291
|
-
|
|
292
|
-
**Example**:
|
|
293
|
-
|
|
294
|
-
.. code-block:: python
|
|
295
|
-
|
|
296
|
-
filter.add_join(field='metadata.user', values=['1','2'], operator=dl.FiltersOperations.IN)
|
|
297
|
-
"""
|
|
298
|
-
if self.resource not in [FiltersResource.ITEM, FiltersResource.ANNOTATION]:
|
|
299
|
-
raise exceptions.PlatformException(error='400',
|
|
300
|
-
message='Cannot join to {} filters'.format(self.resource))
|
|
301
|
-
|
|
302
|
-
if self.join is None:
|
|
303
|
-
self.join = dict()
|
|
304
|
-
if 'on' not in self.join:
|
|
305
|
-
if self.resource == FiltersResource.ITEM:
|
|
306
|
-
self.join['on'] = {'resource': FiltersResource.ANNOTATION.value, 'local': 'itemId', 'forigen': 'id'}
|
|
307
|
-
else:
|
|
308
|
-
self.join['on'] = {'resource': FiltersResource.ITEM.value, 'local': 'id', 'forigen': 'itemId'}
|
|
309
|
-
if 'filter' not in self.join:
|
|
310
|
-
self.join['filter'] = dict()
|
|
311
|
-
join_method = '$' + method
|
|
312
|
-
if join_method not in self.join['filter']:
|
|
313
|
-
self.join['filter'][join_method] = list()
|
|
314
|
-
self.join['filter'][join_method].append(SingleFilter(field=field, values=values, operator=operator).prepare())
|
|
315
|
-
|
|
316
|
-
def __add_defaults(self):
|
|
317
|
-
if self._use_defaults:
|
|
318
|
-
# add items defaults
|
|
319
|
-
if self.resource == FiltersResource.ITEM:
|
|
320
|
-
self._unique_fields = ['type', 'hidden']
|
|
321
|
-
self.add(field='hidden', values=False, method=FiltersMethod.AND)
|
|
322
|
-
self.add(field='type', values='file', method=FiltersMethod.AND)
|
|
323
|
-
# add service defaults
|
|
324
|
-
elif self.resource == FiltersResource.SERVICE:
|
|
325
|
-
self._unique_fields = ['global']
|
|
326
|
-
self.add(field='global', values=True, operator=FiltersOperations.NOT_EQUAL, method=FiltersMethod.AND)
|
|
327
|
-
elif self.resource == FiltersResource.PACKAGE:
|
|
328
|
-
self._unique_fields = ['global']
|
|
329
|
-
self.add(field='global', values=True, operator=FiltersOperations.NOT_EQUAL, method=FiltersMethod.AND)
|
|
330
|
-
# add annotations defaults
|
|
331
|
-
elif self.resource == FiltersResource.ANNOTATION:
|
|
332
|
-
self._unique_fields = ['type']
|
|
333
|
-
values = [annotation_type.value for annotation_type in entities.AnnotationType]
|
|
334
|
-
values.remove(entities.AnnotationType.NOTE.value)
|
|
335
|
-
self.add(field='type', values=values, operator=FiltersOperations.IN, method=FiltersMethod.AND)
|
|
336
|
-
|
|
337
|
-
def __generate_query(self):
|
|
338
|
-
filters_dict = dict()
|
|
339
|
-
|
|
340
|
-
if len(self.or_filter_list) > 0:
|
|
341
|
-
or_filters = list()
|
|
342
|
-
for single_filter in self.or_filter_list:
|
|
343
|
-
or_filters.append(
|
|
344
|
-
single_filter.prepare(recursive=self.recursive and self.resource == FiltersResource.ITEM))
|
|
345
|
-
filters_dict['$or'] = or_filters
|
|
346
|
-
|
|
347
|
-
if len(self.and_filter_list) > 0:
|
|
348
|
-
and_filters = list()
|
|
349
|
-
for single_filter in self.and_filter_list:
|
|
350
|
-
and_filters.append(
|
|
351
|
-
single_filter.prepare(recursive=self.recursive and self.resource == FiltersResource.ITEM))
|
|
352
|
-
filters_dict['$and'] = and_filters
|
|
353
|
-
|
|
354
|
-
return filters_dict
|
|
355
|
-
|
|
356
|
-
def __generate_custom_query(self):
|
|
357
|
-
filters_dict = dict()
|
|
358
|
-
if 'filter' in self.custom_filter or 'join' in self.custom_filter:
|
|
359
|
-
if 'filter' in self.custom_filter:
|
|
360
|
-
filters_dict = self.custom_filter['filter']
|
|
361
|
-
self.join = self.custom_filter.get('join', self.join)
|
|
362
|
-
else:
|
|
363
|
-
filters_dict = self.custom_filter
|
|
364
|
-
return filters_dict
|
|
365
|
-
|
|
366
|
-
def __generate_ref_query(self):
|
|
367
|
-
refs = list()
|
|
368
|
-
if self._ref_task:
|
|
369
|
-
task_refs = list()
|
|
370
|
-
if not isinstance(self._ref_task_id, list):
|
|
371
|
-
self._ref_task_id = [self._ref_task_id]
|
|
372
|
-
|
|
373
|
-
for ref_id in self._ref_task_id:
|
|
374
|
-
task_refs.append({'type': 'task', 'id': ref_id})
|
|
375
|
-
|
|
376
|
-
refs += task_refs
|
|
377
|
-
|
|
378
|
-
if self._ref_assignment:
|
|
379
|
-
assignment_refs = list()
|
|
380
|
-
if not isinstance(self._ref_assignment_id, list):
|
|
381
|
-
self._ref_assignment_id = [self._ref_assignment_id]
|
|
382
|
-
|
|
383
|
-
for ref_id in self._ref_assignment_id:
|
|
384
|
-
assignment_refs.append({'type': 'assignment', 'id': ref_id})
|
|
385
|
-
|
|
386
|
-
refs += assignment_refs
|
|
387
|
-
|
|
388
|
-
return refs
|
|
389
|
-
|
|
390
|
-
def prepare(self, operation=None, update=None, query_only=False, system_update=None, system_metadata=False):
|
|
391
|
-
"""
|
|
392
|
-
To dictionary for platform call
|
|
393
|
-
|
|
394
|
-
:param str operation: operation
|
|
395
|
-
:param update: update
|
|
396
|
-
:param bool query_only: query only
|
|
397
|
-
:param system_update: system update
|
|
398
|
-
:param system_metadata: True, if you want to change metadata system
|
|
399
|
-
:return: dict of the filter
|
|
400
|
-
:rtype: dict
|
|
401
|
-
"""
|
|
402
|
-
########
|
|
403
|
-
# json #
|
|
404
|
-
########
|
|
405
|
-
_json = dict()
|
|
406
|
-
|
|
407
|
-
if self.custom_filter is None:
|
|
408
|
-
_json['filter'] = self.__generate_query()
|
|
409
|
-
else:
|
|
410
|
-
_json['filter'] = self.__generate_custom_query()
|
|
411
|
-
|
|
412
|
-
##################
|
|
413
|
-
# filter options #
|
|
414
|
-
##################
|
|
415
|
-
if not query_only:
|
|
416
|
-
if len(self.sort) > 0:
|
|
417
|
-
_json['sort'] = self.sort
|
|
418
|
-
|
|
419
|
-
self.__validate_page_size()
|
|
420
|
-
|
|
421
|
-
_json['page'] = self.page
|
|
422
|
-
_json['pageSize'] = self.page_size
|
|
423
|
-
_json['resource'] = self.resource
|
|
424
|
-
|
|
425
|
-
########
|
|
426
|
-
# join #
|
|
427
|
-
########
|
|
428
|
-
if self.join is not None:
|
|
429
|
-
_json['join'] = self.join
|
|
430
|
-
|
|
431
|
-
#####################
|
|
432
|
-
# operation or refs #
|
|
433
|
-
#####################
|
|
434
|
-
if self._ref_assignment or self._ref_task:
|
|
435
|
-
_json['references'] = {
|
|
436
|
-
'operation': self._ref_op,
|
|
437
|
-
'refs': self.__generate_ref_query()
|
|
438
|
-
}
|
|
439
|
-
elif operation is not None:
|
|
440
|
-
if operation == 'update':
|
|
441
|
-
if update:
|
|
442
|
-
_json[operation] = {'metadata': {'user': update}}
|
|
443
|
-
else:
|
|
444
|
-
_json[operation] = dict()
|
|
445
|
-
if system_metadata and system_update:
|
|
446
|
-
_json['systemSpace'] = True
|
|
447
|
-
_json[operation]['metadata'] = _json[operation].get('metadata', dict())
|
|
448
|
-
_json[operation]['metadata']['system'] = system_update
|
|
449
|
-
elif operation == 'delete':
|
|
450
|
-
_json[operation] = True
|
|
451
|
-
_json.pop('sort', None)
|
|
452
|
-
if self.resource == FiltersResource.ITEM:
|
|
453
|
-
_json.pop('page', None)
|
|
454
|
-
_json.pop('pageSize', None)
|
|
455
|
-
else:
|
|
456
|
-
raise exceptions.PlatformException(error='400',
|
|
457
|
-
message='Unknown operation: {}'.format(operation))
|
|
458
|
-
|
|
459
|
-
if self.context is not None:
|
|
460
|
-
_json['context'] = self.context
|
|
461
|
-
if self._system_space is not None:
|
|
462
|
-
_json['systemSpace'] = self._system_space
|
|
463
|
-
return _json
|
|
464
|
-
|
|
465
|
-
def print(self, indent=2):
|
|
466
|
-
print(json.dumps(self.prepare(), indent=indent))
|
|
467
|
-
|
|
468
|
-
def sort_by(self, field, value: FiltersOrderByDirection = FiltersOrderByDirection.ASCENDING):
|
|
469
|
-
"""
|
|
470
|
-
sort the filter
|
|
471
|
-
|
|
472
|
-
:param str field: field to sort by it
|
|
473
|
-
:param dl.FiltersOrderByDirection value: FiltersOrderByDirection.ASCENDING, FiltersOrderByDirection.DESCENDING
|
|
474
|
-
|
|
475
|
-
**Example**:
|
|
476
|
-
|
|
477
|
-
.. code-block:: python
|
|
478
|
-
|
|
479
|
-
filter.sort_by(field='metadata.user', values=dl.FiltersOrderByDirection.ASCENDING)
|
|
480
|
-
"""
|
|
481
|
-
if value not in [FiltersOrderByDirection.ASCENDING, FiltersOrderByDirection.DESCENDING]:
|
|
482
|
-
raise exceptions.PlatformException(error='400', message='Sort can be by ascending or descending order only')
|
|
483
|
-
self.sort[field] = value.value if isinstance(value, FiltersOrderByDirection) else value
|
|
484
|
-
|
|
485
|
-
def platform_url(self, resource) -> str:
|
|
486
|
-
"""
|
|
487
|
-
Build a url with filters param to open in web browser
|
|
488
|
-
|
|
489
|
-
:param str resource: dl entity to apply filter on. currently only supports dl.Dataset
|
|
490
|
-
:return: url string
|
|
491
|
-
:rtype: str
|
|
492
|
-
"""
|
|
493
|
-
_json = self.prepare()
|
|
494
|
-
# add the view option
|
|
495
|
-
_json['view'] = 'icons'
|
|
496
|
-
# convert from enum to string
|
|
497
|
-
_json["resource"] = f'{_json["resource"]}'
|
|
498
|
-
# convert the dictionary to a json string
|
|
499
|
-
_json['dqlFilter'] = json.dumps({'filter': _json.pop('filter'),
|
|
500
|
-
'join': _json.pop('join', None),
|
|
501
|
-
'sort': _json.get('sort', None)})
|
|
502
|
-
# set the page size as the UI default
|
|
503
|
-
_json['pageSize'] = 100
|
|
504
|
-
_json['page'] = _json['page']
|
|
505
|
-
# build the url for the dataset data browser
|
|
506
|
-
if isinstance(resource, entities.Dataset):
|
|
507
|
-
url = resource.platform_url + f'?{urllib.parse.urlencode(_json)}'
|
|
508
|
-
else:
|
|
509
|
-
raise NotImplementedError('Not implemented for resource type: {}'.format(type(resource)))
|
|
510
|
-
return url
|
|
511
|
-
|
|
512
|
-
def open_in_web(self, resource):
|
|
513
|
-
"""
|
|
514
|
-
Open the filter in the platform data browser (in a new web browser)
|
|
515
|
-
|
|
516
|
-
:param str resource: dl entity to apply filter on. currently only supports dl.Dataset
|
|
517
|
-
"""
|
|
518
|
-
if isinstance(resource, entities.Dataset):
|
|
519
|
-
resource._client_api._open_in_web(url=self.platform_url(resource=resource))
|
|
520
|
-
else:
|
|
521
|
-
raise NotImplementedError('Not implemented for resource type: {}'.format(type(resource)))
|
|
522
|
-
|
|
523
|
-
def save(self, project: entities.Project, filter_name: str):
|
|
524
|
-
"""
|
|
525
|
-
Save the current DQL filter to the project
|
|
526
|
-
|
|
527
|
-
:param project: dl.Project
|
|
528
|
-
:param filter_name: the saved filter's name
|
|
529
|
-
:return: True if success
|
|
530
|
-
"""
|
|
531
|
-
_json_filter = self.prepare()
|
|
532
|
-
shebang_dict = {"type": "dql",
|
|
533
|
-
"shebang": "dataloop",
|
|
534
|
-
"metadata": {
|
|
535
|
-
"version": "1.0.0",
|
|
536
|
-
"system": {
|
|
537
|
-
"mimetype": "dql"
|
|
538
|
-
},
|
|
539
|
-
"dltype": "filter",
|
|
540
|
-
"filterFieldsState": [],
|
|
541
|
-
"resource": "items",
|
|
542
|
-
"filter": _json_filter.pop('filter'),
|
|
543
|
-
"join": _json_filter.pop('join')
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
b_dataset = project.datasets._get_binaries_dataset()
|
|
547
|
-
byte_io = io.BytesIO()
|
|
548
|
-
byte_io.name = filter_name
|
|
549
|
-
byte_io.write(json.dumps(shebang_dict).encode())
|
|
550
|
-
byte_io.seek(0)
|
|
551
|
-
b_dataset.items.upload(local_path=byte_io,
|
|
552
|
-
remote_path='/.dataloop/dqlfilters/items',
|
|
553
|
-
remote_name=filter_name)
|
|
554
|
-
return True
|
|
555
|
-
|
|
556
|
-
@classmethod
|
|
557
|
-
def load(cls, project: entities.Project, filter_name: str) -> 'Filters':
|
|
558
|
-
"""
|
|
559
|
-
Load a saved filter from the project by name
|
|
560
|
-
|
|
561
|
-
:param project: dl.Project entity
|
|
562
|
-
:param filter_name: filter name
|
|
563
|
-
:return: dl.Filters
|
|
564
|
-
"""
|
|
565
|
-
b_dataset = project.datasets._get_binaries_dataset()
|
|
566
|
-
f = entities.Filters(custom_filter={
|
|
567
|
-
'filter': {'$and': [{'filename': f'/.dataloop/dqlfilters/items/{filter_name}'}]},
|
|
568
|
-
'page': 0,
|
|
569
|
-
'pageSize': 1000,
|
|
570
|
-
'resource': 'items'
|
|
571
|
-
})
|
|
572
|
-
pages = b_dataset.items.list(filters=f)
|
|
573
|
-
if pages.items_count == 0:
|
|
574
|
-
raise exceptions.NotFound(
|
|
575
|
-
f'Saved filter not found: {filter_name}. Run `Filters.list()` to list existing filters')
|
|
576
|
-
with open(pages.items[0].download()) as f:
|
|
577
|
-
data = json.load(f)
|
|
578
|
-
custom_filter = data['metadata']['filter']
|
|
579
|
-
custom_filter['join'] = data['metadata']['join']
|
|
580
|
-
return cls(custom_filter=custom_filter)
|
|
581
|
-
|
|
582
|
-
@staticmethod
|
|
583
|
-
def list(project: entities.Project) -> list:
|
|
584
|
-
"""
|
|
585
|
-
List all saved filters for a project
|
|
586
|
-
:param project: dl.Project entity
|
|
587
|
-
:return: a list of all the saved filters' names
|
|
588
|
-
"""
|
|
589
|
-
b_dataset = project.datasets._get_binaries_dataset()
|
|
590
|
-
f = entities.Filters(use_defaults=False,
|
|
591
|
-
field='dir',
|
|
592
|
-
values='/.dataloop/dqlfilters/items')
|
|
593
|
-
pages = b_dataset.items.list(filters=f)
|
|
594
|
-
all_filter_items = list(pages.all())
|
|
595
|
-
names = [i.name for i in all_filter_items]
|
|
596
|
-
return names
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
class SingleFilter:
|
|
600
|
-
def __init__(self, field, values, operator: FiltersOperations = None):
|
|
601
|
-
self.field = field
|
|
602
|
-
self.values = values
|
|
603
|
-
self.operator = operator
|
|
604
|
-
|
|
605
|
-
@staticmethod
|
|
606
|
-
def __add_recursive(value):
|
|
607
|
-
if not value.endswith('*') and not os.path.splitext(value)[-1].startswith('.'):
|
|
608
|
-
if value.endswith('/'):
|
|
609
|
-
value = value + '**'
|
|
610
|
-
else:
|
|
611
|
-
value = value + '/**'
|
|
612
|
-
return value
|
|
613
|
-
|
|
614
|
-
def prepare(self, recursive=False):
|
|
615
|
-
"""
|
|
616
|
-
To dictionary for platform call
|
|
617
|
-
|
|
618
|
-
:param recursive:recursive
|
|
619
|
-
"""
|
|
620
|
-
_json = dict()
|
|
621
|
-
values = self.values
|
|
622
|
-
|
|
623
|
-
if recursive and self.field == 'filename':
|
|
624
|
-
if isinstance(values, str):
|
|
625
|
-
values = self.__add_recursive(value=values)
|
|
626
|
-
elif isinstance(values, list):
|
|
627
|
-
for i_value, value in enumerate(values):
|
|
628
|
-
values[i_value] = self.__add_recursive(value=value)
|
|
629
|
-
|
|
630
|
-
if self.operator is None:
|
|
631
|
-
_json[self.field] = values
|
|
632
|
-
else:
|
|
633
|
-
value = dict()
|
|
634
|
-
op = self.operator.value if isinstance(self.operator, FiltersOperations) else self.operator
|
|
635
|
-
value['${}'.format(op)] = values
|
|
636
|
-
_json[self.field] = value
|
|
637
|
-
|
|
638
|
-
return _json
|
|
639
|
-
|
|
640
|
-
def print(self, indent=2):
|
|
641
|
-
print(json.dumps(self.prepare(), indent=indent))
|
|
1
|
+
import urllib.parse
|
|
2
|
+
import logging
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import io
|
|
6
|
+
from enum import Enum
|
|
7
|
+
|
|
8
|
+
from .. import exceptions, entities
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(name='dtlpy')
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FiltersKnownFields(str, Enum):
|
|
14
|
+
DIR = "dir"
|
|
15
|
+
ANNOTATED = "annotated"
|
|
16
|
+
FILENAME = "filename"
|
|
17
|
+
CREATED_AT = "createdAt"
|
|
18
|
+
UPDATED_AT = "updatedAt"
|
|
19
|
+
LABEL = "label"
|
|
20
|
+
NAME = "name"
|
|
21
|
+
HIDDEN = "hidden"
|
|
22
|
+
TYPE = 'type'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class FiltersResource(str, Enum):
|
|
26
|
+
ITEM = "items"
|
|
27
|
+
ANNOTATION = "annotations"
|
|
28
|
+
EXECUTION = "executions"
|
|
29
|
+
PACKAGE = "packages"
|
|
30
|
+
DPK = "dpks"
|
|
31
|
+
APP = "apps"
|
|
32
|
+
SERVICE = "services"
|
|
33
|
+
TRIGGER = "triggers"
|
|
34
|
+
MODEL = "models"
|
|
35
|
+
WEBHOOK = "webhooks"
|
|
36
|
+
RECIPE = 'recipe'
|
|
37
|
+
DATASET = 'datasets'
|
|
38
|
+
ONTOLOGY = 'ontology'
|
|
39
|
+
TASK = 'tasks'
|
|
40
|
+
PIPELINE = 'pipeline'
|
|
41
|
+
PIPELINE_EXECUTION = 'pipelineState'
|
|
42
|
+
COMPOSITION = 'composition'
|
|
43
|
+
FEATURE = 'feature_vectors'
|
|
44
|
+
FEATURE_SET = 'feature_sets'
|
|
45
|
+
ORGANIZATIONS = 'organizations'
|
|
46
|
+
DRIVERS = 'drivers'
|
|
47
|
+
SETTINGS = 'setting'
|
|
48
|
+
RESOURCE_EXECUTION = 'resourceExecution'
|
|
49
|
+
METRICS = 'metrics',
|
|
50
|
+
SERVICE_DRIVER = 'serviceDrivers',
|
|
51
|
+
COMPUTE = 'compute'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class FiltersOperations(str, Enum):
|
|
55
|
+
OR = "or"
|
|
56
|
+
AND = "and"
|
|
57
|
+
IN = "in"
|
|
58
|
+
NOT_EQUAL = "ne"
|
|
59
|
+
EQUAL = "eq"
|
|
60
|
+
GREATER_THAN = "gt"
|
|
61
|
+
LESS_THAN = "lt"
|
|
62
|
+
EXISTS = "exists"
|
|
63
|
+
MATCH = "match"
|
|
64
|
+
NIN = 'nin'
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class FiltersMethod(str, Enum):
|
|
68
|
+
OR = "or"
|
|
69
|
+
AND = "and"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class FiltersOrderByDirection(str, Enum):
|
|
73
|
+
DESCENDING = "descending"
|
|
74
|
+
ASCENDING = "ascending"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Filters:
|
|
78
|
+
"""
|
|
79
|
+
Filters entity to filter items from pages in platform
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
field=None,
|
|
85
|
+
values=None,
|
|
86
|
+
operator: FiltersOperations = None,
|
|
87
|
+
method: FiltersMethod = None,
|
|
88
|
+
custom_filter=None,
|
|
89
|
+
resource: FiltersResource = FiltersResource.ITEM,
|
|
90
|
+
use_defaults=True,
|
|
91
|
+
context=None,
|
|
92
|
+
page_size=None,
|
|
93
|
+
):
|
|
94
|
+
if page_size is None:
|
|
95
|
+
if resource in [FiltersResource.EXECUTION,
|
|
96
|
+
FiltersResource.PIPELINE_EXECUTION,
|
|
97
|
+
FiltersResource.DPK]:
|
|
98
|
+
page_size = 100
|
|
99
|
+
else:
|
|
100
|
+
page_size = 1000
|
|
101
|
+
|
|
102
|
+
self.or_filter_list = list()
|
|
103
|
+
self.and_filter_list = list()
|
|
104
|
+
self._unique_fields = list()
|
|
105
|
+
self.custom_filter = custom_filter
|
|
106
|
+
self.known_operators = ['or', 'and', 'in', 'ne', 'eq', 'gt', 'lt', 'exists']
|
|
107
|
+
self._resource = resource
|
|
108
|
+
self.page = 0
|
|
109
|
+
self.page_size = page_size
|
|
110
|
+
self.method = FiltersMethod.AND
|
|
111
|
+
self.sort = dict()
|
|
112
|
+
self.join = None
|
|
113
|
+
self.recursive = True
|
|
114
|
+
|
|
115
|
+
# system only - task and assignment attributes
|
|
116
|
+
self._user_query = 'true'
|
|
117
|
+
self._ref_task = False
|
|
118
|
+
self._ref_assignment = False
|
|
119
|
+
self._ref_op = None
|
|
120
|
+
self._ref_assignment_id = None
|
|
121
|
+
self._ref_task_id = None
|
|
122
|
+
self._system_space = None
|
|
123
|
+
|
|
124
|
+
self._use_defaults = use_defaults
|
|
125
|
+
self.__add_defaults()
|
|
126
|
+
self.context = context
|
|
127
|
+
|
|
128
|
+
if field is not None:
|
|
129
|
+
self.add(field=field, values=values, operator=operator, method=method)
|
|
130
|
+
|
|
131
|
+
def __validate_page_size(self):
|
|
132
|
+
max_page_size = self.__max_page_size
|
|
133
|
+
if self.page_size > max_page_size:
|
|
134
|
+
logger.warning('Cannot list {} with page size greater than {}. Changing page_size to {}.'.format(
|
|
135
|
+
self.resource, max_page_size, max_page_size
|
|
136
|
+
))
|
|
137
|
+
self.page_size = max_page_size
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def __max_page_size(self):
|
|
141
|
+
page_size = 1000
|
|
142
|
+
if self.resource in [FiltersResource.EXECUTION, FiltersResource.PIPELINE_EXECUTION]:
|
|
143
|
+
page_size = 100
|
|
144
|
+
return page_size
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def resource(self):
|
|
148
|
+
return f'{self._resource.value}' if isinstance(self._resource, FiltersResource) else f'{self._resource}'
|
|
149
|
+
|
|
150
|
+
@resource.setter
|
|
151
|
+
def resource(self, resource):
|
|
152
|
+
self._resource = resource
|
|
153
|
+
self.reset()
|
|
154
|
+
self.__add_defaults()
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def system_space(self):
|
|
158
|
+
return self._system_space
|
|
159
|
+
|
|
160
|
+
@system_space.setter
|
|
161
|
+
def system_space(self, val: bool):
|
|
162
|
+
self._system_space = val
|
|
163
|
+
|
|
164
|
+
def reset(self):
|
|
165
|
+
self.or_filter_list = list()
|
|
166
|
+
self.and_filter_list = list()
|
|
167
|
+
self._unique_fields = list()
|
|
168
|
+
self.custom_filter = None
|
|
169
|
+
self.page = 0
|
|
170
|
+
self.page_size = 1000
|
|
171
|
+
self.method = FiltersMethod.AND
|
|
172
|
+
self.sort = dict()
|
|
173
|
+
self.join = None
|
|
174
|
+
self.recursive = True
|
|
175
|
+
self._nullify_refs()
|
|
176
|
+
|
|
177
|
+
def _nullify_refs(self):
|
|
178
|
+
self._ref_task = False
|
|
179
|
+
self._ref_assignment = False
|
|
180
|
+
self._ref_op = None
|
|
181
|
+
self._ref_assignment_id = None
|
|
182
|
+
self._ref_task_id = None
|
|
183
|
+
|
|
184
|
+
def add(self, field, values, operator: FiltersOperations = None, method: FiltersMethod = None):
|
|
185
|
+
"""
|
|
186
|
+
Add filter
|
|
187
|
+
|
|
188
|
+
:param str field: Metadata field / attribute
|
|
189
|
+
:param values: field values
|
|
190
|
+
:param dl.FiltersOperations operator: optional - in, gt, lt, eq, ne
|
|
191
|
+
:param dl.FiltersMethod method: Optional - or/and
|
|
192
|
+
|
|
193
|
+
**Example**:
|
|
194
|
+
|
|
195
|
+
.. code-block:: python
|
|
196
|
+
|
|
197
|
+
filter.add(field='metadata.user', values=['1','2'], operator=dl.FiltersOperations.IN)
|
|
198
|
+
"""
|
|
199
|
+
if method is None:
|
|
200
|
+
method = self.method
|
|
201
|
+
if 'metadata.system.refs.metadata' in field and self.resource == FiltersResource.ITEM:
|
|
202
|
+
logger.warning('Filtering by metadata.system.refs.metadata may cause incorrect results. please use match operator')
|
|
203
|
+
|
|
204
|
+
# create SingleFilter object and add to self.filter_list
|
|
205
|
+
if method == FiltersMethod.OR:
|
|
206
|
+
self.or_filter_list.append(SingleFilter(field=field, values=values, operator=operator))
|
|
207
|
+
elif method == FiltersMethod.AND:
|
|
208
|
+
self.__override(field=field, values=values, operator=operator)
|
|
209
|
+
else:
|
|
210
|
+
raise exceptions.PlatformException(error='400',
|
|
211
|
+
message='Unknown method {}, please select from: or/and'.format(method))
|
|
212
|
+
|
|
213
|
+
def __override(self, field, values, operator=None):
|
|
214
|
+
if field in self._unique_fields:
|
|
215
|
+
for i_single_filter, single_filter in enumerate(self.and_filter_list):
|
|
216
|
+
if single_filter.field == field:
|
|
217
|
+
self.and_filter_list.pop(i_single_filter)
|
|
218
|
+
self.and_filter_list.append(
|
|
219
|
+
SingleFilter(field=field, values=values, operator=operator)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def generate_url_query_params(self, url):
|
|
223
|
+
"""
|
|
224
|
+
generate url query params
|
|
225
|
+
|
|
226
|
+
:param str url:
|
|
227
|
+
"""
|
|
228
|
+
url = '{}?'.format(url)
|
|
229
|
+
for f in self.and_filter_list:
|
|
230
|
+
if isinstance(f.values, list):
|
|
231
|
+
url = '{}{}={}&'.format(url, f.field, ','.join(f.values))
|
|
232
|
+
else:
|
|
233
|
+
url = '{}{}={}&'.format(url, f.field, f.values)
|
|
234
|
+
return '{}&pageOffset={}&pageSize={}'.format(url, self.page, self.page_size)
|
|
235
|
+
|
|
236
|
+
def has_field(self, field):
|
|
237
|
+
"""
|
|
238
|
+
is filter has field
|
|
239
|
+
|
|
240
|
+
:param str field: field to check
|
|
241
|
+
:return: Ture is have it
|
|
242
|
+
:rtype: bool
|
|
243
|
+
"""
|
|
244
|
+
for single_filter in self.or_filter_list:
|
|
245
|
+
if single_filter.field == field:
|
|
246
|
+
return True
|
|
247
|
+
|
|
248
|
+
for single_filter in self.and_filter_list:
|
|
249
|
+
if single_filter.field == field:
|
|
250
|
+
return True
|
|
251
|
+
|
|
252
|
+
return False
|
|
253
|
+
|
|
254
|
+
def pop(self, field):
|
|
255
|
+
"""
|
|
256
|
+
Pop filed
|
|
257
|
+
|
|
258
|
+
:param str field: field to pop
|
|
259
|
+
"""
|
|
260
|
+
for single_filter in self.or_filter_list:
|
|
261
|
+
if single_filter.field == field:
|
|
262
|
+
self.or_filter_list.remove(single_filter)
|
|
263
|
+
|
|
264
|
+
for single_filter in self.and_filter_list:
|
|
265
|
+
if single_filter.field == field:
|
|
266
|
+
self.and_filter_list.remove(single_filter)
|
|
267
|
+
|
|
268
|
+
def pop_join(self, field):
|
|
269
|
+
"""
|
|
270
|
+
Pop join
|
|
271
|
+
|
|
272
|
+
:param str field: field to pop
|
|
273
|
+
"""
|
|
274
|
+
if self.join is not None:
|
|
275
|
+
for single_filter in self.join['filter']['$and']:
|
|
276
|
+
if field in single_filter:
|
|
277
|
+
self.join['filter']['$and'].remove(single_filter)
|
|
278
|
+
|
|
279
|
+
def add_join(self, field,
|
|
280
|
+
values,
|
|
281
|
+
operator: FiltersOperations = None,
|
|
282
|
+
method: FiltersMethod = FiltersMethod.AND
|
|
283
|
+
):
|
|
284
|
+
"""
|
|
285
|
+
join a query to the filter
|
|
286
|
+
|
|
287
|
+
:param str field: Metadata field / attribute
|
|
288
|
+
:param str or list values: field values
|
|
289
|
+
:param dl.FiltersOperations operator: optional - in, gt, lt, eq, ne
|
|
290
|
+
:param method: optional - str - FiltersMethod.AND, FiltersMethod.OR
|
|
291
|
+
|
|
292
|
+
**Example**:
|
|
293
|
+
|
|
294
|
+
.. code-block:: python
|
|
295
|
+
|
|
296
|
+
filter.add_join(field='metadata.user', values=['1','2'], operator=dl.FiltersOperations.IN)
|
|
297
|
+
"""
|
|
298
|
+
if self.resource not in [FiltersResource.ITEM, FiltersResource.ANNOTATION]:
|
|
299
|
+
raise exceptions.PlatformException(error='400',
|
|
300
|
+
message='Cannot join to {} filters'.format(self.resource))
|
|
301
|
+
|
|
302
|
+
if self.join is None:
|
|
303
|
+
self.join = dict()
|
|
304
|
+
if 'on' not in self.join:
|
|
305
|
+
if self.resource == FiltersResource.ITEM:
|
|
306
|
+
self.join['on'] = {'resource': FiltersResource.ANNOTATION.value, 'local': 'itemId', 'forigen': 'id'}
|
|
307
|
+
else:
|
|
308
|
+
self.join['on'] = {'resource': FiltersResource.ITEM.value, 'local': 'id', 'forigen': 'itemId'}
|
|
309
|
+
if 'filter' not in self.join:
|
|
310
|
+
self.join['filter'] = dict()
|
|
311
|
+
join_method = '$' + method
|
|
312
|
+
if join_method not in self.join['filter']:
|
|
313
|
+
self.join['filter'][join_method] = list()
|
|
314
|
+
self.join['filter'][join_method].append(SingleFilter(field=field, values=values, operator=operator).prepare())
|
|
315
|
+
|
|
316
|
+
def __add_defaults(self):
|
|
317
|
+
if self._use_defaults:
|
|
318
|
+
# add items defaults
|
|
319
|
+
if self.resource == FiltersResource.ITEM:
|
|
320
|
+
self._unique_fields = ['type', 'hidden']
|
|
321
|
+
self.add(field='hidden', values=False, method=FiltersMethod.AND)
|
|
322
|
+
self.add(field='type', values='file', method=FiltersMethod.AND)
|
|
323
|
+
# add service defaults
|
|
324
|
+
elif self.resource == FiltersResource.SERVICE:
|
|
325
|
+
self._unique_fields = ['global']
|
|
326
|
+
self.add(field='global', values=True, operator=FiltersOperations.NOT_EQUAL, method=FiltersMethod.AND)
|
|
327
|
+
elif self.resource == FiltersResource.PACKAGE:
|
|
328
|
+
self._unique_fields = ['global']
|
|
329
|
+
self.add(field='global', values=True, operator=FiltersOperations.NOT_EQUAL, method=FiltersMethod.AND)
|
|
330
|
+
# add annotations defaults
|
|
331
|
+
elif self.resource == FiltersResource.ANNOTATION:
|
|
332
|
+
self._unique_fields = ['type']
|
|
333
|
+
values = [annotation_type.value for annotation_type in entities.AnnotationType]
|
|
334
|
+
values.remove(entities.AnnotationType.NOTE.value)
|
|
335
|
+
self.add(field='type', values=values, operator=FiltersOperations.IN, method=FiltersMethod.AND)
|
|
336
|
+
|
|
337
|
+
def __generate_query(self):
|
|
338
|
+
filters_dict = dict()
|
|
339
|
+
|
|
340
|
+
if len(self.or_filter_list) > 0:
|
|
341
|
+
or_filters = list()
|
|
342
|
+
for single_filter in self.or_filter_list:
|
|
343
|
+
or_filters.append(
|
|
344
|
+
single_filter.prepare(recursive=self.recursive and self.resource == FiltersResource.ITEM))
|
|
345
|
+
filters_dict['$or'] = or_filters
|
|
346
|
+
|
|
347
|
+
if len(self.and_filter_list) > 0:
|
|
348
|
+
and_filters = list()
|
|
349
|
+
for single_filter in self.and_filter_list:
|
|
350
|
+
and_filters.append(
|
|
351
|
+
single_filter.prepare(recursive=self.recursive and self.resource == FiltersResource.ITEM))
|
|
352
|
+
filters_dict['$and'] = and_filters
|
|
353
|
+
|
|
354
|
+
return filters_dict
|
|
355
|
+
|
|
356
|
+
def __generate_custom_query(self):
|
|
357
|
+
filters_dict = dict()
|
|
358
|
+
if 'filter' in self.custom_filter or 'join' in self.custom_filter:
|
|
359
|
+
if 'filter' in self.custom_filter:
|
|
360
|
+
filters_dict = self.custom_filter['filter']
|
|
361
|
+
self.join = self.custom_filter.get('join', self.join)
|
|
362
|
+
else:
|
|
363
|
+
filters_dict = self.custom_filter
|
|
364
|
+
return filters_dict
|
|
365
|
+
|
|
366
|
+
def __generate_ref_query(self):
|
|
367
|
+
refs = list()
|
|
368
|
+
if self._ref_task:
|
|
369
|
+
task_refs = list()
|
|
370
|
+
if not isinstance(self._ref_task_id, list):
|
|
371
|
+
self._ref_task_id = [self._ref_task_id]
|
|
372
|
+
|
|
373
|
+
for ref_id in self._ref_task_id:
|
|
374
|
+
task_refs.append({'type': 'task', 'id': ref_id})
|
|
375
|
+
|
|
376
|
+
refs += task_refs
|
|
377
|
+
|
|
378
|
+
if self._ref_assignment:
|
|
379
|
+
assignment_refs = list()
|
|
380
|
+
if not isinstance(self._ref_assignment_id, list):
|
|
381
|
+
self._ref_assignment_id = [self._ref_assignment_id]
|
|
382
|
+
|
|
383
|
+
for ref_id in self._ref_assignment_id:
|
|
384
|
+
assignment_refs.append({'type': 'assignment', 'id': ref_id})
|
|
385
|
+
|
|
386
|
+
refs += assignment_refs
|
|
387
|
+
|
|
388
|
+
return refs
|
|
389
|
+
|
|
390
|
+
def prepare(self, operation=None, update=None, query_only=False, system_update=None, system_metadata=False):
|
|
391
|
+
"""
|
|
392
|
+
To dictionary for platform call
|
|
393
|
+
|
|
394
|
+
:param str operation: operation
|
|
395
|
+
:param update: update
|
|
396
|
+
:param bool query_only: query only
|
|
397
|
+
:param system_update: system update
|
|
398
|
+
:param system_metadata: True, if you want to change metadata system
|
|
399
|
+
:return: dict of the filter
|
|
400
|
+
:rtype: dict
|
|
401
|
+
"""
|
|
402
|
+
########
|
|
403
|
+
# json #
|
|
404
|
+
########
|
|
405
|
+
_json = dict()
|
|
406
|
+
|
|
407
|
+
if self.custom_filter is None:
|
|
408
|
+
_json['filter'] = self.__generate_query()
|
|
409
|
+
else:
|
|
410
|
+
_json['filter'] = self.__generate_custom_query()
|
|
411
|
+
|
|
412
|
+
##################
|
|
413
|
+
# filter options #
|
|
414
|
+
##################
|
|
415
|
+
if not query_only:
|
|
416
|
+
if len(self.sort) > 0:
|
|
417
|
+
_json['sort'] = self.sort
|
|
418
|
+
|
|
419
|
+
self.__validate_page_size()
|
|
420
|
+
|
|
421
|
+
_json['page'] = self.page
|
|
422
|
+
_json['pageSize'] = self.page_size
|
|
423
|
+
_json['resource'] = self.resource
|
|
424
|
+
|
|
425
|
+
########
|
|
426
|
+
# join #
|
|
427
|
+
########
|
|
428
|
+
if self.join is not None:
|
|
429
|
+
_json['join'] = self.join
|
|
430
|
+
|
|
431
|
+
#####################
|
|
432
|
+
# operation or refs #
|
|
433
|
+
#####################
|
|
434
|
+
if self._ref_assignment or self._ref_task:
|
|
435
|
+
_json['references'] = {
|
|
436
|
+
'operation': self._ref_op,
|
|
437
|
+
'refs': self.__generate_ref_query()
|
|
438
|
+
}
|
|
439
|
+
elif operation is not None:
|
|
440
|
+
if operation == 'update':
|
|
441
|
+
if update:
|
|
442
|
+
_json[operation] = {'metadata': {'user': update}}
|
|
443
|
+
else:
|
|
444
|
+
_json[operation] = dict()
|
|
445
|
+
if system_metadata and system_update:
|
|
446
|
+
_json['systemSpace'] = True
|
|
447
|
+
_json[operation]['metadata'] = _json[operation].get('metadata', dict())
|
|
448
|
+
_json[operation]['metadata']['system'] = system_update
|
|
449
|
+
elif operation == 'delete':
|
|
450
|
+
_json[operation] = True
|
|
451
|
+
_json.pop('sort', None)
|
|
452
|
+
if self.resource == FiltersResource.ITEM:
|
|
453
|
+
_json.pop('page', None)
|
|
454
|
+
_json.pop('pageSize', None)
|
|
455
|
+
else:
|
|
456
|
+
raise exceptions.PlatformException(error='400',
|
|
457
|
+
message='Unknown operation: {}'.format(operation))
|
|
458
|
+
|
|
459
|
+
if self.context is not None:
|
|
460
|
+
_json['context'] = self.context
|
|
461
|
+
if self._system_space is not None:
|
|
462
|
+
_json['systemSpace'] = self._system_space
|
|
463
|
+
return _json
|
|
464
|
+
|
|
465
|
+
def print(self, indent=2):
|
|
466
|
+
print(json.dumps(self.prepare(), indent=indent))
|
|
467
|
+
|
|
468
|
+
def sort_by(self, field, value: FiltersOrderByDirection = FiltersOrderByDirection.ASCENDING):
|
|
469
|
+
"""
|
|
470
|
+
sort the filter
|
|
471
|
+
|
|
472
|
+
:param str field: field to sort by it
|
|
473
|
+
:param dl.FiltersOrderByDirection value: FiltersOrderByDirection.ASCENDING, FiltersOrderByDirection.DESCENDING
|
|
474
|
+
|
|
475
|
+
**Example**:
|
|
476
|
+
|
|
477
|
+
.. code-block:: python
|
|
478
|
+
|
|
479
|
+
filter.sort_by(field='metadata.user', values=dl.FiltersOrderByDirection.ASCENDING)
|
|
480
|
+
"""
|
|
481
|
+
if value not in [FiltersOrderByDirection.ASCENDING, FiltersOrderByDirection.DESCENDING]:
|
|
482
|
+
raise exceptions.PlatformException(error='400', message='Sort can be by ascending or descending order only')
|
|
483
|
+
self.sort[field] = value.value if isinstance(value, FiltersOrderByDirection) else value
|
|
484
|
+
|
|
485
|
+
def platform_url(self, resource) -> str:
|
|
486
|
+
"""
|
|
487
|
+
Build a url with filters param to open in web browser
|
|
488
|
+
|
|
489
|
+
:param str resource: dl entity to apply filter on. currently only supports dl.Dataset
|
|
490
|
+
:return: url string
|
|
491
|
+
:rtype: str
|
|
492
|
+
"""
|
|
493
|
+
_json = self.prepare()
|
|
494
|
+
# add the view option
|
|
495
|
+
_json['view'] = 'icons'
|
|
496
|
+
# convert from enum to string
|
|
497
|
+
_json["resource"] = f'{_json["resource"]}'
|
|
498
|
+
# convert the dictionary to a json string
|
|
499
|
+
_json['dqlFilter'] = json.dumps({'filter': _json.pop('filter'),
|
|
500
|
+
'join': _json.pop('join', None),
|
|
501
|
+
'sort': _json.get('sort', None)})
|
|
502
|
+
# set the page size as the UI default
|
|
503
|
+
_json['pageSize'] = 100
|
|
504
|
+
_json['page'] = _json['page']
|
|
505
|
+
# build the url for the dataset data browser
|
|
506
|
+
if isinstance(resource, entities.Dataset):
|
|
507
|
+
url = resource.platform_url + f'?{urllib.parse.urlencode(_json)}'
|
|
508
|
+
else:
|
|
509
|
+
raise NotImplementedError('Not implemented for resource type: {}'.format(type(resource)))
|
|
510
|
+
return url
|
|
511
|
+
|
|
512
|
+
def open_in_web(self, resource):
|
|
513
|
+
"""
|
|
514
|
+
Open the filter in the platform data browser (in a new web browser)
|
|
515
|
+
|
|
516
|
+
:param str resource: dl entity to apply filter on. currently only supports dl.Dataset
|
|
517
|
+
"""
|
|
518
|
+
if isinstance(resource, entities.Dataset):
|
|
519
|
+
resource._client_api._open_in_web(url=self.platform_url(resource=resource))
|
|
520
|
+
else:
|
|
521
|
+
raise NotImplementedError('Not implemented for resource type: {}'.format(type(resource)))
|
|
522
|
+
|
|
523
|
+
def save(self, project: entities.Project, filter_name: str):
|
|
524
|
+
"""
|
|
525
|
+
Save the current DQL filter to the project
|
|
526
|
+
|
|
527
|
+
:param project: dl.Project
|
|
528
|
+
:param filter_name: the saved filter's name
|
|
529
|
+
:return: True if success
|
|
530
|
+
"""
|
|
531
|
+
_json_filter = self.prepare()
|
|
532
|
+
shebang_dict = {"type": "dql",
|
|
533
|
+
"shebang": "dataloop",
|
|
534
|
+
"metadata": {
|
|
535
|
+
"version": "1.0.0",
|
|
536
|
+
"system": {
|
|
537
|
+
"mimetype": "dql"
|
|
538
|
+
},
|
|
539
|
+
"dltype": "filter",
|
|
540
|
+
"filterFieldsState": [],
|
|
541
|
+
"resource": "items",
|
|
542
|
+
"filter": _json_filter.pop('filter'),
|
|
543
|
+
"join": _json_filter.pop('join')
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
b_dataset = project.datasets._get_binaries_dataset()
|
|
547
|
+
byte_io = io.BytesIO()
|
|
548
|
+
byte_io.name = filter_name
|
|
549
|
+
byte_io.write(json.dumps(shebang_dict).encode())
|
|
550
|
+
byte_io.seek(0)
|
|
551
|
+
b_dataset.items.upload(local_path=byte_io,
|
|
552
|
+
remote_path='/.dataloop/dqlfilters/items',
|
|
553
|
+
remote_name=filter_name)
|
|
554
|
+
return True
|
|
555
|
+
|
|
556
|
+
@classmethod
|
|
557
|
+
def load(cls, project: entities.Project, filter_name: str) -> 'Filters':
|
|
558
|
+
"""
|
|
559
|
+
Load a saved filter from the project by name
|
|
560
|
+
|
|
561
|
+
:param project: dl.Project entity
|
|
562
|
+
:param filter_name: filter name
|
|
563
|
+
:return: dl.Filters
|
|
564
|
+
"""
|
|
565
|
+
b_dataset = project.datasets._get_binaries_dataset()
|
|
566
|
+
f = entities.Filters(custom_filter={
|
|
567
|
+
'filter': {'$and': [{'filename': f'/.dataloop/dqlfilters/items/{filter_name}'}]},
|
|
568
|
+
'page': 0,
|
|
569
|
+
'pageSize': 1000,
|
|
570
|
+
'resource': 'items'
|
|
571
|
+
})
|
|
572
|
+
pages = b_dataset.items.list(filters=f)
|
|
573
|
+
if pages.items_count == 0:
|
|
574
|
+
raise exceptions.NotFound(
|
|
575
|
+
f'Saved filter not found: {filter_name}. Run `Filters.list()` to list existing filters')
|
|
576
|
+
with open(pages.items[0].download()) as f:
|
|
577
|
+
data = json.load(f)
|
|
578
|
+
custom_filter = data['metadata']['filter']
|
|
579
|
+
custom_filter['join'] = data['metadata']['join']
|
|
580
|
+
return cls(custom_filter=custom_filter)
|
|
581
|
+
|
|
582
|
+
@staticmethod
|
|
583
|
+
def list(project: entities.Project) -> list:
|
|
584
|
+
"""
|
|
585
|
+
List all saved filters for a project
|
|
586
|
+
:param project: dl.Project entity
|
|
587
|
+
:return: a list of all the saved filters' names
|
|
588
|
+
"""
|
|
589
|
+
b_dataset = project.datasets._get_binaries_dataset()
|
|
590
|
+
f = entities.Filters(use_defaults=False,
|
|
591
|
+
field='dir',
|
|
592
|
+
values='/.dataloop/dqlfilters/items')
|
|
593
|
+
pages = b_dataset.items.list(filters=f)
|
|
594
|
+
all_filter_items = list(pages.all())
|
|
595
|
+
names = [i.name for i in all_filter_items]
|
|
596
|
+
return names
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
class SingleFilter:
|
|
600
|
+
def __init__(self, field, values, operator: FiltersOperations = None):
|
|
601
|
+
self.field = field
|
|
602
|
+
self.values = values
|
|
603
|
+
self.operator = operator
|
|
604
|
+
|
|
605
|
+
@staticmethod
|
|
606
|
+
def __add_recursive(value):
|
|
607
|
+
if not value.endswith('*') and not os.path.splitext(value)[-1].startswith('.'):
|
|
608
|
+
if value.endswith('/'):
|
|
609
|
+
value = value + '**'
|
|
610
|
+
else:
|
|
611
|
+
value = value + '/**'
|
|
612
|
+
return value
|
|
613
|
+
|
|
614
|
+
def prepare(self, recursive=False):
|
|
615
|
+
"""
|
|
616
|
+
To dictionary for platform call
|
|
617
|
+
|
|
618
|
+
:param recursive:recursive
|
|
619
|
+
"""
|
|
620
|
+
_json = dict()
|
|
621
|
+
values = self.values
|
|
622
|
+
|
|
623
|
+
if recursive and self.field == 'filename':
|
|
624
|
+
if isinstance(values, str):
|
|
625
|
+
values = self.__add_recursive(value=values)
|
|
626
|
+
elif isinstance(values, list):
|
|
627
|
+
for i_value, value in enumerate(values):
|
|
628
|
+
values[i_value] = self.__add_recursive(value=value)
|
|
629
|
+
|
|
630
|
+
if self.operator is None:
|
|
631
|
+
_json[self.field] = values
|
|
632
|
+
else:
|
|
633
|
+
value = dict()
|
|
634
|
+
op = self.operator.value if isinstance(self.operator, FiltersOperations) else self.operator
|
|
635
|
+
value['${}'.format(op)] = values
|
|
636
|
+
_json[self.field] = value
|
|
637
|
+
|
|
638
|
+
return _json
|
|
639
|
+
|
|
640
|
+
def print(self, indent=2):
|
|
641
|
+
print(json.dumps(self.prepare(), indent=indent))
|