dtlpy 1.114.13__py3-none-any.whl → 1.114.15__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.
@@ -4,18 +4,24 @@ import re
4
4
  from .. import entities, miscellaneous, exceptions, _api_reference
5
5
  from ..services.api_client import ApiClient
6
6
 
7
- logger = logging.getLogger(name='dtlpy')
7
+ logger = logging.getLogger(name="dtlpy")
8
8
 
9
9
 
10
10
  class Drivers:
11
11
  """
12
12
  Drivers Repository
13
-
13
+
14
14
  The Drivers class allows users to manage drivers that are used to connect with external storage.
15
15
  Read more about external storage in our `documentation <https://dataloop.ai/docs/overview-1>`_ and `developers' docs <https://developers.dataloop.ai/tutorials/data_management/>`_.
16
16
  """
17
17
 
18
18
  def __init__(self, client_api: ApiClient, project: entities.Project = None):
19
+ """
20
+ Initialize the Drivers repository.
21
+
22
+ :param ApiClient client_api: The API client instance
23
+ :param Project project: Optional project entity. If not provided, will try to get from checkout
24
+ """
19
25
  self._client_api = client_api
20
26
  self._project = project
21
27
 
@@ -26,38 +32,51 @@ class Drivers:
26
32
  def project(self) -> entities.Project:
27
33
  if self._project is None:
28
34
  # try get checkout
29
- project = self._client_api.state_io.get('project')
35
+ project = self._client_api.state_io.get("project")
30
36
  if project is not None:
31
37
  self._project = entities.Project.from_json(_json=project, client_api=self._client_api)
32
38
  if self._project is None:
33
39
  raise exceptions.PlatformException(
34
- error='2001',
35
- message='Cannot perform action WITHOUT Project entity in Drivers repository.'
36
- ' Please checkout or set a project')
40
+ error="2001",
41
+ message="Cannot perform action WITHOUT Project entity in Drivers repository."
42
+ " Please checkout or set a project",
43
+ )
37
44
  assert isinstance(self._project, entities.Project)
38
45
  return self._project
39
46
 
40
47
  @project.setter
41
48
  def project(self, project: entities.Project):
49
+ """
50
+ Set the project for this Drivers repository.
51
+
52
+ :param Project project: The project entity to set
53
+ :raises ValueError: If the provided project is not a valid Project entity
54
+ """
42
55
  if not isinstance(project, entities.Project):
43
- raise ValueError('Must input a valid Project entity')
56
+ raise ValueError("Must input a valid Project entity")
44
57
  self._project = project
45
58
 
46
59
  ###########
47
60
  # methods #
48
61
  ###########
49
62
  def __get_by_id(self, driver_id) -> entities.Driver:
50
- success, response = self._client_api.gen_request(req_type='get',
51
- path='/drivers/{}'.format(driver_id))
63
+ """
64
+ Get a driver by its ID from the platform.
65
+
66
+ :param str driver_id: The driver ID
67
+ :return: Driver object
68
+ :rtype: dtlpy.entities.driver.Driver
69
+ :raises PlatformException: If the driver is not found or there's an API error
70
+ """
71
+ success, response = self._client_api.gen_request(req_type="get", path="/drivers/{}".format(driver_id))
52
72
  if success:
53
73
  _json = response.json()
54
- driver = self._getDriverClass(_json).from_json(client_api=self._client_api,
55
- _json=_json)
74
+ driver = self._getDriverClass(_json).from_json(client_api=self._client_api, _json=_json)
56
75
  else:
57
76
  raise exceptions.PlatformException(response)
58
77
  return driver
59
78
 
60
- @_api_reference.add(path='/drivers', method='get')
79
+ @_api_reference.add(path="/drivers", method="get")
61
80
  def list(self) -> miscellaneous.List[entities.Driver]:
62
81
  """
63
82
  Get the project's drivers list.
@@ -75,17 +94,28 @@ class Drivers:
75
94
 
76
95
  """
77
96
 
78
- success, response = self._client_api.gen_request(req_type='get',
79
- path='/drivers?projectId={}'.format(self.project.id))
97
+ success, response = self._client_api.gen_request(
98
+ req_type="get", path="/drivers?projectId={}".format(self.project.id)
99
+ )
80
100
  if not success:
81
101
  raise exceptions.PlatformException(response)
82
- drivers = miscellaneous.List([self._getDriverClass(_json).from_json(_json=_json,
83
- client_api=self._client_api) for _json in
84
- response.json()])
102
+ drivers = miscellaneous.List(
103
+ [
104
+ self._getDriverClass(_json).from_json(_json=_json, client_api=self._client_api)
105
+ for _json in response.json()
106
+ ]
107
+ )
85
108
  return drivers
86
109
 
87
110
  def _getDriverClass(self, _json):
88
- driver_type = _json.get('type', None)
111
+ """
112
+ Determine the appropriate driver class based on the driver type in the JSON response.
113
+
114
+ :param dict _json: The JSON response containing driver information
115
+ :return: The appropriate driver class (S3Driver, GcsDriver, AzureBlobDriver, or Driver)
116
+ :rtype: type
117
+ """
118
+ driver_type = _json.get("type", None)
89
119
  if driver_type == entities.ExternalStorage.S3:
90
120
  driver_class = entities.S3Driver
91
121
  elif driver_type == entities.ExternalStorage.GCS:
@@ -96,10 +126,8 @@ class Drivers:
96
126
  driver_class = entities.Driver
97
127
  return driver_class
98
128
 
99
- @_api_reference.add(path='/drivers/{id}', method='get')
100
- def get(self,
101
- driver_name: str = None,
102
- driver_id: str = None) -> entities.Driver:
129
+ @_api_reference.add(path="/drivers/{id}", method="get")
130
+ def get(self, driver_name: str = None, driver_id: str = None) -> entities.Driver:
103
131
  """
104
132
  Get a Driver object to use in your code.
105
133
 
@@ -125,35 +153,238 @@ class Drivers:
125
153
  driver = [driver for driver in drivers if driver.name == driver_name]
126
154
  if not driver:
127
155
  # list is empty
128
- raise exceptions.PlatformException(error='404',
129
- message='Driver not found. Name: {}'.format(driver_name))
156
+ raise exceptions.PlatformException(
157
+ error="404", message="Driver not found. Name: {}".format(driver_name)
158
+ )
130
159
  # driver = None
131
160
  elif len(driver) > 1:
132
161
  # more than one matching driver
133
162
  raise exceptions.PlatformException(
134
- error='404',
135
- message='More than one driver with same name. Please "get" by id')
163
+ error="404", message='More than one driver with same name. Please "get" by id'
164
+ )
136
165
  else:
137
166
  driver = driver[0]
138
167
  else:
139
- raise exceptions.PlatformException(
140
- error='400',
141
- message='Must provide an identifier (name or id) in inputs')
168
+ raise exceptions.PlatformException(error="400", message="Must provide an identifier (name or id) in inputs")
142
169
  return driver
143
170
 
144
- @_api_reference.add(path='/drivers', method='post')
145
- def create(self,
146
- name: str,
147
- driver_type: entities.ExternalStorage,
148
- integration_id: str,
149
- bucket_name: str,
150
- integration_type: entities.IntegrationType,
151
- project_id: str = None,
152
- allow_external_delete: bool = True,
153
- region: str = None,
154
- storage_class: str = "",
155
- path: str = "",
156
- endpoint: str = None):
171
+ @_api_reference.add(path="/drivers", method="post")
172
+ def _create_driver(self, payload: dict):
173
+ """
174
+ Create a driver on the platform using the provided payload.
175
+
176
+ :param dict payload: The driver creation payload
177
+ :return: The created driver object
178
+ :rtype: dtlpy.entities.driver.Driver
179
+ :raises PlatformException: If the driver creation fails
180
+ """
181
+ success, response = self._client_api.gen_request(req_type="post", path="/drivers", json_req=payload)
182
+ if not success:
183
+ raise exceptions.PlatformException(response)
184
+ else:
185
+ _json = response.json()
186
+ return self._getDriverClass(_json).from_json(_json=_json, client_api=self._client_api)
187
+
188
+ def create_powerscale_s3(
189
+ self,
190
+ name: str,
191
+ integration: entities.Integration,
192
+ elastic_index: str,
193
+ endpoint: str,
194
+ bucket_name: str,
195
+ region: str,
196
+ elastic_index_path: str,
197
+ path: str = None,
198
+ project_id: str = None,
199
+ allow_external_delete: bool = False
200
+ ):
201
+ """
202
+ Create a PowerScale S3 driver.
203
+
204
+ **Prerequisites**: You must be in the role of an *owner* or *developer*.
205
+
206
+ :param str name: The driver name
207
+ :param Integration integration: The S3 integration to use
208
+ :param str elastic_index: The elastic index for PowerScale S3 driver
209
+ :param str project_id: Optional project ID. If not provided, uses the current project
210
+ :param bool allow_external_delete: True to allow deleting files from external storage when files are deleted in your Dataloop storage
211
+ :param str endpoint: The endpoint URL. Must be in the format 'http://<hostname>:<port>' or 'https://<hostname>:<port>'
212
+ :param str bucket_name: The external bucket name
213
+ :param str region: The bucket region (relevant for S3)
214
+ :param str elastic_index_path: The elastic index path for PowerScale S3 driver
215
+ :param str path: The path to the NFS driver
216
+ :return: The created PowerScale S3 driver object
217
+ :rtype: dtlpy.entities.driver.Driver
218
+ :raises ValueError: If the integration type is not S3
219
+ :raises PlatformException: If the driver creation fails
220
+
221
+ **Example**:
222
+
223
+ .. code-block:: python
224
+
225
+ project.drivers.create_powerscale_s3(
226
+ name='powerscale_driver',
227
+ integration=integration,
228
+ elastic_index='my_index',
229
+ elastic_index_path='my_index_path',
230
+ endpoint='http://location:8765',
231
+ bucket_name='my_bucket',
232
+ region='us-west-1',
233
+ path='my_path'
234
+ )
235
+ """
236
+ if not integration.type == entities.IntegrationType.S3:
237
+ raise ValueError("Integration type must be S3 for PowerScale S3 driver")
238
+
239
+ payload = {
240
+ "integrationId": integration.id,
241
+ "integrationType": integration.type,
242
+ "name": name,
243
+ "metadata": {"system": {"projectId": self.project.id if project_id is None else project_id}},
244
+ "type": entities.ExternalStorage.POWERSCALE_S3,
245
+ "payload": {
246
+ "elasticIndex": elastic_index,
247
+ "endpoint": endpoint,
248
+ "path": path,
249
+ "elasticIndexPath": elastic_index_path,
250
+ "bucketName": bucket_name,
251
+ "region": region
252
+ },
253
+ "allowExternalDelete": allow_external_delete,
254
+ "creator": self._client_api.info().get("user_email"),
255
+ }
256
+ return self._create_driver(payload)
257
+
258
+
259
+ def create_powerscale_nfs(
260
+ self,
261
+ name: str,
262
+ integration: entities.Integration,
263
+ elastic_index: str,
264
+ elastic_index_path: str,
265
+ project_id: str = None,
266
+ allow_external_delete: bool = False
267
+ ):
268
+ """
269
+ Create a PowerScale NFS driver.
270
+
271
+ **Prerequisites**: You must be in the role of an *owner* or *developer*.
272
+
273
+ :param str name: The driver name
274
+ :param Integration integration: The S3 integration to use
275
+ :param str elastic_index: The elastic index for PowerScale NFS driver
276
+ :param str project_id: Optional project ID. If not provided, uses the current project
277
+ :param bool allow_external_delete: True to allow deleting files from external storage when files are deleted in your Dataloop storage
278
+ :param str elastic_index_path: The elastic index path for PowerScale NFS driver
279
+ :return: The created PowerScale NFS driver object
280
+ :rtype: dtlpy.entities.driver.Driver
281
+ :raises ValueError: If the integration type is not S3
282
+ :raises PlatformException: If the driver creation fails
283
+
284
+ **Example**:
285
+
286
+ .. code-block:: python
287
+
288
+ project.drivers.create_powerscale_nfs(
289
+ name='powerscale_driver',
290
+ integration=integration,
291
+ elastic_index='my_index',
292
+ elastic_index_path='my_index_path',
293
+ )
294
+ """
295
+ if not integration.type == entities.IntegrationType.S3:
296
+ raise ValueError("Integration type must be S3 for PowerScale NFS driver")
297
+
298
+ payload = {
299
+ "integrationId": integration.id,
300
+ "integrationType": integration.type,
301
+ "name": name,
302
+ "metadata": {"system": {"projectId": self.project.id if project_id is None else project_id}},
303
+ "type": entities.ExternalStorage.POWERSCALE_NFS,
304
+ "payload": {"elasticIndex": elastic_index, "elasticIndexPath": elastic_index_path},
305
+ "allowExternalDelete": allow_external_delete,
306
+ "creator": self._client_api.info().get("user_email"),
307
+ }
308
+ return self._create_driver(payload)
309
+
310
+ def create_min_io(
311
+ self,
312
+ name: str,
313
+ integration: entities.Integration,
314
+ bucket_name: str,
315
+ endpoint: str,
316
+ project_id: str = None,
317
+ allow_external_delete: bool = True,
318
+ region: str = None,
319
+ storage_class: str = "",
320
+ path: str = "",
321
+ ):
322
+ """
323
+ Create a MinIO driver.
324
+
325
+ **Prerequisites**: You must be in the role of an *owner* or *developer*.
326
+
327
+ :param str name: The driver name
328
+ :param Integration integration: The S3 integration to use
329
+ :param str bucket_name: The external bucket name
330
+ :param str endpoint: The MinIO endpoint URL. Must be in the format 'http://<hostname>:<port>' or 'https://<hostname>:<port>'
331
+ :param str project_id: Optional project ID. If not provided, uses the current project
332
+ :param bool allow_external_delete: True to allow deleting files from external storage when files are deleted in your Dataloop storage
333
+ :param str region: The bucket region (relevant for S3)
334
+ :param str storage_class: The storage class (relevant for S3)
335
+ :param str path: Optional path. By default path is the root folder. Path is case sensitive
336
+ :return: The created MinIO driver object
337
+ :rtype: dtlpy.entities.driver.Driver
338
+ :raises ValueError: If the integration type is not S3 or if the endpoint URL format is invalid
339
+ :raises PlatformException: If the driver creation fails
340
+
341
+ **Example**:
342
+
343
+ .. code-block:: python
344
+
345
+ project.drivers.create_min_io(
346
+ name='minio_driver',
347
+ integration=integration,
348
+ bucket_name='my_bucket',
349
+ endpoint='http://localhost:9000'
350
+ )
351
+ """
352
+ if not integration.type == entities.IntegrationType.S3:
353
+ raise ValueError("Integration type must be S3 for Minio driver")
354
+
355
+ if not re.match(r"^https?://[A-Za-z0-9.-]+:\d+$", endpoint):
356
+ raise ValueError(
357
+ f"Invalid endpoint URL '{endpoint}'. Must be 'http://<hostname>:<port>' or 'https://<hostname>:<port>'."
358
+ )
359
+
360
+ payload = {
361
+ "integrationId": integration.id,
362
+ "integrationType": integration.type,
363
+ "name": name,
364
+ "metadata": {"system": {"projectId": self.project.id if project_id is None else project_id}},
365
+ "type": entities.ExternalStorage.MIN_IO,
366
+ "payload": {"bucketName": bucket_name, "storageClass": storage_class, "region": region, "path": path, "endpoint": endpoint},
367
+ "allowExternalDelete": allow_external_delete,
368
+ "creator": self._client_api.info().get("user_email"),
369
+ }
370
+
371
+ return self._create_driver(payload)
372
+
373
+
374
+ def create(
375
+ self,
376
+ name: str,
377
+ driver_type: entities.ExternalStorage,
378
+ integration_id: str,
379
+ bucket_name: str,
380
+ integration_type: entities.IntegrationType,
381
+ project_id: str = None,
382
+ allow_external_delete: bool = True,
383
+ region: str = None,
384
+ storage_class: str = "",
385
+ path: str = "",
386
+ endpoint: str = None
387
+ ):
157
388
  """
158
389
  Create a storage driver.
159
390
 
@@ -169,7 +400,7 @@ class Drivers:
169
400
  :param str region: relevant only for s3 - the bucket region
170
401
  :param str storage_class: relevant only for s3
171
402
  :param str path: Optional. By default path is the root folder. Path is case sensitive integration
172
- :param endpoint path: Optional. Custom endpoint for S3 storage. Must be in the format 'http://<hostname>:<port>' or 'https://<hostname>:<port>'.
403
+ :param str endpoint: Optional. Custom endpoint for minio storage. Must be in the format 'http://<hostname>:<port>' or 'https://<hostname>:<port>'.
173
404
  :return: driver object
174
405
  :rtype: dtlpy.entities.driver.Driver
175
406
 
@@ -187,53 +418,35 @@ class Drivers:
187
418
  if integration_type is None:
188
419
  integration_type = driver_type
189
420
  if driver_type == entities.ExternalStorage.S3:
190
- bucket_payload = 'bucketName'
421
+ bucket_payload = "bucketName"
191
422
  if endpoint:
192
- if not re.match(r'^https?://[A-Za-z0-9.-]+:\d+$', endpoint):
423
+ if not re.match(r"^https?://[A-Za-z0-9.-]+:\d+$", endpoint):
193
424
  raise ValueError(
194
425
  f"Invalid endpoint URL '{endpoint}'. Must be 'http://<hostname>:<port>' or 'https://<hostname>:<port>'."
195
426
  )
427
+
196
428
  elif driver_type == entities.ExternalStorage.GCS:
197
- bucket_payload = 'bucket'
429
+ bucket_payload = "bucket"
198
430
  else:
199
- bucket_payload = 'containerName'
431
+ bucket_payload = "containerName"
200
432
  payload = {
201
433
  "integrationId": integration_id,
202
- 'integrationType': integration_type,
434
+ "integrationType": integration_type,
203
435
  "name": name,
204
- "metadata": {
205
- "system": {
206
- "projectId": self.project.id if project_id is None else project_id
207
- }
208
- },
436
+ "metadata": {"system": {"projectId": self.project.id if project_id is None else project_id}},
209
437
  "type": driver_type,
210
- "payload": {
211
- bucket_payload: bucket_name,
212
- "storageClass": storage_class,
213
- "region": region,
214
- "path": path
215
- },
438
+ "payload": {bucket_payload: bucket_name, "storageClass": storage_class, "region": region, "path": path},
216
439
  "allowExternalDelete": allow_external_delete,
217
- "creator": self._client_api.info().get('user_email')
440
+ "creator": self._client_api.info().get("user_email"),
218
441
  }
219
- if endpoint and driver_type == entities.ExternalStorage.S3:
220
- payload['payload']['endpoint'] = endpoint
221
442
 
222
- success, response = self._client_api.gen_request(req_type='post',
223
- path='/drivers',
224
- json_req=payload)
225
- if not success:
226
- raise exceptions.PlatformException(response)
227
- else:
228
- _json = response.json()
229
- return self._getDriverClass(_json).from_json(_json=_json, client_api=self._client_api)
443
+ if endpoint and driver_type == entities.ExternalStorage.S3:
444
+ payload["payload"]["endpoint"] = endpoint
230
445
 
231
- @_api_reference.add(path='/drivers/{id}', method='delete')
232
- def delete(self,
233
- driver_name: str = None,
234
- driver_id: str = None,
235
- sure: bool = False,
236
- really: bool = False):
446
+ return self._create_driver(payload)
447
+
448
+ @_api_reference.add(path="/drivers/{id}", method="delete")
449
+ def delete(self, driver_name: str = None, driver_id: str = None, sure: bool = False, really: bool = False):
237
450
  """
238
451
  Delete a driver forever!
239
452
 
@@ -254,13 +467,12 @@ class Drivers:
254
467
  """
255
468
  if sure and really:
256
469
  driver = self.get(driver_name=driver_name, driver_id=driver_id)
257
- success, response = self._client_api.gen_request(req_type='delete',
258
- path='/drivers/{}'.format(driver.id))
470
+ success, response = self._client_api.gen_request(req_type="delete", path="/drivers/{}".format(driver.id))
259
471
  if not success:
260
472
  raise exceptions.PlatformException(response)
261
- logger.info('Driver {!r} was deleted successfully'.format(driver.name))
473
+ logger.info("Driver {!r} was deleted successfully".format(driver.name))
262
474
  return True
263
475
  else:
264
476
  raise exceptions.PlatformException(
265
- error='403',
266
- message='Cant delete driver from SDK. Please login to platform to delete')
477
+ error="403", message="Cant delete driver from SDK. Please login to platform to delete"
478
+ )