bluer-objects 6.104.1__py3-none-any.whl → 6.129.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.
- bluer_objects/.abcli/tests/storage.sh +9 -3
- bluer_objects/__init__.py +1 -1
- bluer_objects/config.env +1 -1
- bluer_objects/file/load.py +2 -9
- bluer_objects/file/save.py +1 -19
- bluer_objects/storage/WebDAV.py +0 -7
- bluer_objects/storage/WebDAVrequest.py +346 -0
- bluer_objects/storage/WebDAVzip.py +5 -21
- bluer_objects/storage/__init__.py +3 -0
- bluer_objects/storage/base.py +30 -2
- bluer_objects/tests/test_env.py +2 -0
- bluer_objects/tests/test_file_load_save_text.py +46 -0
- bluer_objects/tests/test_storage.py +8 -21
- bluer_objects/tests/test_storage_base.py +39 -0
- bluer_objects/tests/test_storage_webdav_request.py +72 -0
- bluer_objects/tests/test_storage_webdav_zip.py +39 -0
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.129.1.dist-info}/METADATA +2 -2
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.129.1.dist-info}/RECORD +21 -16
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.129.1.dist-info}/WHEEL +1 -1
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.129.1.dist-info}/licenses/LICENSE +0 -0
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.129.1.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
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
|
-
#
|
|
41
|
-
|
|
47
|
+
# download
|
|
42
48
|
bluer_objects_download \
|
|
43
49
|
filename=this.yaml \
|
|
44
50
|
$object_name
|
bluer_objects/__init__.py
CHANGED
bluer_objects/config.env
CHANGED
bluer_objects/file/load.py
CHANGED
|
@@ -149,21 +149,14 @@ def load_matrix(
|
|
|
149
149
|
def load_text(
|
|
150
150
|
filename,
|
|
151
151
|
ignore_error=False,
|
|
152
|
-
count=-1,
|
|
153
152
|
log=False,
|
|
154
153
|
) -> Tuple[bool, List[str]]:
|
|
155
154
|
success = True
|
|
156
155
|
text = []
|
|
157
156
|
|
|
158
157
|
try:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
text = fp.read()
|
|
162
|
-
text = text.split("\n")
|
|
163
|
-
else:
|
|
164
|
-
# https://stackoverflow.com/a/1767589/10917551
|
|
165
|
-
with open(filename) as fp:
|
|
166
|
-
text = [next(fp) for _ in range(count)]
|
|
158
|
+
with open(filename, "r") as fp:
|
|
159
|
+
text = fp.read().splitlines()
|
|
167
160
|
except:
|
|
168
161
|
success = False
|
|
169
162
|
if not ignore_error:
|
bluer_objects/file/save.py
CHANGED
|
@@ -13,7 +13,6 @@ from bluer_options.host import is_jupyter
|
|
|
13
13
|
from bluer_objects import NAME
|
|
14
14
|
from bluer_objects.file.classes import JsonEncoder
|
|
15
15
|
from bluer_objects.file.functions import path as file_path
|
|
16
|
-
from bluer_objects.file.load import load_text
|
|
17
16
|
from bluer_objects.path import create as path_create
|
|
18
17
|
from bluer_objects.logger import logger
|
|
19
18
|
|
|
@@ -214,32 +213,15 @@ def save_matrix(
|
|
|
214
213
|
def save_text(
|
|
215
214
|
filename: str,
|
|
216
215
|
text: List[str],
|
|
217
|
-
if_different: bool = False,
|
|
218
216
|
log: bool = False,
|
|
219
|
-
remove_empty_lines: bool = False,
|
|
220
217
|
) -> bool:
|
|
221
|
-
if remove_empty_lines:
|
|
222
|
-
text = [
|
|
223
|
-
line
|
|
224
|
-
for line, next_line in zip(text, text[1:] + ["x"])
|
|
225
|
-
if line.strip() or next_line.strip()
|
|
226
|
-
]
|
|
227
|
-
|
|
228
|
-
if if_different:
|
|
229
|
-
_, content = load_text(filename, ignore_error=True)
|
|
230
|
-
|
|
231
|
-
if "|".join([line for line in content if line]) == "|".join(
|
|
232
|
-
[line for line in text if line]
|
|
233
|
-
):
|
|
234
|
-
return True
|
|
235
|
-
|
|
236
218
|
if not prepare_for_saving(filename):
|
|
237
219
|
return False
|
|
238
220
|
|
|
239
221
|
success = True
|
|
240
222
|
try:
|
|
241
223
|
with open(filename, "w") as fp:
|
|
242
|
-
fp.writelines(
|
|
224
|
+
fp.writelines(string + "\n" for string in text)
|
|
243
225
|
except:
|
|
244
226
|
success = False
|
|
245
227
|
|
bluer_objects/storage/WebDAV.py
CHANGED
|
@@ -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 = "
|
|
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
|
-
|
|
138
|
-
|
|
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:
|
bluer_objects/storage/base.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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,
|
bluer_objects/tests/test_env.py
CHANGED
|
@@ -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,46 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from bluer_options import string
|
|
4
|
+
|
|
5
|
+
from bluer_objects import file, objects
|
|
6
|
+
from bluer_objects.file.load import load_text
|
|
7
|
+
from bluer_objects.file.save import save_text
|
|
8
|
+
from bluer_objects.tests.test_objects import test_object
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.mark.parametrize(
|
|
12
|
+
[
|
|
13
|
+
"filename",
|
|
14
|
+
],
|
|
15
|
+
[
|
|
16
|
+
["test.json"],
|
|
17
|
+
["test.yaml"],
|
|
18
|
+
["test.yaml"],
|
|
19
|
+
],
|
|
20
|
+
)
|
|
21
|
+
def test_file_load_save_text(
|
|
22
|
+
test_object,
|
|
23
|
+
filename: str,
|
|
24
|
+
):
|
|
25
|
+
filename_input = objects.path_of(
|
|
26
|
+
object_name=test_object,
|
|
27
|
+
filename=filename,
|
|
28
|
+
)
|
|
29
|
+
success, text_input = load_text(filename_input)
|
|
30
|
+
assert success
|
|
31
|
+
|
|
32
|
+
filename_test = file.add_suffix(
|
|
33
|
+
filename_input,
|
|
34
|
+
string.random(),
|
|
35
|
+
)
|
|
36
|
+
assert save_text(
|
|
37
|
+
filename_test,
|
|
38
|
+
text_input,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
success, text_output = load_text(filename_test)
|
|
42
|
+
assert success
|
|
43
|
+
|
|
44
|
+
assert len(text_input) == len(text_output)
|
|
45
|
+
for line_input, line_output in zip(text_input, text_output):
|
|
46
|
+
assert line_input == line_output
|
|
@@ -1,34 +1,20 @@
|
|
|
1
|
-
from
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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.
|
|
3
|
+
Version: 6.129.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
|
[](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml) [](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml) [](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml) [](https://pypi.org/project/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.
|
|
66
|
+
built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.129.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=
|
|
1
|
+
bluer_objects/__init__.py,sha256=QwE0nTd3RYTVIXgiJdMtSIfXOgFnYDJCLGn_FiOZQww,315
|
|
2
2
|
bluer_objects/__main__.py,sha256=Yqfov833_hJuRne19WrGhT5DWAPtdffpoMxeSXS7EGw,359
|
|
3
|
-
bluer_objects/config.env,sha256=
|
|
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=
|
|
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
|
|
@@ -66,8 +66,8 @@ bluer_objects/file/__init__.py,sha256=c_79ipBkKl6OFDimOev0vnaVdpUk-Bl3oJUapOreMX
|
|
|
66
66
|
bluer_objects/file/__main__.py,sha256=v2IXWvZeh_B2sGYWzv1CiUY-7HWHXXghZM5M4IPjbu4,1277
|
|
67
67
|
bluer_objects/file/classes.py,sha256=TRgeRP2yxInPkBnywhuB4BsoBcBRA3UmQzX1dI43UxU,872
|
|
68
68
|
bluer_objects/file/functions.py,sha256=CiHZLK9Mz8M3-U_dpQSlfEIAl52zPBWyQDepLoll6Ow,6389
|
|
69
|
-
bluer_objects/file/load.py,sha256=
|
|
70
|
-
bluer_objects/file/save.py,sha256=
|
|
69
|
+
bluer_objects/file/load.py,sha256=1zt5xC95HFr89G9lsi3gCJMSvC4Bt0vVeeUEf3NjpOQ,4281
|
|
70
|
+
bluer_objects/file/save.py,sha256=dl-3qfrh3ZmD42_JFmaBXWcoXdZ-cipt_LTGrHyaV7I,4997
|
|
71
71
|
bluer_objects/graphics/__init__.py,sha256=Dd0kQqN7Ldvp1N9oyIirPZ6W3IdUtfPj2u21Bf4W_MI,213
|
|
72
72
|
bluer_objects/graphics/__main__.py,sha256=A221gpkUDYd_S2eYz8i6KwaPumg8myaR7L5j464wC54,1909
|
|
73
73
|
bluer_objects/graphics/frame.py,sha256=WcSn-0oqDw48Akmn_bwcjDC9U_kKqRYRoGWYPoKyFvY,321
|
|
@@ -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=
|
|
111
|
-
bluer_objects/storage/
|
|
112
|
-
bluer_objects/storage/
|
|
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=
|
|
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=
|
|
121
|
+
bluer_objects/tests/test_env.py,sha256=MFm1IYkpAZzaCQCKvP3ADkORww0nmAIV6ZZdR48qMRU,655
|
|
121
122
|
bluer_objects/tests/test_file_load_save.py,sha256=mNCo3ay55ktc5L6SPpNyrpsJrGfVpYi66EgunlAN-Uw,2406
|
|
123
|
+
bluer_objects/tests/test_file_load_save_text.py,sha256=3XnBGlv3KZvheHY-RlX1Su6LOBkkn57pkf9_dXR81r8,1017
|
|
122
124
|
bluer_objects/tests/test_fullname.py,sha256=xWFf9qqzDQ-4RxRyvyR9GWZyU5qNrKxru94UUKMJfPk,80
|
|
123
125
|
bluer_objects/tests/test_graphics.py,sha256=mEuk0rWLwr7b2nv4FH6f-RphwfqP23xe2pkjhWe0HgU,238
|
|
124
126
|
bluer_objects/tests/test_graphics_frame.py,sha256=wRW3MjnfS8edNHiWi_BFJBULoLs1JlJhpFeuCoW5I6A,267
|
|
@@ -133,11 +135,14 @@ bluer_objects/tests/test_metadata.py,sha256=jT39xsP4u3dq6ZWmmVwHlk0D_33Uv_-McNBd
|
|
|
133
135
|
bluer_objects/tests/test_mlflow.py,sha256=B7CvITThv6YmDB1la9_H2sF2VLt8urpNDQ0YnC1n8HU,1381
|
|
134
136
|
bluer_objects/tests/test_objects.py,sha256=4yv8QL2s6pw2nIOMPEaCn1p_HxUfRb84j_L0Kl0gHIs,1439
|
|
135
137
|
bluer_objects/tests/test_path.py,sha256=JjONWyhZyMM_u1SzD1RI_iZ5vYJDUe-B51fbbHczIig,85
|
|
136
|
-
bluer_objects/tests/test_storage.py,sha256=
|
|
138
|
+
bluer_objects/tests/test_storage.py,sha256=3kFq4lVuvHIpHYob6YprqNdiPaZKgSdMJSsCZ-nvXdI,822
|
|
139
|
+
bluer_objects/tests/test_storage_base.py,sha256=ieuuuldGWdximvckpiP-y5bUe3tQd-1hatCyxYPTtfg,949
|
|
140
|
+
bluer_objects/tests/test_storage_webdav_request.py,sha256=hJVwUBcu4fo1rsRRjk0U4cxJQ-bgNPMJJCIqz_ExaLE,1705
|
|
141
|
+
bluer_objects/tests/test_storage_webdav_zip.py,sha256=aFwqREkbEIvJRvkC0Wyfirl_f4tRhtSD3lpNSmQ_BeI,953
|
|
137
142
|
bluer_objects/tests/test_testing.py,sha256=d2NH435yqJBl9wmfMqGGd-f0Y0jsL2QhHUXkty9AwPA,235
|
|
138
143
|
bluer_objects/tests/test_version.py,sha256=Lyf3PMcA22e17BNRk_2VgPrtao6dWEgVoXo68Uds8SE,75
|
|
139
|
-
bluer_objects-6.
|
|
140
|
-
bluer_objects-6.
|
|
141
|
-
bluer_objects-6.
|
|
142
|
-
bluer_objects-6.
|
|
143
|
-
bluer_objects-6.
|
|
144
|
+
bluer_objects-6.129.1.dist-info/licenses/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
|
|
145
|
+
bluer_objects-6.129.1.dist-info/METADATA,sha256=QN0wQsDNrg-DSQIKJnt4hN4vrLfLJnPZ2Azxg2-xGZ8,3554
|
|
146
|
+
bluer_objects-6.129.1.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
147
|
+
bluer_objects-6.129.1.dist-info/top_level.txt,sha256=RX2TpddbnRkurda3G_pAdyeTztP2IhhRPx949GlEvQo,14
|
|
148
|
+
bluer_objects-6.129.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|