digitalhub 0.9.0b3__py3-none-any.whl → 0.9.0b4__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.

Potentially problematic release.


This version of digitalhub might be problematic. Click here for more details.

@@ -168,7 +168,7 @@ class MaterialEntity(VersionedEntity):
168
168
  paths = store.upload(source, self.spec.path)
169
169
 
170
170
  # Update files info
171
- files_info = store.get_file_info(paths)
171
+ files_info = store.get_file_info(self.spec.path, paths)
172
172
  self._update_files_info(files_info)
173
173
 
174
174
  ##############################
@@ -736,6 +736,10 @@ class OperationsProcessor:
736
736
  """
737
737
  if not identifier.startswith("store://"):
738
738
  entity_id = identifier
739
+ else:
740
+ splt = identifier.split(":")
741
+ if len(splt) == 3:
742
+ identifier = f"{splt[0]}:{splt[1]}"
739
743
  return self.read_context_entity(
740
744
  identifier,
741
745
  entity_type=entity_type,
@@ -52,13 +52,17 @@ class Store:
52
52
  """
53
53
 
54
54
  @abstractmethod
55
- def upload(self, src: str | list[str], dst: str | None = None) -> list[tuple[str, str]]:
55
+ def upload(self, src: str | list[str], dst: str) -> list[tuple[str, str]]:
56
56
  """
57
57
  Method to upload artifact to storage.
58
58
  """
59
59
 
60
60
  @abstractmethod
61
- def get_file_info(self, paths: list[str]) -> list[dict]:
61
+ def get_file_info(
62
+ self,
63
+ root: str,
64
+ paths: list[tuple[str, str]],
65
+ ) -> list[dict]:
62
66
  """
63
67
  Method to get file metadata.
64
68
  """
@@ -61,7 +61,7 @@ class LocalStore(Store):
61
61
  """
62
62
  raise StoreError("Local store does not support download.")
63
63
 
64
- def upload(self, src: str | list[str], dst: str | None = None) -> list[tuple[str, str]]:
64
+ def upload(self, src: str | list[str], dst: str) -> list[tuple[str, str]]:
65
65
  """
66
66
  Upload an artifact to storage.
67
67
 
@@ -72,7 +72,11 @@ class LocalStore(Store):
72
72
  """
73
73
  raise StoreError("Local store does not support upload.")
74
74
 
75
- def get_file_info(self, paths: list[str]) -> list[dict]:
75
+ def get_file_info(
76
+ self,
77
+ root: str,
78
+ paths: list[tuple[str, str]],
79
+ ) -> list[dict]:
76
80
  """
77
81
  Method to get file metadata.
78
82
 
@@ -69,7 +69,7 @@ class RemoteStore(Store):
69
69
 
70
70
  return self._download_file(root, dst, overwrite)
71
71
 
72
- def upload(self, src: str | list[str], dst: str | None = None) -> list[tuple[str, str]]:
72
+ def upload(self, src: str | list[str], dst: str) -> list[tuple[str, str]]:
73
73
  """
74
74
  Upload an artifact to storage.
75
75
 
@@ -80,7 +80,11 @@ class RemoteStore(Store):
80
80
  """
81
81
  raise StoreError("Remote HTTP store does not support upload.")
82
82
 
83
- def get_file_info(self, paths: list[str]) -> list[dict]:
83
+ def get_file_info(
84
+ self,
85
+ root: str,
86
+ paths: list[tuple[str, str]],
87
+ ) -> list[dict]:
84
88
  """
85
89
  Get file information from HTTP(s) storage.
86
90
 
@@ -13,6 +13,7 @@ from digitalhub.readers.api import get_reader_by_object
13
13
  from digitalhub.stores._base.store import Store, StoreConfig
14
14
  from digitalhub.utils.exceptions import StoreError
15
15
  from digitalhub.utils.file_utils import get_file_info_from_s3, get_file_mime_type
16
+ from digitalhub.utils.s3_utils import get_bucket_name
16
17
 
17
18
  # Type aliases
18
19
  S3Client = Type["botocore.client.S3"]
@@ -76,7 +77,7 @@ class S3Store(Store):
76
77
  str
77
78
  Destination path of the downloaded artifact.
78
79
  """
79
- client, bucket = self._check_factory()
80
+ client, bucket = self._check_factory(root)
80
81
 
81
82
  # Build destination directory
82
83
  if dst.suffix == "":
@@ -126,14 +127,18 @@ class S3Store(Store):
126
127
  return str(Path(dst, trees[0]))
127
128
  return str(dst)
128
129
 
129
- def upload(self, src: str | list[str], dst: str | None = None) -> list[tuple[str, str]]:
130
+ def upload(
131
+ self,
132
+ src: str | list[str],
133
+ dst: str,
134
+ ) -> list[tuple[str, str]]:
130
135
  """
131
136
  Upload an artifact to storage.
132
137
 
133
138
  Parameters
134
139
  ----------
135
- src : str
136
- List of sources.
140
+ src : str | list[str]
141
+ Source(s).
137
142
  dst : str
138
143
  The destination of the artifact on storage.
139
144
 
@@ -143,18 +148,11 @@ class S3Store(Store):
143
148
  Returns the list of destination and source paths of the uploaded artifacts.
144
149
  """
145
150
  # Destination handling
151
+ key = self._get_key(dst)
146
152
 
147
- # If no destination is provided, build key from source
148
- # Otherwise build key from destination
149
- if dst is None:
150
- raise StoreError(
151
- "Destination must be provided. If source is a list of files or a directory, destination must be a partition, e.g. 's3://bucket/partition/' otherwise a destination key, e.g. 's3://bucket/key'"
152
- )
153
- else:
154
- dst = self._get_key(dst)
155
-
156
- # Source handling
157
- if not isinstance(src, list):
153
+ # Source handling (files list, dir or single file)
154
+ src_is_list = isinstance(src, list)
155
+ if not src_is_list:
158
156
  self._check_local_src(src)
159
157
  src_is_dir = Path(src).is_dir()
160
158
  else:
@@ -165,21 +163,31 @@ class S3Store(Store):
165
163
  src = src[0]
166
164
 
167
165
  # If source is a directory, destination must be a partition
168
- if (src_is_dir or isinstance(src, list)) and not dst.endswith("/"):
169
- raise StoreError("Destination must be a partition if the source is a directory or a list of files.")
166
+ if (src_is_dir or src_is_list) and not dst.endswith("/"):
167
+ raise StoreError(
168
+ "If source is a list of files or a directory, "
169
+ "destination must be a partition, e.g. 's3://bucket/partition/'"
170
+ )
171
+
172
+ # S3 client
173
+ client, bucket = self._check_factory(dst)
170
174
 
171
175
  # Directory
172
176
  if src_is_dir:
173
- return self._upload_dir(src, dst)
177
+ return self._upload_dir(src, key, client, bucket)
174
178
 
175
179
  # List of files
176
- elif isinstance(src, list):
177
- return self._upload_file_list(src, dst)
180
+ elif src_is_list:
181
+ return self._upload_file_list(src, key, client, bucket)
178
182
 
179
183
  # Single file
180
- return self._upload_single_file(src, dst)
184
+ return self._upload_single_file(src, key, client, bucket)
181
185
 
182
- def upload_fileobject(self, src: BytesIO, dst: str) -> str:
186
+ def upload_fileobject(
187
+ self,
188
+ src: BytesIO,
189
+ dst: str,
190
+ ) -> str:
183
191
  """
184
192
  Upload an BytesIO to S3 based storage.
185
193
 
@@ -188,18 +196,23 @@ class S3Store(Store):
188
196
  src : BytesIO
189
197
  The source object to be persisted.
190
198
  dst : str
191
- The destination partition for the artifact.
199
+ The destination path of the artifact.
192
200
 
193
201
  Returns
194
202
  -------
195
203
  str
196
204
  S3 key of the uploaded artifact.
197
205
  """
198
- client, bucket = self._check_factory()
199
- self._upload_fileobject(src, dst, client, bucket)
200
- return f"s3://{bucket}/{dst}"
206
+ client, bucket = self._check_factory(dst)
207
+ key = self._get_key(dst)
208
+ self._upload_fileobject(src, key, client, bucket)
209
+ return f"s3://{bucket}/{key}"
201
210
 
202
- def get_file_info(self, paths: list[tuple[str, str]]) -> list[dict]:
211
+ def get_file_info(
212
+ self,
213
+ root: str,
214
+ paths: list[tuple[str, str]],
215
+ ) -> list[dict]:
203
216
  """
204
217
  Method to get file metadata.
205
218
 
@@ -213,7 +226,7 @@ class S3Store(Store):
213
226
  list[dict]
214
227
  Returns files metadata.
215
228
  """
216
- client, bucket = self._check_factory()
229
+ client, bucket = self._check_factory(root)
217
230
 
218
231
  infos = []
219
232
  for i in paths:
@@ -264,7 +277,13 @@ class S3Store(Store):
264
277
  # Download file
265
278
  client.download_file(bucket, key, dst_pth)
266
279
 
267
- def _upload_dir(self, src: str, dst: str) -> list[tuple[str, str]]:
280
+ def _upload_dir(
281
+ self,
282
+ src: str,
283
+ dst: str,
284
+ client: S3Client,
285
+ bucket: str,
286
+ ) -> list[tuple[str, str]]:
268
287
  """
269
288
  Upload directory to storage.
270
289
 
@@ -274,14 +293,16 @@ class S3Store(Store):
274
293
  List of sources.
275
294
  dst : str
276
295
  The destination of the artifact on storage.
296
+ client : S3Client
297
+ The S3 client object.
298
+ bucket : str
299
+ The name of the S3 bucket.
277
300
 
278
301
  Returns
279
302
  -------
280
303
  list[tuple[str, str]]
281
304
  Returns the list of destination and source paths of the uploaded artifacts.
282
305
  """
283
- client, bucket = self._check_factory()
284
-
285
306
  # Get list of files
286
307
  src_pth = Path(src)
287
308
  files = [i for i in src_pth.rglob("*") if i.is_file()]
@@ -299,7 +320,13 @@ class S3Store(Store):
299
320
  paths.append((k, str(f.relative_to(src_pth))))
300
321
  return paths
301
322
 
302
- def _upload_file_list(self, src: list[str], dst: str) -> list[tuple[str, str]]:
323
+ def _upload_file_list(
324
+ self,
325
+ src: list[str],
326
+ dst: str,
327
+ client: S3Client,
328
+ bucket: str,
329
+ ) -> list[tuple[str, str]]:
303
330
  """
304
331
  Upload list of files to storage.
305
332
 
@@ -309,13 +336,16 @@ class S3Store(Store):
309
336
  List of sources.
310
337
  dst : str
311
338
  The destination of the artifact on storage.
339
+ client : S3Client
340
+ The S3 client object.
341
+ bucket : str
342
+ The name of the S3 bucket.
312
343
 
313
344
  Returns
314
345
  -------
315
346
  list[tuple[str, str]]
316
347
  Returns the list of destination and source paths of the uploaded artifacts.
317
348
  """
318
- client, bucket = self._check_factory()
319
349
  files = src
320
350
  keys = []
321
351
  for i in files:
@@ -330,7 +360,13 @@ class S3Store(Store):
330
360
  paths.append((k, Path(f).name))
331
361
  return paths
332
362
 
333
- def _upload_single_file(self, src: str, dst: str) -> str:
363
+ def _upload_single_file(
364
+ self,
365
+ src: str,
366
+ dst: str,
367
+ client: S3Client,
368
+ bucket: str,
369
+ ) -> str:
334
370
  """
335
371
  Upload a single file to storage.
336
372
 
@@ -340,14 +376,16 @@ class S3Store(Store):
340
376
  List of sources.
341
377
  dst : str
342
378
  The destination of the artifact on storage.
379
+ client : S3Client
380
+ The S3 client object.
381
+ bucket : str
382
+ The name of the S3 bucket.
343
383
 
344
384
  Returns
345
385
  -------
346
386
  str
347
387
  Returns the list of destination and source paths of the uploaded artifacts.
348
388
  """
349
- client, bucket = self._check_factory()
350
-
351
389
  if dst.endswith("/"):
352
390
  dst = f"{dst.removeprefix('/')}{Path(src).name}"
353
391
 
@@ -357,7 +395,12 @@ class S3Store(Store):
357
395
  return [(dst, name)]
358
396
 
359
397
  @staticmethod
360
- def _upload_file(src: str, key: str, client: S3Client, bucket: str) -> None:
398
+ def _upload_file(
399
+ src: str,
400
+ key: str,
401
+ client: S3Client,
402
+ bucket: str,
403
+ ) -> None:
361
404
  """
362
405
  Upload a file to S3 based storage. The function checks if the
363
406
  bucket is accessible.
@@ -384,7 +427,12 @@ class S3Store(Store):
384
427
  client.upload_file(Filename=src, Bucket=bucket, Key=key, ExtraArgs=extra_args)
385
428
 
386
429
  @staticmethod
387
- def _upload_fileobject(fileobj: BytesIO, key: str, client: S3Client, bucket: str) -> None:
430
+ def _upload_fileobject(
431
+ fileobj: BytesIO,
432
+ key: str,
433
+ client: S3Client,
434
+ bucket: str,
435
+ ) -> None:
388
436
  """
389
437
  Upload a fileobject to S3 based storage. The function checks if the bucket is accessible.
390
438
 
@@ -409,7 +457,13 @@ class S3Store(Store):
409
457
  # Datastore methods
410
458
  ##############################
411
459
 
412
- def write_df(self, df: Any, dst: str, extension: str | None = None, **kwargs) -> str:
460
+ def write_df(
461
+ self,
462
+ df: Any,
463
+ dst: str,
464
+ extension: str | None = None,
465
+ **kwargs,
466
+ ) -> str:
413
467
  """
414
468
  Write a dataframe to S3 based storage. Kwargs are passed to df.to_parquet().
415
469
 
@@ -419,6 +473,8 @@ class S3Store(Store):
419
473
  The dataframe.
420
474
  dst : str
421
475
  The destination path on S3 based storage.
476
+ extension : str
477
+ The extension of the file.
422
478
  **kwargs : dict
423
479
  Keyword arguments.
424
480
 
@@ -430,15 +486,13 @@ class S3Store(Store):
430
486
  fileobj = BytesIO()
431
487
  reader = get_reader_by_object(df)
432
488
  reader.write_df(df, fileobj, extension=extension, **kwargs)
433
-
434
- key = self._get_key(dst)
435
- return self.upload_fileobject(fileobj, key)
489
+ return self.upload_fileobject(fileobj, dst)
436
490
 
437
491
  ##############################
438
492
  # Helper methods
439
493
  ##############################
440
494
 
441
- def _get_bucket(self) -> str:
495
+ def _get_bucket(self, root: str) -> str:
442
496
  """
443
497
  Get the name of the S3 bucket from the URI.
444
498
 
@@ -447,7 +501,7 @@ class S3Store(Store):
447
501
  str
448
502
  The name of the S3 bucket.
449
503
  """
450
- return str(self.config.bucket_name)
504
+ return get_bucket_name(root)
451
505
 
452
506
  def _get_client(self) -> S3Client:
453
507
  """
@@ -465,7 +519,7 @@ class S3Store(Store):
465
519
  }
466
520
  return boto3.client("s3", **cfg)
467
521
 
468
- def _check_factory(self) -> tuple[S3Client, str]:
522
+ def _check_factory(self, root: str) -> tuple[S3Client, str]:
469
523
  """
470
524
  Check if the S3 bucket is accessible by sending a head_bucket request.
471
525
 
@@ -475,7 +529,7 @@ class S3Store(Store):
475
529
  A tuple containing the S3 client object and the name of the S3 bucket.
476
530
  """
477
531
  client = self._get_client()
478
- bucket = self._get_bucket()
532
+ bucket = self._get_bucket(root)
479
533
  self._check_access_to_storage(client, bucket)
480
534
  return client, bucket
481
535
 
@@ -99,7 +99,11 @@ class SqlStore(Store):
99
99
  table = self._get_table_name(root)
100
100
  return self._download_table(schema, table, str(dst))
101
101
 
102
- def upload(self, src: str | list[str], dst: str | None = None) -> list[tuple[str, str]]:
102
+ def upload(
103
+ self,
104
+ src: str | list[str],
105
+ dst: str,
106
+ ) -> list[tuple[str, str]]:
103
107
  """
104
108
  Upload an artifact to storage.
105
109
 
@@ -110,7 +114,11 @@ class SqlStore(Store):
110
114
  """
111
115
  raise StoreError("SQL store does not support upload.")
112
116
 
113
- def get_file_info(self, paths: list[str]) -> list[dict]:
117
+ def get_file_info(
118
+ self,
119
+ root: str,
120
+ paths: list[tuple[str, str]],
121
+ ) -> list[dict]:
114
122
  """
115
123
  Get file information from SQL based storage.
116
124
 
@@ -7,6 +7,23 @@ from urllib.parse import urlparse
7
7
  from boto3 import client as boto3_client
8
8
 
9
9
 
10
+ def get_bucket_name(path: str) -> str:
11
+ """
12
+ Get bucket name from path.
13
+
14
+ Parameters
15
+ ----------
16
+ path : str
17
+ The source path to get the key from.
18
+
19
+ Returns
20
+ -------
21
+ str
22
+ The bucket name.
23
+ """
24
+ return urlparse(path).netloc
25
+
26
+
10
27
  def get_bucket_and_key(path: str) -> tuple[str, str]:
11
28
  """
12
29
  Get bucket and key from path.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: digitalhub
3
- Version: 0.9.0b3
3
+ Version: 0.9.0b4
4
4
  Summary: Python SDK for Digitalhub
5
5
  Author-email: Fondazione Bruno Kessler <dslab@fbk.eu>, Matteo Martini <mmartini@fbk.eu>
6
6
  License: Apache License
@@ -40,7 +40,7 @@ digitalhub/entities/_base/entity/_constructors/uuid.py,sha256=QzG0nsVpGU2UDD5Cjp
40
40
  digitalhub/entities/_base/executable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  digitalhub/entities/_base/executable/entity.py,sha256=tNQmmABuY90eKWcxePPGu4iaZhDLyL9TdugKVcnnKSY,10079
42
42
  digitalhub/entities/_base/material/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
- digitalhub/entities/_base/material/entity.py,sha256=J262BLNeW9yYE_W_K07tnvigSI3BJzIXrPlxqow44M0,6914
43
+ digitalhub/entities/_base/material/entity.py,sha256=Gm87nZCKUIredCEucqwZ5T_QGG6cjSuWXKzrw15w-l4,6930
44
44
  digitalhub/entities/_base/material/spec.py,sha256=jL1OohnYhUSrdTaFF3Rkw817jIjNY0ewm1wB3tgQ_9c,436
45
45
  digitalhub/entities/_base/material/status.py,sha256=I9yxNLHvsHSRDkKcKGPxlPJrJ7grsrxHxId06wtqVXk,383
46
46
  digitalhub/entities/_base/material/utils.py,sha256=EL-p6XEYlPxQ33II2ish2sVx3hIdPcrgbSh5om7Xfls,2427
@@ -58,7 +58,7 @@ digitalhub/entities/_commons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
58
58
  digitalhub/entities/_commons/enums.py,sha256=pjhbOMzAABRPbV6XNt-2Lyn2kLWIFBAwpeboCtvnz1w,1861
59
59
  digitalhub/entities/_commons/utils.py,sha256=_HL6zFSCL_2ug4LpXcxK1MJQQhWL34wj1B2q0Ie0TKU,1792
60
60
  digitalhub/entities/_operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
- digitalhub/entities/_operations/processor.py,sha256=C5LHmV19Ovk5e4E329TbkdYqIrJ26UOQjnkYBHQk018,46654
61
+ digitalhub/entities/_operations/processor.py,sha256=iKNFvB78iPqkI6-elFr0oTF_p_MRDbDnKGDFYG2GUI4,46792
62
62
  digitalhub/entities/artifact/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  digitalhub/entities/artifact/crud.py,sha256=y69PyoWAYOx-Pl_wnds3M0xSLNbADpdV_xG4zElJ0aI,7824
64
64
  digitalhub/entities/artifact/utils.py,sha256=NNzD2AcIJzmV_Jo_8k5ZcSp2arKcZ07CCIYKn2lvoKM,1320
@@ -194,15 +194,15 @@ digitalhub/stores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
194
194
  digitalhub/stores/api.py,sha256=TwD8WXVuEPwtrmcyhP9SC0i7xkVHov5fpu94nHhZRHg,994
195
195
  digitalhub/stores/builder.py,sha256=kraGDfgV5cZ2QivXTWwbyz1FgAehgjlL9dmI6dxEc0U,5927
196
196
  digitalhub/stores/_base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
- digitalhub/stores/_base/store.py,sha256=Wc3bHLELO3WW7aQ5Dy9tqHh2nOx7L80cZ1tDwwpb1sQ,5255
197
+ digitalhub/stores/_base/store.py,sha256=QscqsAAgvYX9bAsoADKs0SkLahmMvvEHZ_NsBj2ri6k,5295
198
198
  digitalhub/stores/local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
199
- digitalhub/stores/local/store.py,sha256=nwOvLvM-DLSqsjlYZLLSoy2pr4pMnaunrwUSi2yNJco,6726
199
+ digitalhub/stores/local/store.py,sha256=_-0JEnGCEcKUrLeB2xf_CDGuSeAEXcNyX6JCvSWkU3M,6766
200
200
  digitalhub/stores/remote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
201
- digitalhub/stores/remote/store.py,sha256=NdA63gyWVKXHlxjoOqi8Vx1jttXDU4GcU0zohV9utjk,4194
201
+ digitalhub/stores/remote/store.py,sha256=g9u87NBfFBasHWSTn82ZRZ0QttpYpX_Y0g16xO1r-AQ,4234
202
202
  digitalhub/stores/s3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
203
- digitalhub/stores/s3/store.py,sha256=sM2hvSGxf5S6l80GpDzxyr3_v-wAYoMfV-oOiF6TOpc,16263
203
+ digitalhub/stores/s3/store.py,sha256=CzjdMyatPps8uW4HFKz-OZcOUlVlGebUX4jxrzp48Eg,16912
204
204
  digitalhub/stores/sql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
205
- digitalhub/stores/sql/store.py,sha256=epL1TGvWPFjpKBGxqkrfMOEA9-fjakNVbQwSo-YhfNw,10411
205
+ digitalhub/stores/sql/store.py,sha256=jhulvAIacR0HAomv25PCxG3mr6BKhF-9c9k0D5ruCQ8,10482
206
206
  digitalhub/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
207
207
  digitalhub/utils/data_utils.py,sha256=2eETyxml610Ij7uyDnNc3YiELl2WFLIkj3FL4y6EPk8,2733
208
208
  digitalhub/utils/exceptions.py,sha256=pL2C3vTCscHsjpqDqGN3OXu0bBn7NL9ENOoM2S37CyE,1139
@@ -211,7 +211,7 @@ digitalhub/utils/generic_utils.py,sha256=5flGSQ50UyzUtlnLPyIhZ6blijPGFxPITukfH-y
211
211
  digitalhub/utils/git_utils.py,sha256=aFYL1cpfY-2VnlW7eHmjjjlTLECc5UUUfjb_IQPOY5k,3244
212
212
  digitalhub/utils/io_utils.py,sha256=8jD4Rp_b7LZEpY5JSMxVUowZsnifKnbGpHT5Hijx9-g,3299
213
213
  digitalhub/utils/logger.py,sha256=ml3ne6D8wuRdNZ4F6ywmvWotSxjmZWnmKgNiuHb4R5M,437
214
- digitalhub/utils/s3_utils.py,sha256=oXLzp4K7o45IwK0XOMt4OElDyB09fKRic5WTNA82WUA,1113
214
+ digitalhub/utils/s3_utils.py,sha256=kbET2FL7UXfqBMgSpky-E3wO5SMjpaLbIAFtnGe2pXU,1383
215
215
  digitalhub/utils/uri_utils.py,sha256=IUbR9PjxHr2VghxRG3iyCGpMPSLvL17JLKLZp8kXsgg,3272
216
216
  test/test_crud_functions.py,sha256=tQs_QBaPCuYVSBpbl-he5_6jr_tteCXVmohj1ZluNsA,2769
217
217
  test/test_crud_runs.py,sha256=lkssy15UPJKymgazmi5gG6RLxyTsG-tM_CpNCowD2gQ,2220
@@ -223,8 +223,8 @@ test/local/CRUD/test_dataitems.py,sha256=LQqTzI59uwTGy4zoq8jL0yWVe2W9vXlatkgDU9a
223
223
  test/local/CRUD/test_models.py,sha256=msosbZuRwIMbZtmi3ZaOva4TjQ4lrzkNu9AguIFhrSo,2929
224
224
  test/local/imports/test_imports.py,sha256=W-YugO0rpJwvtWp57MXaXfEmE-f5iWuCiLY-n0ZU4z8,1271
225
225
  test/local/instances/test_validate.py,sha256=bGPKRFR_Tb5nlzzmI_ty_6UVUvYGseE2-pkNVoGWeO0,1842
226
- digitalhub-0.9.0b3.dist-info/LICENSE.txt,sha256=_yVOtnbW7Ss28mp058UEEc1X4Rgj8-kQBP_kj8_Sc88,11585
227
- digitalhub-0.9.0b3.dist-info/METADATA,sha256=3AXEwBDEr7vREKj1Jt-IySOXq_h9_QeAAjpuE6eM2VQ,15316
228
- digitalhub-0.9.0b3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
229
- digitalhub-0.9.0b3.dist-info/top_level.txt,sha256=ae9pDfCF27ZoaVAxuBKONMP0lm5P-N_I-e-no1WlvD8,16
230
- digitalhub-0.9.0b3.dist-info/RECORD,,
226
+ digitalhub-0.9.0b4.dist-info/LICENSE.txt,sha256=_yVOtnbW7Ss28mp058UEEc1X4Rgj8-kQBP_kj8_Sc88,11585
227
+ digitalhub-0.9.0b4.dist-info/METADATA,sha256=C6m2lVyVZnLBcNRPOT2T08DERYbwS3ZAEtF192-1jdA,15316
228
+ digitalhub-0.9.0b4.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
229
+ digitalhub-0.9.0b4.dist-info/top_level.txt,sha256=ae9pDfCF27ZoaVAxuBKONMP0lm5P-N_I-e-no1WlvD8,16
230
+ digitalhub-0.9.0b4.dist-info/RECORD,,