bluer-objects 6.107.1__py3-none-any.whl → 6.133.1__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 bluer-objects might be problematic. Click here for more details.

@@ -11,10 +11,13 @@ function test_bluer_objects_storage() {
11
11
  create_test_asset \
12
12
  --object_name $object_name
13
13
  [[ $? -ne 0 ]] && return 1
14
+ bluer_ai_hr
14
15
 
15
- # testing upload
16
+ bluer_objects_ls local $object_name
17
+ [[ $? -ne 0 ]] && return 1
16
18
  bluer_ai_hr
17
19
 
20
+ # upload
18
21
  bluer_objects_upload \
19
22
  filename=this.yaml \
20
23
  $object_name
@@ -33,12 +36,15 @@ function test_bluer_objects_storage() {
33
36
  [[ $? -ne 0 ]] && return 1
34
37
  bluer_ai_hr
35
38
 
39
+ bluer_objects_ls cloud $object_name
40
+ [[ $? -ne 0 ]] && return 1
41
+ bluer_ai_hr
42
+
36
43
  # clean-up
37
44
  rm -rfv $object_path
38
45
  bluer_ai_hr
39
46
 
40
- # testing download
41
-
47
+ # download
42
48
  bluer_objects_download \
43
49
  filename=this.yaml \
44
50
  $object_name
bluer_objects/__init__.py CHANGED
@@ -4,7 +4,7 @@ ICON = "🌀"
4
4
 
5
5
  DESCRIPTION = f"{ICON} Object management in Bash."
6
6
 
7
- VERSION = "6.107.1"
7
+ VERSION = "6.133.1"
8
8
 
9
9
  REPO_NAME = "bluer-objects"
10
10
 
bluer_objects/config.env CHANGED
@@ -1,3 +1,3 @@
1
1
  ABCLI_MLFLOW_EXPERIMENT_PREFIX=experiment/
2
2
 
3
- BLUER_OBJECTS_STORAGE_INTERFACE=webdavzip
3
+ BLUER_OBJECTS_STORAGE_INTERFACE=webdav-request
@@ -150,6 +150,8 @@ def download(
150
150
  return True
151
151
 
152
152
  try:
153
+ os.makedirs(path(filename), exist_ok=True)
154
+
153
155
  # https://stackoverflow.com/a/27406501
154
156
  with urllib3.PoolManager().request(
155
157
  "GET", url, preload_content=False
@@ -82,13 +82,6 @@ class WebDAVInterface(StorageInterface):
82
82
  log=log,
83
83
  )
84
84
 
85
- def ls(
86
- self,
87
- object_name: str,
88
- where: str = "local",
89
- ) -> Tuple[bool, List[str]]:
90
- assert False, "not implemented"
91
-
92
85
  def upload(
93
86
  self,
94
87
  object_name: str,
@@ -0,0 +1,346 @@
1
+ import requests
2
+ from requests.auth import HTTPBasicAuth
3
+ import glob
4
+ from typing import Tuple, List
5
+ from xml.etree import ElementTree as ET
6
+ from tqdm import tqdm
7
+
8
+ from bluer_objects.storage.base import StorageInterface
9
+ from bluer_objects import env, file, path
10
+ from bluer_objects import objects
11
+ from bluer_objects.logger import logger
12
+
13
+
14
+ # https://chatgpt.com/c/6824cf43-6738-8005-8733-54b6a77f20ee
15
+ class WebDAVRequestInterface(StorageInterface):
16
+ name = "webdav-request"
17
+
18
+ def clear(
19
+ self,
20
+ do_dryrun: bool = True,
21
+ log: bool = True,
22
+ ) -> bool:
23
+ logger.info(
24
+ "{}.clear({})".format(
25
+ self.__class__.__name__,
26
+ "dryrun" if do_dryrun else "",
27
+ )
28
+ )
29
+
30
+ success, list_of_objects = self.list_raw(
31
+ suffix="",
32
+ recursive=False,
33
+ )
34
+ if not success:
35
+ return False
36
+
37
+ count: int = 0
38
+ for thing in tqdm(list_of_objects):
39
+ thing_name = thing.split(f"{env.WEBDAV_LOGIN}/", 1)[1]
40
+ if not thing_name.startswith("test"):
41
+ continue
42
+
43
+ if not thing_name.endswith("/"):
44
+ continue
45
+
46
+ if not self.delete(
47
+ object_name=thing_name.split("/", 1)[0],
48
+ do_dryrun=do_dryrun,
49
+ log=log,
50
+ ):
51
+ return False
52
+
53
+ count += 1
54
+
55
+ logger.info(f"deleted {count} object(s).")
56
+ return True
57
+
58
+ def delete(
59
+ self,
60
+ object_name: str,
61
+ do_dryrun: bool = True,
62
+ log: bool = True,
63
+ ) -> bool:
64
+ if log:
65
+ logger.info(
66
+ "{}.delete({}){}".format(
67
+ self.__class__.__name__,
68
+ object_name,
69
+ " dryrun" if do_dryrun else "",
70
+ )
71
+ )
72
+ if do_dryrun:
73
+ return True
74
+
75
+ try:
76
+ response = requests.request(
77
+ method="DELETE",
78
+ url=f"{env.WEBDAV_HOSTNAME}/{object_name}/",
79
+ auth=HTTPBasicAuth(
80
+ env.WEBDAV_LOGIN,
81
+ env.WEBDAV_PASSWORD,
82
+ ),
83
+ )
84
+ except Exception as e:
85
+ logger.error(e)
86
+ return False
87
+
88
+ if response.status_code in [200, 204]:
89
+ return True
90
+
91
+ logger.error(f"failed to delete: {response.status_code} - {response.text}")
92
+ return False
93
+
94
+ def mkdir(
95
+ self,
96
+ path: str,
97
+ log: bool = True,
98
+ ) -> bool:
99
+ url = f"{env.WEBDAV_HOSTNAME}/"
100
+ for folder in path.split("/"):
101
+ url = f"{url}{folder}/"
102
+
103
+ try:
104
+ response = requests.request(
105
+ "MKCOL",
106
+ url,
107
+ auth=HTTPBasicAuth(
108
+ env.WEBDAV_LOGIN,
109
+ env.WEBDAV_PASSWORD,
110
+ ),
111
+ )
112
+ except Exception as e:
113
+ logger.error(e)
114
+ return False
115
+
116
+ if response.status_code == 405: # Already exists
117
+ continue
118
+
119
+ if response.status_code == 201: # Created
120
+ if log:
121
+ logger.info(
122
+ "{}.mkdir {}".format(
123
+ self.__class__.__name__,
124
+ url.split(env.WEBDAV_HOSTNAME, 1)[1],
125
+ )
126
+ )
127
+ continue
128
+
129
+ logger.error(f"failed to create: {response.status_code} - {response.text}")
130
+ return False
131
+
132
+ return True
133
+
134
+ def download(
135
+ self,
136
+ object_name: str,
137
+ filename: str = "",
138
+ log: bool = True,
139
+ ) -> bool:
140
+ if filename:
141
+ local_path = objects.path_of(
142
+ object_name=object_name,
143
+ filename=filename,
144
+ create=True,
145
+ )
146
+
147
+ if not path.create(file.path(local_path)):
148
+ return False
149
+
150
+ url = f"{env.WEBDAV_HOSTNAME}/{object_name}/{filename}"
151
+
152
+ try:
153
+ response = requests.get(
154
+ url,
155
+ auth=HTTPBasicAuth(
156
+ env.WEBDAV_LOGIN,
157
+ env.WEBDAV_PASSWORD,
158
+ ),
159
+ )
160
+ except Exception as e:
161
+ logger.error(e)
162
+ return False
163
+
164
+ if response.status_code == 404: # object not found
165
+ return True
166
+
167
+ if response.status_code == 200:
168
+ try:
169
+ with open(local_path, "wb") as file_:
170
+ file_.write(response.content)
171
+ except Exception as e:
172
+ logger.error(e)
173
+ return False
174
+
175
+ return super().download(
176
+ object_name=object_name,
177
+ filename=filename,
178
+ log=log,
179
+ )
180
+
181
+ logger.error(f"failed to download: {response.status_code}")
182
+ return False
183
+
184
+ success, list_of_files = self.ls(
185
+ object_name=object_name,
186
+ where="cloud",
187
+ )
188
+ if not success:
189
+ return False
190
+
191
+ for filename_ in tqdm(list_of_files):
192
+ if not self.download(
193
+ object_name=object_name,
194
+ filename=filename_,
195
+ log=log,
196
+ ):
197
+ return False
198
+
199
+ return True
200
+
201
+ def list_raw(
202
+ self,
203
+ suffix: str,
204
+ recursive: bool,
205
+ ) -> Tuple[bool, List[str]]:
206
+ # https://chatgpt.com/c/6824f8d3-d9c0-8005-a7fa-d646f812f4b7
207
+ headers = {
208
+ "Depth": "infinity" if recursive else "1",
209
+ "Content-Type": "application/xml",
210
+ }
211
+
212
+ # Minimal PROPFIND XML body
213
+ data = """<?xml version="1.0"?>
214
+ <d:propfind xmlns:d="DAV:">
215
+ <d:prop><d:displayname/></d:prop>
216
+ </d:propfind>"""
217
+
218
+ try:
219
+ response = requests.request(
220
+ method="PROPFIND",
221
+ url=f"{env.WEBDAV_HOSTNAME}/{suffix}",
222
+ data=data,
223
+ headers=headers,
224
+ auth=HTTPBasicAuth(
225
+ env.WEBDAV_LOGIN,
226
+ env.WEBDAV_PASSWORD,
227
+ ),
228
+ )
229
+ except Exception as e:
230
+ logger.error(e)
231
+ return False, []
232
+
233
+ if response.status_code == 404: # object not found
234
+ return True, []
235
+
236
+ if response.status_code in (207, 207):
237
+ tree = ET.fromstring(response.content)
238
+ ns = {"d": "DAV:"}
239
+ list_of_files = []
240
+ for resp in tree.findall("d:response", ns):
241
+ href = resp.find("d:href", ns).text
242
+ list_of_files.append(href)
243
+
244
+ return True, list_of_files
245
+
246
+ logger.error(f"failed to list: {response.status_code} - {response.text}")
247
+ return False, []
248
+
249
+ def ls(
250
+ self,
251
+ object_name: str,
252
+ where: str = "local",
253
+ ) -> Tuple[bool, List[str]]:
254
+ if where == "cloud":
255
+ success, list_of_files = self.list_raw(
256
+ suffix=f"{object_name}/",
257
+ recursive=True,
258
+ )
259
+
260
+ return success, sorted(
261
+ [
262
+ filename
263
+ for filename in [
264
+ filename.split(f"{env.WEBDAV_LOGIN}/{object_name}/", 1)[1]
265
+ for filename in list_of_files
266
+ if not filename.endswith("/")
267
+ ]
268
+ if filename
269
+ ]
270
+ )
271
+
272
+ return super().ls(
273
+ object_name=object_name,
274
+ where=where,
275
+ )
276
+
277
+ def upload(
278
+ self,
279
+ object_name: str,
280
+ filename: str = "",
281
+ log: bool = True,
282
+ ) -> bool:
283
+ if filename:
284
+ if not self.mkdir(
285
+ path="{}/{}".format(
286
+ object_name,
287
+ file.path(filename),
288
+ ),
289
+ log=log,
290
+ ):
291
+ return False
292
+
293
+ url = f"{env.WEBDAV_HOSTNAME}/{object_name}/{filename}"
294
+
295
+ local_path = objects.path_of(
296
+ object_name=object_name,
297
+ filename=filename,
298
+ )
299
+
300
+ try:
301
+ with open(local_path, "rb") as file_data:
302
+ response = requests.put(
303
+ url,
304
+ data=file_data,
305
+ auth=HTTPBasicAuth(
306
+ env.WEBDAV_LOGIN,
307
+ env.WEBDAV_PASSWORD,
308
+ ),
309
+ )
310
+ except Exception as e:
311
+ logger.error(e)
312
+ return False
313
+
314
+ if response.status_code in [200, 201, 204]:
315
+ return super().upload(
316
+ object_name=object_name,
317
+ filename=filename,
318
+ log=log,
319
+ )
320
+
321
+ logger.error(f"failed to upload: {response.status_code} - {response.text}")
322
+ return False
323
+
324
+ object_path = "{}/".format(objects.object_path(object_name=object_name))
325
+ for filename_ in tqdm(
326
+ sorted(
327
+ glob.glob(
328
+ objects.path_of(
329
+ object_name=object_name,
330
+ filename="**",
331
+ ),
332
+ recursive=True,
333
+ )
334
+ )
335
+ ):
336
+ if not file.exists(filename_):
337
+ continue
338
+
339
+ if not self.upload(
340
+ object_name=object_name,
341
+ filename=filename_.split(object_path, 1)[1],
342
+ log=log,
343
+ ):
344
+ return False
345
+
346
+ return True
@@ -13,7 +13,7 @@ from bluer_objects.logger import logger
13
13
 
14
14
  # tars the objects to avoid 'content-length' - see WebDAVInterface.
15
15
  class WebDAVzipInterface(StorageInterface):
16
- name = "webdavzip"
16
+ name = "webdav-zip"
17
17
 
18
18
  def __init__(self):
19
19
  super().__init__()
@@ -106,24 +106,6 @@ class WebDAVzipInterface(StorageInterface):
106
106
  object_name: str,
107
107
  where: str = "local",
108
108
  ) -> Tuple[bool, List[str]]:
109
- if where == "local":
110
- object_path = objects.object_path(
111
- object_name=object_name,
112
- )
113
-
114
- return True, [
115
- os.path.relpath(filename, start=object_path)
116
- for filename in glob.glob(
117
- os.path.join(
118
- object_path,
119
- "**",
120
- "*",
121
- ),
122
- recursive=True,
123
- )
124
- if os.path.isfile(filename)
125
- ]
126
-
127
109
  if where == "cloud":
128
110
  try:
129
111
  if self.client.check(remote_path=f"{object_name}.zip"):
@@ -134,8 +116,10 @@ class WebDAVzipInterface(StorageInterface):
134
116
 
135
117
  return True, []
136
118
 
137
- logger.error(f"Unknown 'where': {where}")
138
- return False, []
119
+ return super().ls(
120
+ object_name=object_name,
121
+ where=where,
122
+ )
139
123
 
140
124
  def upload(
141
125
  self,
@@ -2,6 +2,7 @@ from typing import Tuple, List
2
2
 
3
3
  from bluer_objects.storage.base import StorageInterface
4
4
  from bluer_objects.storage.WebDAV import WebDAVInterface
5
+ from bluer_objects.storage.WebDAVrequest import WebDAVRequestInterface
5
6
  from bluer_objects.storage.WebDAVzip import WebDAVzipInterface
6
7
  from bluer_objects import env
7
8
  from bluer_objects.logger import logger
@@ -10,6 +11,8 @@ interface = StorageInterface()
10
11
 
11
12
  if env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVInterface.name:
12
13
  interface = WebDAVInterface()
14
+ elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVRequestInterface.name:
15
+ interface = WebDAVRequestInterface()
13
16
  elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVzipInterface.name:
14
17
  interface = WebDAVzipInterface()
15
18
  else:
@@ -1,5 +1,8 @@
1
+ import os
2
+ import glob
1
3
  from typing import Tuple, List
2
4
 
5
+ from bluer_objects import objects
3
6
  from bluer_objects.logger import logger
4
7
 
5
8
 
@@ -8,7 +11,7 @@ class StorageInterface:
8
11
  self,
9
12
  do_dryrun: bool = True,
10
13
  ) -> bool:
11
- return False
14
+ return True
12
15
 
13
16
  def download(
14
17
  self,
@@ -32,7 +35,32 @@ class StorageInterface:
32
35
  object_name: str,
33
36
  where: str = "local",
34
37
  ) -> Tuple[bool, List[str]]:
35
- return True, []
38
+ if where == "local":
39
+ object_path = objects.object_path(
40
+ object_name=object_name,
41
+ )
42
+
43
+ return True, sorted(
44
+ [
45
+ os.path.relpath(filename, start=object_path)
46
+ for filename in glob.glob(
47
+ os.path.join(
48
+ object_path,
49
+ "**",
50
+ "*",
51
+ ),
52
+ recursive=True,
53
+ )
54
+ if os.path.isfile(filename)
55
+ ]
56
+ )
57
+
58
+ if where == "cloud":
59
+ logger.error("not implemented")
60
+ return False, []
61
+
62
+ logger.error(f"Unknown 'where': {where}")
63
+ return False, []
36
64
 
37
65
  def upload(
38
66
  self,
@@ -2,6 +2,7 @@ from bluer_ai.tests.test_env import test_bluer_ai_env
2
2
 
3
3
  from bluer_objects import env
4
4
  from bluer_objects.storage.WebDAV import WebDAVInterface
5
+ from bluer_objects.storage.WebDAVrequest import WebDAVRequestInterface
5
6
  from bluer_objects.storage.WebDAVzip import WebDAVzipInterface
6
7
 
7
8
 
@@ -14,6 +15,7 @@ def test_bluer_objects_env():
14
15
 
15
16
  assert env.BLUER_OBJECTS_STORAGE_INTERFACE in [
16
17
  WebDAVInterface.name,
18
+ WebDAVRequestInterface.name,
17
19
  WebDAVzipInterface.name,
18
20
  ]
19
21
 
@@ -0,0 +1,25 @@
1
+ import pytest
2
+
3
+ from bluer_objects import objects, file
4
+
5
+
6
+ @pytest.mark.parametrize(
7
+ ["url"],
8
+ [
9
+ ["https://raw.githubusercontent.com/jbrownlee/Datasets/master/shampoo.csv"],
10
+ ],
11
+ )
12
+ def test_file_download(url: str):
13
+ object_name = objects.unique_object("test_file_download")
14
+
15
+ filename = objects.path_of(
16
+ object_name=object_name,
17
+ filename=url.split("/")[-1],
18
+ )
19
+
20
+ assert file.download(
21
+ url=url,
22
+ filename=filename,
23
+ )
24
+
25
+ assert file.exists(filename)
@@ -94,7 +94,7 @@ def test_file_load_save_matrix(
94
94
  size: Tuple[int, ...],
95
95
  dtype: Union[np.dtype, type],
96
96
  ) -> None:
97
- object_name = objects.unique_object(test_file_load_save_matrix)
97
+ object_name = objects.unique_object("test_file_load_save_matrix")
98
98
 
99
99
  test_matrix = (
100
100
  np.random.randint(0, 256, size=size, dtype=dtype)
@@ -18,7 +18,7 @@ def test_log_matrix(
18
18
  test_image,
19
19
  verbose: bool,
20
20
  ):
21
- object_name = objects.unique_object()
21
+ object_name = objects.unique_object("test_log_matrix")
22
22
 
23
23
  assert log_matrix(
24
24
  matrix=test_image,
@@ -58,7 +58,7 @@ def test_log_matrix_hist(
58
58
  test_image,
59
59
  verbose: bool,
60
60
  ):
61
- object_name = objects.unique_object()
61
+ object_name = objects.unique_object("test_log_matrix_hist")
62
62
 
63
63
  assert log_matrix_hist(
64
64
  matrix=test_image,
@@ -77,7 +77,8 @@ def test_metadata(
77
77
  get_source: Callable[[str], str],
78
78
  get_source_type: MetadataSourceType,
79
79
  ):
80
- object_name = unique_object()
80
+ object_name = unique_object("test_metadata")
81
+
81
82
  key = random()
82
83
  value = random()
83
84
 
@@ -98,7 +99,8 @@ def test_metadata(
98
99
 
99
100
 
100
101
  def test_metadata_dict():
101
- object_name = unique_object()
102
+ object_name = unique_object("test_metadata_dict")
103
+
102
104
  key = random()
103
105
  value = {random(): random() for _ in range(10)}
104
106
 
@@ -138,7 +140,8 @@ def test_metadata_dict():
138
140
 
139
141
 
140
142
  def test_metadata_file():
141
- object_name = unique_object()
143
+ object_name = unique_object("test_metadata_file")
144
+
142
145
  key = random()
143
146
  value = random()
144
147
 
@@ -153,7 +156,8 @@ def test_metadata_file():
153
156
 
154
157
 
155
158
  def test_metadata_object():
156
- object_name = unique_object()
159
+ object_name = unique_object("test_metadata_object")
160
+
157
161
  key = random()
158
162
  value = random()
159
163
 
@@ -163,7 +167,8 @@ def test_metadata_object():
163
167
 
164
168
 
165
169
  def test_metadata_path():
166
- object_name = unique_object()
170
+ object_name = unique_object("test_metadata_path")
171
+
167
172
  key = random()
168
173
  value = random()
169
174
 
@@ -175,7 +180,8 @@ def test_metadata_path():
175
180
 
176
181
 
177
182
  def test_metadata_upload():
178
- object_name = unique_object()
183
+ object_name = unique_object("test_metadata_upload")
184
+
179
185
  key = random()
180
186
  value = random()
181
187
 
@@ -11,7 +11,7 @@ from bluer_objects.mlflow import testing
11
11
 
12
12
 
13
13
  def test_from_and_to_experiment_name():
14
- object_name = unique_object()
14
+ object_name = unique_object("test_from_and_to_experiment_name")
15
15
 
16
16
  assert (
17
17
  objects.to_object_name(objects.to_experiment_name(object_name)) == object_name
@@ -27,7 +27,7 @@ def test_mlflow_testing():
27
27
  [["x=1,y=2,z=3"]],
28
28
  )
29
29
  def test_mlflow_tag_set_get(tags_str: str):
30
- object_name = unique_object("test_mlflow_tag_set")
30
+ object_name = unique_object("test_mlflow_tag_set_get")
31
31
 
32
32
  assert tags.set_tags(
33
33
  object_name,
@@ -41,6 +41,7 @@ def test_objects_list_of_files(
41
41
 
42
42
  def test_object_object_path():
43
43
  object_name = objects.unique_object("test_object_object_path")
44
+
44
45
  object_path = objects.object_path(object_name, create=True)
45
46
  assert object_path
46
47
  assert path.exists(object_path)
@@ -61,5 +62,6 @@ def test_objects_path_of(test_object):
61
62
  )
62
63
  def test_objects_unique_object(prefix: str):
63
64
  object_name = objects.unique_object(prefix)
65
+
64
66
  assert object_name
65
67
  assert object_name.startswith(prefix)
@@ -1,34 +1,20 @@
1
- from bluer_options import string
2
-
3
- from bluer_objects import file, objects
1
+ from bluer_objects import objects
4
2
  from bluer_objects import storage
3
+ from bluer_objects.testing import create_test_asset
5
4
 
6
5
 
7
6
  def test_storage():
8
7
  object_name = objects.unique_object("test_storage")
9
8
 
10
- depth = 10
11
-
12
- for filename in [
13
- "this.yaml",
14
- "that.yaml",
15
- "subfolder/this.yaml",
16
- "subfolder/that.yaml",
17
- ]:
18
- assert file.save_yaml(
19
- objects.path_of(
20
- object_name=object_name,
21
- filename=filename,
22
- ),
23
- {
24
- string.random(length=depth): string.random(length=depth)
25
- for _ in range(depth)
26
- },
27
- )
9
+ assert create_test_asset(
10
+ object_name=object_name,
11
+ depth=10,
12
+ )
28
13
 
29
14
  for filename in [
30
15
  "this.yaml",
31
16
  "subfolder/this.yaml",
17
+ "test-00.png",
32
18
  ]:
33
19
  assert storage.upload(
34
20
  object_name=object_name,
@@ -40,6 +26,7 @@ def test_storage():
40
26
  for filename in [
41
27
  "this.yaml",
42
28
  "subfolder/this.yaml",
29
+ "test-00.png",
43
30
  ]:
44
31
  assert storage.download(
45
32
  object_name=object_name,
@@ -0,0 +1,39 @@
1
+ from bluer_objects import objects
2
+ from bluer_objects.testing import create_test_asset
3
+ from bluer_objects.storage import StorageInterface
4
+
5
+
6
+ def test_storage_base():
7
+ object_name = objects.unique_object("test_storage_base")
8
+
9
+ assert create_test_asset(
10
+ object_name=object_name,
11
+ depth=10,
12
+ )
13
+
14
+ storage = StorageInterface()
15
+
16
+ success, list_of_files_local = storage.ls(
17
+ object_name=object_name,
18
+ where="local",
19
+ )
20
+ assert success
21
+ assert list_of_files_local
22
+
23
+ success, list_of_files_cloud = storage.ls(
24
+ object_name=object_name,
25
+ where="cloud",
26
+ )
27
+ assert not success
28
+ assert not list_of_files_cloud
29
+
30
+ assert storage.upload(object_name=object_name)
31
+
32
+ success, list_of_files_cloud = storage.ls(
33
+ object_name=object_name,
34
+ where="cloud",
35
+ )
36
+ assert not success
37
+ assert not list_of_files_cloud
38
+
39
+ assert storage.download(object_name=object_name)
@@ -0,0 +1,72 @@
1
+ from bluer_objects import objects
2
+ from bluer_objects.testing import create_test_asset
3
+ from bluer_objects.storage import WebDAVRequestInterface
4
+
5
+
6
+ def test_storage_webdav_request():
7
+ object_name = objects.unique_object("test_storage_webdav_request")
8
+
9
+ assert create_test_asset(
10
+ object_name=object_name,
11
+ depth=10,
12
+ )
13
+
14
+ storage = WebDAVRequestInterface()
15
+
16
+ success, list_of_files_local = storage.ls(
17
+ object_name=object_name,
18
+ where="local",
19
+ )
20
+ assert success
21
+ assert list_of_files_local
22
+
23
+ success, list_of_files_cloud = storage.ls(
24
+ object_name=object_name,
25
+ where="cloud",
26
+ )
27
+ assert success
28
+ assert not list_of_files_cloud
29
+
30
+ for filename in [
31
+ "this.yaml",
32
+ "subfolder/this.yaml",
33
+ "test-00.png",
34
+ ]:
35
+ assert storage.upload(
36
+ object_name=object_name,
37
+ filename=filename,
38
+ )
39
+
40
+ success, list_of_files_cloud = storage.ls(
41
+ object_name=object_name,
42
+ where="cloud",
43
+ )
44
+ assert success
45
+ assert list_of_files_cloud
46
+
47
+ assert storage.upload(object_name=object_name)
48
+
49
+ success, list_of_files_cloud = storage.ls(
50
+ object_name=object_name,
51
+ where="cloud",
52
+ )
53
+ assert success
54
+ assert list_of_files_cloud
55
+ assert list_of_files_cloud == list_of_files_local
56
+
57
+ for filename in [
58
+ "this.yaml",
59
+ "subfolder/this.yaml",
60
+ "test-00.png",
61
+ ]:
62
+ assert storage.download(
63
+ object_name=object_name,
64
+ filename=filename,
65
+ )
66
+
67
+ assert storage.download(object_name=object_name)
68
+
69
+ assert storage.delete(
70
+ object_name=object_name,
71
+ do_dryrun=False,
72
+ )
@@ -0,0 +1,39 @@
1
+ from bluer_objects import objects
2
+ from bluer_objects.testing import create_test_asset
3
+ from bluer_objects.storage import WebDAVzipInterface
4
+
5
+
6
+ def test_storage_webdav_zip():
7
+ object_name = objects.unique_object("test_storage_webdav_zip")
8
+
9
+ assert create_test_asset(
10
+ object_name=object_name,
11
+ depth=10,
12
+ )
13
+
14
+ storage = WebDAVzipInterface()
15
+
16
+ success, list_of_files_local = storage.ls(
17
+ object_name=object_name,
18
+ where="local",
19
+ )
20
+ assert success
21
+ assert list_of_files_local
22
+
23
+ success, list_of_files_cloud = storage.ls(
24
+ object_name=object_name,
25
+ where="cloud",
26
+ )
27
+ assert success
28
+ assert not list_of_files_cloud
29
+
30
+ assert storage.upload(object_name=object_name)
31
+
32
+ success, list_of_files_cloud = storage.ls(
33
+ object_name=object_name,
34
+ where="cloud",
35
+ )
36
+ assert success
37
+ assert list_of_files_cloud
38
+
39
+ assert storage.download(object_name=object_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bluer_objects
3
- Version: 6.107.1
3
+ Version: 6.133.1
4
4
  Summary: 🌀 Object management in Bash.
5
5
  Home-page: https://github.com/kamangir/bluer-objects
6
6
  Author: Arash Abadpour (Kamangir)
@@ -63,6 +63,6 @@ pip install bluer-objects
63
63
 
64
64
  [![pylint](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml) [![pytest](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml) [![bashtest](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml) [![PyPI version](https://img.shields.io/pypi/v/bluer-objects.svg)](https://pypi.org/project/bluer-objects/) [![PyPI - Downloads](https://img.shields.io/pypi/dd/bluer-objects)](https://pypistats.org/packages/bluer-objects)
65
65
 
66
- built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.107.1`](https://github.com/kamangir/bluer-objects).
66
+ built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.133.1`](https://github.com/kamangir/bluer-objects).
67
67
 
68
68
  built by 🌀 [`blueness-3.118.1`](https://github.com/kamangir/blueness).
@@ -1,6 +1,6 @@
1
- bluer_objects/__init__.py,sha256=rJ5ww8HpbXyQL_nx9tdXZDwCTjouiSu4k9Sko60RGVM,315
1
+ bluer_objects/__init__.py,sha256=774USgP5qvl-GrE6IkJmQkJsNTe9H7euzkIuZxe20ig,315
2
2
  bluer_objects/__main__.py,sha256=Yqfov833_hJuRne19WrGhT5DWAPtdffpoMxeSXS7EGw,359
3
- bluer_objects/config.env,sha256=cMVT0kVQ00xGUoQyUqC8jpqkhR13Kpkl1-0sKQlxQAI,85
3
+ bluer_objects/config.env,sha256=OskMqZi0CuvYM4TDq_wzrG7UonxvV0pV6zwObwHaLTI,90
4
4
  bluer_objects/env.py,sha256=J5LklWyWT-Yvvoe8MVCZQ3iqRqyDutq6IbNYNj9A1VM,1183
5
5
  bluer_objects/markdown.py,sha256=PhAwCTHIisO9qOpKHeb63U5oD9Zi8LnIQKTx_OWS4wE,938
6
6
  bluer_objects/objects.py,sha256=EYzA1vKngY2c_gdMKnUfrKVUcf-5wpFKgBFaVJA4cLE,1626
@@ -57,7 +57,7 @@ bluer_objects/.abcli/tests/mlflow_cache.sh,sha256=EEAPGasQgN4j6YLp30_IMYAPCTUBxm
57
57
  bluer_objects/.abcli/tests/mlflow_logging.sh,sha256=TVzHhk9qRthpP2xdKwu3LwK00S77GqH50io3oVyS2UE,305
58
58
  bluer_objects/.abcli/tests/mlflow_tags.sh,sha256=pX4sEK_z2Vrb7a6Bq4qWurFVPZkvjpS10K4MLx3mf64,811
59
59
  bluer_objects/.abcli/tests/mlflow_test.sh,sha256=7MXxYq2GgD2MEJbQlpx80qLT2HaaVn_PFFMpSA_hWA4,125
60
- bluer_objects/.abcli/tests/storage.sh,sha256=HOpVnA-pQEWC4mSdTpE31BM7FxJlE9kZdvEL57VfA7c,1199
60
+ bluer_objects/.abcli/tests/storage.sh,sha256=DTrlldjNerH2E79G8X4IXY2hMBK6vmBX7jRCqYzmR4I,1357
61
61
  bluer_objects/.abcli/tests/version.sh,sha256=k-lXozSjyFgFR58cTzUYla0Ef-upx3sSK641zI5ynfE,169
62
62
  bluer_objects/README/__init__.py,sha256=5ghygLdrsjqP2Tui5O3Ax9DR8nEHHh1HydKV05dhRhc,1259
63
63
  bluer_objects/README/functions.py,sha256=IriuSysrApSTEgOZHqq32-eyks5v5Tn-KvmwYQUIloc,10752
@@ -65,7 +65,7 @@ bluer_objects/README/items.py,sha256=-XaNCr5b_NGRkZVfIQ6hBFgJw5GIVcMJdktT3hWoam4
65
65
  bluer_objects/file/__init__.py,sha256=c_79ipBkKl6OFDimOev0vnaVdpUk-Bl3oJUapOreMXc,681
66
66
  bluer_objects/file/__main__.py,sha256=v2IXWvZeh_B2sGYWzv1CiUY-7HWHXXghZM5M4IPjbu4,1277
67
67
  bluer_objects/file/classes.py,sha256=TRgeRP2yxInPkBnywhuB4BsoBcBRA3UmQzX1dI43UxU,872
68
- bluer_objects/file/functions.py,sha256=CiHZLK9Mz8M3-U_dpQSlfEIAl52zPBWyQDepLoll6Ow,6389
68
+ bluer_objects/file/functions.py,sha256=H4cgKtCTpbY3dR7kAOvbAbq8xSEHR9s6MQ_3W-Pb6Ng,6441
69
69
  bluer_objects/file/load.py,sha256=1zt5xC95HFr89G9lsi3gCJMSvC4Bt0vVeeUEf3NjpOQ,4281
70
70
  bluer_objects/file/save.py,sha256=dl-3qfrh3ZmD42_JFmaBXWcoXdZ-cipt_LTGrHyaV7I,4997
71
71
  bluer_objects/graphics/__init__.py,sha256=Dd0kQqN7Ldvp1N9oyIirPZ6W3IdUtfPj2u21Bf4W_MI,213
@@ -107,18 +107,20 @@ bluer_objects/mlflow/objects.py,sha256=aXYHLRCTt1FtDQoyPOG-doCFms7qF6Krz00Fg3kzJ
107
107
  bluer_objects/mlflow/runs.py,sha256=v1IKRvxbuKkengESnG-xdUXxxNSkALMeBmfMQwrUKSs,2416
108
108
  bluer_objects/mlflow/tags.py,sha256=8uBYRrE4weTLrwPqo-c4M21FEVRANf7SGCcxpoCPhuM,2475
109
109
  bluer_objects/mlflow/testing.py,sha256=cJH5Ki02fJN_Xos1j9yvwQChXvMkOa9i12vtDKmkbNc,842
110
- bluer_objects/storage/WebDAV.py,sha256=bTq06MjTO9RffP3Uc4oEKwFaGx18DFb29VxD3jrPTz4,3078
111
- bluer_objects/storage/WebDAVzip.py,sha256=7N1m4VZy1UIQZj7z5nkiuP_LxkW9GeKA_n6oLb_ikDw,4376
112
- bluer_objects/storage/__init__.py,sha256=8KFhOPVw-5m1CiFUh8Ppz4zRA5kBo4nOBVbpznk6998,1320
110
+ bluer_objects/storage/WebDAV.py,sha256=IvYZDST6Cg1rgRhQ5eh3Hrq8V7S3oon9O29MH55QLxA,2922
111
+ bluer_objects/storage/WebDAVrequest.py,sha256=ihWOxP7h28qj0-5AZ0SsERSBrViq9p4iNVeR4pGBWQo,9836
112
+ bluer_objects/storage/WebDAVzip.py,sha256=Sd_rU57pJaRa05sKNQiMr85Bg3w7O5k8N1pSN1u8omA,3872
113
+ bluer_objects/storage/__init__.py,sha256=RCE6j7b0jP-zhy4DoSjw9Ox8-Iy_z9H92yvSnSs3HpA,1505
113
114
  bluer_objects/storage/__main__.py,sha256=vZI6rUkrekf1eYUgWOOUnFhl4qPfpByzwb-tihTOiIo,1776
114
- bluer_objects/storage/base.py,sha256=bxccHx78H_2Ux7dlwl1qrPMeEs72SHFAO_quhmJ31Sw,1129
115
+ bluer_objects/storage/base.py,sha256=72I1zvlpbQbFU20TxqcTodR4m8PYgBPXMfteek8V0_A,1949
115
116
  bluer_objects/testing/__init__.py,sha256=DWY5ZtvCnHG_t9BDiqy_ArLOZi-nlyAtPVMLA1PPAMU,62
116
117
  bluer_objects/testing/__main__.py,sha256=EfuNfx1TXLriW6HHf86L7qp1FXoEV5F4sxej1r_i95k,656
117
118
  bluer_objects/testing/functions.py,sha256=AXAfzWLcEPkbSYTehdahshjKJ45C4IJkRs_TgrHOntc,1355
118
119
  bluer_objects/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
120
  bluer_objects/tests/test_README.py,sha256=5D4UV8VcjbeAPThsYVynYtVFuP8gwMAhIjEWuOQZsWs,89
120
- bluer_objects/tests/test_env.py,sha256=Gjjb9FoQ6MPvFwX8pdx74aND8Ye_Bb-8XpaaKOZtw-4,547
121
- bluer_objects/tests/test_file_load_save.py,sha256=mNCo3ay55ktc5L6SPpNyrpsJrGfVpYi66EgunlAN-Uw,2406
121
+ bluer_objects/tests/test_env.py,sha256=MFm1IYkpAZzaCQCKvP3ADkORww0nmAIV6ZZdR48qMRU,655
122
+ bluer_objects/tests/test_file_download.py,sha256=1_adHYqgSifkdP-I7TQVW0t8MLCujQ61fvRbcrSkcmg,512
123
+ bluer_objects/tests/test_file_load_save.py,sha256=5uUBjyiBglzNn9sAWmjQ8zLnElJ6osJQe2lnQgKk9FQ,2408
122
124
  bluer_objects/tests/test_file_load_save_text.py,sha256=3XnBGlv3KZvheHY-RlX1Su6LOBkkn57pkf9_dXR81r8,1017
123
125
  bluer_objects/tests/test_fullname.py,sha256=xWFf9qqzDQ-4RxRyvyR9GWZyU5qNrKxru94UUKMJfPk,80
124
126
  bluer_objects/tests/test_graphics.py,sha256=mEuk0rWLwr7b2nv4FH6f-RphwfqP23xe2pkjhWe0HgU,238
@@ -128,17 +130,20 @@ bluer_objects/tests/test_graphics_screen.py,sha256=26GMDxImz57oWb8mFrNBtiGnctfjO
128
130
  bluer_objects/tests/test_graphics_signature.py,sha256=CVV257E3A5KBwqEDpRXShN-ful1zFwV9S-z-06oFkxM,1588
129
131
  bluer_objects/tests/test_graphics_text.py,sha256=_jLZVuAcQQYlKpATeQCBpPMa8UhKQ__bFYR1bedO5EE,314
130
132
  bluer_objects/tests/test_logger.py,sha256=DdkZqj8YOErKf6T-SWEPtU21LGfQf_O3GKrCn3H0Ujs,88
131
- bluer_objects/tests/test_logger_matrix.py,sha256=krJPUdlQTLD8P8EjkrlmJVw6Iylwbl8cBfj8yv8egWg,1664
133
+ bluer_objects/tests/test_logger_matrix.py,sha256=qedidEDGusMWQM04kgk3mt74yFm4iU3jIyjE4gRi_FQ,1703
132
134
  bluer_objects/tests/test_markdown.py,sha256=KtCWKIDs4U1M3qAGFMYhzVpdGiDV2VU8z7dCaU3s3Ec,217
133
- bluer_objects/tests/test_metadata.py,sha256=jT39xsP4u3dq6ZWmmVwHlk0D_33Uv_-McNBdy_ba2DM,4264
134
- bluer_objects/tests/test_mlflow.py,sha256=B7CvITThv6YmDB1la9_H2sF2VLt8urpNDQ0YnC1n8HU,1381
135
- bluer_objects/tests/test_objects.py,sha256=4yv8QL2s6pw2nIOMPEaCn1p_HxUfRb84j_L0Kl0gHIs,1439
135
+ bluer_objects/tests/test_metadata.py,sha256=Qy-Zp5yFrHmZ5tjujuLNcvI2YEyzNuAFXgy0L7sJOJ0,4389
136
+ bluer_objects/tests/test_mlflow.py,sha256=Ee6T7r2qT1fvUv2ommC3Wl5Gwz1olURvMvhoaM0779M,1419
137
+ bluer_objects/tests/test_objects.py,sha256=pqdXvnAJ5WPlHvqqaKrd9-vqktrE9GOVxSgqHs8yK8w,1441
136
138
  bluer_objects/tests/test_path.py,sha256=JjONWyhZyMM_u1SzD1RI_iZ5vYJDUe-B51fbbHczIig,85
137
- bluer_objects/tests/test_storage.py,sha256=2tJ6Hev9ShId9Qn-0FXDw41HWjcl3wymcB_Bv1FJWi4,1127
139
+ bluer_objects/tests/test_storage.py,sha256=3kFq4lVuvHIpHYob6YprqNdiPaZKgSdMJSsCZ-nvXdI,822
140
+ bluer_objects/tests/test_storage_base.py,sha256=ieuuuldGWdximvckpiP-y5bUe3tQd-1hatCyxYPTtfg,949
141
+ bluer_objects/tests/test_storage_webdav_request.py,sha256=hJVwUBcu4fo1rsRRjk0U4cxJQ-bgNPMJJCIqz_ExaLE,1705
142
+ bluer_objects/tests/test_storage_webdav_zip.py,sha256=aFwqREkbEIvJRvkC0Wyfirl_f4tRhtSD3lpNSmQ_BeI,953
138
143
  bluer_objects/tests/test_testing.py,sha256=d2NH435yqJBl9wmfMqGGd-f0Y0jsL2QhHUXkty9AwPA,235
139
144
  bluer_objects/tests/test_version.py,sha256=Lyf3PMcA22e17BNRk_2VgPrtao6dWEgVoXo68Uds8SE,75
140
- bluer_objects-6.107.1.dist-info/licenses/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
141
- bluer_objects-6.107.1.dist-info/METADATA,sha256=VHCtDaSYE3R4wQONP0xEzOa98ZSX1oV0ycaZU7S8zKc,3554
142
- bluer_objects-6.107.1.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
143
- bluer_objects-6.107.1.dist-info/top_level.txt,sha256=RX2TpddbnRkurda3G_pAdyeTztP2IhhRPx949GlEvQo,14
144
- bluer_objects-6.107.1.dist-info/RECORD,,
145
+ bluer_objects-6.133.1.dist-info/licenses/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
146
+ bluer_objects-6.133.1.dist-info/METADATA,sha256=589H6252yUINWWFRERwjv_N_cDUvOxFU-WDC1qUMDpA,3554
147
+ bluer_objects-6.133.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
148
+ bluer_objects-6.133.1.dist-info/top_level.txt,sha256=RX2TpddbnRkurda3G_pAdyeTztP2IhhRPx949GlEvQo,14
149
+ bluer_objects-6.133.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.1)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5