bluer-objects 6.104.1__py3-none-any.whl → 6.464.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.
- bluer_objects/.abcli/abcli.sh +6 -0
- bluer_objects/.abcli/alias.sh +13 -6
- bluer_objects/.abcli/assets/cd.sh +20 -0
- bluer_objects/.abcli/assets/mv.sh +34 -0
- bluer_objects/.abcli/assets/publish.sh +40 -0
- bluer_objects/.abcli/assets.sh +15 -0
- bluer_objects/.abcli/create_test_asset.sh +10 -0
- bluer_objects/.abcli/download.sh +3 -1
- bluer_objects/.abcli/file.sh +15 -4
- bluer_objects/.abcli/gif.sh +18 -0
- bluer_objects/.abcli/host.sh +23 -7
- bluer_objects/.abcli/ls.sh +19 -8
- bluer_objects/.abcli/metadata/download.sh +9 -0
- bluer_objects/.abcli/metadata/edit.sh +15 -0
- bluer_objects/.abcli/metadata/upload.sh +9 -0
- bluer_objects/.abcli/mlflow/browse.sh +2 -0
- bluer_objects/.abcli/mlflow/deploy.sh +21 -5
- bluer_objects/.abcli/mlflow/lock/lock.sh +11 -0
- bluer_objects/.abcli/mlflow/lock/unlock.sh +12 -0
- bluer_objects/.abcli/mlflow/lock.sh +15 -0
- bluer_objects/.abcli/mlflow/tags/search.sh +1 -5
- bluer_objects/.abcli/mlflow.sh +0 -2
- bluer_objects/.abcli/pdf/convert.sh +92 -0
- bluer_objects/.abcli/pdf.sh +15 -0
- bluer_objects/.abcli/storage/clear.sh +2 -0
- bluer_objects/.abcli/tests/clone.sh +2 -3
- bluer_objects/.abcli/tests/create_test_asset.sh +16 -0
- bluer_objects/.abcli/tests/file.sh +64 -0
- bluer_objects/.abcli/tests/gif.sh +3 -3
- bluer_objects/.abcli/tests/help.sh +23 -7
- bluer_objects/.abcli/tests/ls.sh +11 -4
- bluer_objects/.abcli/tests/metadata.sh +35 -0
- bluer_objects/.abcli/tests/mlflow_lock.sh +30 -0
- bluer_objects/.abcli/tests/mlflow_tags.sh +1 -1
- bluer_objects/.abcli/tests/open.sh +11 -0
- bluer_objects/.abcli/tests/open_gif_open.sh +14 -0
- bluer_objects/.abcli/tests/pdf.sh +39 -0
- bluer_objects/.abcli/tests/storage_clear.sh +11 -0
- bluer_objects/.abcli/tests/storage_public_upload.sh +25 -0
- bluer_objects/.abcli/tests/storage_status.sh +12 -0
- bluer_objects/.abcli/tests/{storage.sh → storage_upload_download.sh} +26 -8
- bluer_objects/.abcli/upload.sh +26 -2
- bluer_objects/README/__init__.py +7 -22
- bluer_objects/README/alias.py +67 -0
- bluer_objects/README/build/__init__.py +0 -0
- bluer_objects/README/build/aliases.py +23 -0
- bluer_objects/README/build/docs.py +23 -0
- bluer_objects/README/build/modules.py +9 -0
- bluer_objects/README/consts.py +44 -0
- bluer_objects/README/functions.py +154 -204
- bluer_objects/README/items.py +78 -6
- bluer_objects/README/process/__init__.py +0 -0
- bluer_objects/README/process/assets.py +36 -0
- bluer_objects/README/process/details.py +20 -0
- bluer_objects/README/process/envs.py +23 -0
- bluer_objects/README/process/help.py +27 -0
- bluer_objects/README/process/include.py +40 -0
- bluer_objects/README/process/legacy.py +21 -0
- bluer_objects/README/process/mermaid.py +20 -0
- bluer_objects/README/process/national_internet.py +55 -0
- bluer_objects/README/process/objects.py +32 -0
- bluer_objects/README/process/signature.py +35 -0
- bluer_objects/README/process/title.py +44 -0
- bluer_objects/README/process/variables.py +12 -0
- bluer_objects/__init__.py +1 -1
- bluer_objects/assets/__init__.py +0 -0
- bluer_objects/assets/__main__.py +57 -0
- bluer_objects/assets/functions.py +62 -0
- bluer_objects/config.env +13 -1
- bluer_objects/env.py +27 -1
- bluer_objects/file/__main__.py +52 -7
- bluer_objects/file/functions.py +21 -4
- bluer_objects/file/load.py +2 -9
- bluer_objects/file/save.py +17 -24
- bluer_objects/graphics/__main__.py +7 -0
- bluer_objects/graphics/gif.py +11 -7
- bluer_objects/graphics/screen.py +9 -8
- bluer_objects/help/assets.py +93 -0
- bluer_objects/help/create_test_asset.py +22 -0
- bluer_objects/help/download.py +17 -3
- bluer_objects/help/file.py +59 -0
- bluer_objects/help/functions.py +9 -1
- bluer_objects/help/gif.py +25 -0
- bluer_objects/help/host.py +6 -4
- bluer_objects/help/ls.py +26 -3
- bluer_objects/help/metadata.py +51 -0
- bluer_objects/help/mlflow/__init__.py +23 -2
- bluer_objects/help/mlflow/cache.py +2 -4
- bluer_objects/help/mlflow/lock.py +52 -0
- bluer_objects/help/mlflow/tags.py +34 -23
- bluer_objects/help/pdf.py +67 -0
- bluer_objects/help/upload.py +10 -3
- bluer_objects/host/functions.py +4 -1
- bluer_objects/logger/confusion_matrix.py +76 -0
- bluer_objects/logger/image.py +110 -0
- bluer_objects/logger/stitch.py +107 -0
- bluer_objects/markdown.py +8 -6
- bluer_objects/metadata/__init__.py +1 -0
- bluer_objects/metadata/flatten.py +27 -0
- bluer_objects/mlflow/__init__.py +1 -1
- bluer_objects/mlflow/__main__.py +49 -31
- bluer_objects/mlflow/lock/__init__.py +1 -0
- bluer_objects/mlflow/lock/__main__.py +58 -0
- bluer_objects/mlflow/lock/functions.py +121 -0
- bluer_objects/mlflow/logging.py +53 -41
- bluer_objects/mlflow/models.py +7 -0
- bluer_objects/mlflow/objects.py +7 -0
- bluer_objects/mlflow/runs.py +10 -1
- bluer_objects/mlflow/serverless/__init__.py +3 -0
- bluer_objects/mlflow/serverless/api.py +88 -0
- bluer_objects/mlflow/serverless/read.py +19 -0
- bluer_objects/mlflow/serverless/search.py +35 -0
- bluer_objects/mlflow/serverless/write.py +42 -0
- bluer_objects/mlflow/tags.py +59 -9
- bluer_objects/objects.py +3 -1
- bluer_objects/pdf/__init__.py +1 -0
- bluer_objects/pdf/__main__.py +78 -0
- bluer_objects/pdf/convert/__init__.py +0 -0
- bluer_objects/pdf/convert/batch.py +54 -0
- bluer_objects/pdf/convert/combination.py +32 -0
- bluer_objects/pdf/convert/convert.py +110 -0
- bluer_objects/pdf/convert/image.py +53 -0
- bluer_objects/pdf/convert/md.py +97 -0
- bluer_objects/pdf/convert/missing.py +96 -0
- bluer_objects/pdf/convert/pdf.py +37 -0
- bluer_objects/sample.env +6 -0
- bluer_objects/storage/WebDAV.py +11 -7
- bluer_objects/storage/WebDAVrequest.py +360 -0
- bluer_objects/storage/WebDAVzip.py +26 -29
- bluer_objects/storage/__init__.py +28 -1
- bluer_objects/storage/__main__.py +40 -6
- bluer_objects/storage/base.py +84 -5
- bluer_objects/storage/policies.py +7 -0
- bluer_objects/storage/s3.py +367 -0
- bluer_objects/testing/__main__.py +6 -0
- bluer_objects/tests/test_README_consts.py +71 -0
- bluer_objects/tests/test_README_items.py +128 -0
- bluer_objects/tests/test_alias.py +33 -0
- bluer_objects/tests/test_env.py +42 -7
- bluer_objects/tests/test_file_download.py +30 -0
- bluer_objects/tests/test_file_load_save.py +1 -2
- bluer_objects/tests/test_file_load_save_text.py +46 -0
- bluer_objects/tests/test_graphics_gif.py +2 -0
- bluer_objects/tests/test_log_image_grid.py +29 -0
- bluer_objects/tests/test_logger_confusion_matrix.py +18 -0
- bluer_objects/tests/test_logger_matrix.py +2 -2
- bluer_objects/tests/test_logger_stitch_images.py +47 -0
- bluer_objects/tests/test_metadata.py +12 -6
- bluer_objects/tests/test_metadata_flatten.py +109 -0
- bluer_objects/tests/test_mlflow.py +114 -5
- bluer_objects/tests/test_mlflow_lock.py +26 -0
- bluer_objects/tests/test_objects.py +2 -0
- bluer_objects/tests/test_shell.py +34 -0
- bluer_objects/tests/test_storage.py +8 -21
- bluer_objects/tests/test_storage_base.py +39 -0
- bluer_objects/tests/test_storage_s3.py +67 -0
- bluer_objects/tests/test_storage_webdav_request.py +75 -0
- bluer_objects/tests/test_storage_webdav_zip.py +42 -0
- bluer_objects/tests/test_web_is_accessible.py +11 -0
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/METADATA +20 -11
- bluer_objects-6.464.1.dist-info/RECORD +228 -0
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/WHEEL +1 -1
- bluer_objects/.abcli/storage/download_file.sh +0 -9
- bluer_objects/.abcli/storage/exists.sh +0 -8
- bluer_objects/.abcli/storage/list.sh +0 -8
- bluer_objects/.abcli/storage/rm.sh +0 -11
- bluer_objects/.abcli/tests/mlflow_test.sh +0 -7
- bluer_objects-6.104.1.dist-info/RECORD +0 -143
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/licenses/LICENSE +0 -0
- {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from bluer_objects import file, objects
|
|
2
|
+
from bluer_objects.env import abcli_path_git
|
|
3
|
+
from bluer_objects.logger import logger
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def convert_pdf(
|
|
7
|
+
source_filename: str,
|
|
8
|
+
suffix: str,
|
|
9
|
+
object_name: str,
|
|
10
|
+
list_of_pdfs: list[str],
|
|
11
|
+
) -> bool:
|
|
12
|
+
logger.info("🌠 pdf found!")
|
|
13
|
+
filename_pdf = file.add_extension(
|
|
14
|
+
objects.path_of(
|
|
15
|
+
filename="docs/{}".format(
|
|
16
|
+
(
|
|
17
|
+
suffix.split(abcli_path_git, 1)[1]
|
|
18
|
+
if abcli_path_git in suffix
|
|
19
|
+
else suffix
|
|
20
|
+
),
|
|
21
|
+
),
|
|
22
|
+
object_name=object_name,
|
|
23
|
+
),
|
|
24
|
+
"pdf",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if filename_pdf not in list_of_pdfs:
|
|
28
|
+
list_of_pdfs.append(filename_pdf)
|
|
29
|
+
|
|
30
|
+
if file.exists(filename_pdf):
|
|
31
|
+
logger.info(f"✅ {filename_pdf}")
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
return file.copy(
|
|
35
|
+
source_filename,
|
|
36
|
+
filename_pdf,
|
|
37
|
+
)
|
bluer_objects/sample.env
CHANGED
bluer_objects/storage/WebDAV.py
CHANGED
|
@@ -4,6 +4,7 @@ from webdav3.client import Client
|
|
|
4
4
|
from bluer_objects.storage.base import StorageInterface
|
|
5
5
|
from bluer_objects import env, file, path
|
|
6
6
|
from bluer_objects import objects
|
|
7
|
+
from bluer_objects.storage.policies import DownloadPolicy
|
|
7
8
|
from bluer_objects.logger import logger
|
|
8
9
|
|
|
9
10
|
|
|
@@ -56,6 +57,7 @@ class WebDAVInterface(StorageInterface):
|
|
|
56
57
|
object_name: str,
|
|
57
58
|
filename: str = "",
|
|
58
59
|
log: bool = True,
|
|
60
|
+
policy: DownloadPolicy = DownloadPolicy.NONE,
|
|
59
61
|
) -> bool:
|
|
60
62
|
local_path = objects.path_of(
|
|
61
63
|
object_name=object_name,
|
|
@@ -80,21 +82,21 @@ class WebDAVInterface(StorageInterface):
|
|
|
80
82
|
object_name=object_name,
|
|
81
83
|
filename=filename,
|
|
82
84
|
log=log,
|
|
85
|
+
policy=policy,
|
|
83
86
|
)
|
|
84
87
|
|
|
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
88
|
def upload(
|
|
93
89
|
self,
|
|
94
90
|
object_name: str,
|
|
95
91
|
filename: str = "",
|
|
92
|
+
public: bool = False,
|
|
93
|
+
zip: bool = False,
|
|
96
94
|
log: bool = True,
|
|
97
95
|
) -> bool:
|
|
96
|
+
if public or zip:
|
|
97
|
+
logger.error("public/zip upload not supported.")
|
|
98
|
+
return False
|
|
99
|
+
|
|
98
100
|
if filename:
|
|
99
101
|
remote_dir = "/".join([object_name] + filename.split("/")[:-1])
|
|
100
102
|
if not self.mkdir(
|
|
@@ -118,5 +120,7 @@ class WebDAVInterface(StorageInterface):
|
|
|
118
120
|
return super().upload(
|
|
119
121
|
object_name=object_name,
|
|
120
122
|
filename=filename,
|
|
123
|
+
public=public,
|
|
124
|
+
zip=zip,
|
|
121
125
|
log=log,
|
|
122
126
|
)
|
|
@@ -0,0 +1,360 @@
|
|
|
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.storage.policies import DownloadPolicy
|
|
12
|
+
from bluer_objects.logger import logger
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# https://chatgpt.com/c/6824cf43-6738-8005-8733-54b6a77f20ee
|
|
16
|
+
class WebDAVRequestInterface(StorageInterface):
|
|
17
|
+
name = "webdav-request"
|
|
18
|
+
|
|
19
|
+
def clear(
|
|
20
|
+
self,
|
|
21
|
+
do_dryrun: bool = True,
|
|
22
|
+
log: bool = True,
|
|
23
|
+
public: bool = False,
|
|
24
|
+
) -> bool:
|
|
25
|
+
if not super().clear(
|
|
26
|
+
do_dryrun=do_dryrun,
|
|
27
|
+
log=log,
|
|
28
|
+
public=public,
|
|
29
|
+
):
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
success, list_of_objects = self.list_raw(
|
|
33
|
+
suffix="",
|
|
34
|
+
recursive=False,
|
|
35
|
+
)
|
|
36
|
+
if not success:
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
count: int = 0
|
|
40
|
+
for thing in tqdm(list_of_objects):
|
|
41
|
+
thing_name = thing.split(f"{env.WEBDAV_LOGIN}/", 1)[1]
|
|
42
|
+
if not thing_name.startswith("test"):
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
if not thing_name.endswith("/"):
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
if not self.delete(
|
|
49
|
+
object_name=thing_name.split("/", 1)[0],
|
|
50
|
+
do_dryrun=do_dryrun,
|
|
51
|
+
log=log,
|
|
52
|
+
):
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
count += 1
|
|
56
|
+
|
|
57
|
+
logger.info(f"deleted {count} object(s).")
|
|
58
|
+
return True
|
|
59
|
+
|
|
60
|
+
def delete(
|
|
61
|
+
self,
|
|
62
|
+
object_name: str,
|
|
63
|
+
do_dryrun: bool = True,
|
|
64
|
+
log: bool = True,
|
|
65
|
+
) -> bool:
|
|
66
|
+
if log:
|
|
67
|
+
logger.info(
|
|
68
|
+
"{}.delete({}){}".format(
|
|
69
|
+
self.__class__.__name__,
|
|
70
|
+
object_name,
|
|
71
|
+
" dryrun" if do_dryrun else "",
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
if do_dryrun:
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
response = requests.request(
|
|
79
|
+
method="DELETE",
|
|
80
|
+
url=f"{env.WEBDAV_HOSTNAME}/{object_name}/",
|
|
81
|
+
auth=HTTPBasicAuth(
|
|
82
|
+
env.WEBDAV_LOGIN,
|
|
83
|
+
env.WEBDAV_PASSWORD,
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logger.error(e)
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
if response.status_code in [200, 204]:
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
logger.error(f"failed to delete: {response.status_code} - {response.text}")
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
def mkdir(
|
|
97
|
+
self,
|
|
98
|
+
path: str,
|
|
99
|
+
log: bool = True,
|
|
100
|
+
) -> bool:
|
|
101
|
+
url = f"{env.WEBDAV_HOSTNAME}/"
|
|
102
|
+
for folder in path.split("/"):
|
|
103
|
+
url = f"{url}{folder}/"
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
response = requests.request(
|
|
107
|
+
"MKCOL",
|
|
108
|
+
url,
|
|
109
|
+
auth=HTTPBasicAuth(
|
|
110
|
+
env.WEBDAV_LOGIN,
|
|
111
|
+
env.WEBDAV_PASSWORD,
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
except Exception as e:
|
|
115
|
+
logger.error(e)
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
if response.status_code == 405: # Already exists
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
if response.status_code == 201: # Created
|
|
122
|
+
if log:
|
|
123
|
+
logger.info(
|
|
124
|
+
"{}.mkdir {}".format(
|
|
125
|
+
self.__class__.__name__,
|
|
126
|
+
url.split(env.WEBDAV_HOSTNAME, 1)[1],
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
logger.error(f"failed to create: {response.status_code} - {response.text}")
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
def download(
|
|
137
|
+
self,
|
|
138
|
+
object_name: str,
|
|
139
|
+
filename: str = "",
|
|
140
|
+
log: bool = True,
|
|
141
|
+
policy: DownloadPolicy = DownloadPolicy.NONE,
|
|
142
|
+
) -> bool:
|
|
143
|
+
if filename:
|
|
144
|
+
local_path = objects.path_of(
|
|
145
|
+
object_name=object_name,
|
|
146
|
+
filename=filename,
|
|
147
|
+
create=True,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if not path.create(file.path(local_path)):
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
url = f"{env.WEBDAV_HOSTNAME}/{object_name}/{filename}"
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
response = requests.get(
|
|
157
|
+
url,
|
|
158
|
+
auth=HTTPBasicAuth(
|
|
159
|
+
env.WEBDAV_LOGIN,
|
|
160
|
+
env.WEBDAV_PASSWORD,
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
except Exception as e:
|
|
164
|
+
logger.error(e)
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
if response.status_code == 404: # object not found
|
|
168
|
+
return True
|
|
169
|
+
|
|
170
|
+
if response.status_code == 200:
|
|
171
|
+
try:
|
|
172
|
+
with open(local_path, "wb") as file_:
|
|
173
|
+
file_.write(response.content)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.error(e)
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
return super().download(
|
|
179
|
+
object_name=object_name,
|
|
180
|
+
filename=filename,
|
|
181
|
+
log=log,
|
|
182
|
+
policy=policy,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
logger.error(f"failed to download: {response.status_code}")
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
success, list_of_files = self.ls(
|
|
189
|
+
object_name=object_name,
|
|
190
|
+
where="cloud",
|
|
191
|
+
)
|
|
192
|
+
if not success:
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
for filename_ in tqdm(list_of_files):
|
|
196
|
+
if not self.download(
|
|
197
|
+
object_name=object_name,
|
|
198
|
+
filename=filename_,
|
|
199
|
+
log=log,
|
|
200
|
+
policy=policy,
|
|
201
|
+
):
|
|
202
|
+
return False
|
|
203
|
+
|
|
204
|
+
return True
|
|
205
|
+
|
|
206
|
+
def list_raw(
|
|
207
|
+
self,
|
|
208
|
+
suffix: str,
|
|
209
|
+
recursive: bool,
|
|
210
|
+
) -> Tuple[bool, List[str]]:
|
|
211
|
+
# https://chatgpt.com/c/6824f8d3-d9c0-8005-a7fa-d646f812f4b7
|
|
212
|
+
headers = {
|
|
213
|
+
"Depth": "infinity" if recursive else "1",
|
|
214
|
+
"Content-Type": "application/xml",
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# Minimal PROPFIND XML body
|
|
218
|
+
data = """<?xml version="1.0"?>
|
|
219
|
+
<d:propfind xmlns:d="DAV:">
|
|
220
|
+
<d:prop><d:displayname/></d:prop>
|
|
221
|
+
</d:propfind>"""
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
response = requests.request(
|
|
225
|
+
method="PROPFIND",
|
|
226
|
+
url=f"{env.WEBDAV_HOSTNAME}/{suffix}",
|
|
227
|
+
data=data,
|
|
228
|
+
headers=headers,
|
|
229
|
+
auth=HTTPBasicAuth(
|
|
230
|
+
env.WEBDAV_LOGIN,
|
|
231
|
+
env.WEBDAV_PASSWORD,
|
|
232
|
+
),
|
|
233
|
+
)
|
|
234
|
+
except Exception as e:
|
|
235
|
+
logger.error(e)
|
|
236
|
+
return False, []
|
|
237
|
+
|
|
238
|
+
if response.status_code == 404: # object not found
|
|
239
|
+
return True, []
|
|
240
|
+
|
|
241
|
+
if response.status_code in (207, 207):
|
|
242
|
+
tree = ET.fromstring(response.content)
|
|
243
|
+
ns = {"d": "DAV:"}
|
|
244
|
+
list_of_files = []
|
|
245
|
+
for resp in tree.findall("d:response", ns):
|
|
246
|
+
href = resp.find("d:href", ns).text
|
|
247
|
+
list_of_files.append(href)
|
|
248
|
+
|
|
249
|
+
return True, list_of_files
|
|
250
|
+
|
|
251
|
+
logger.error(f"failed to list: {response.status_code} - {response.text}")
|
|
252
|
+
return False, []
|
|
253
|
+
|
|
254
|
+
def ls(
|
|
255
|
+
self,
|
|
256
|
+
object_name: str,
|
|
257
|
+
where: str = "local",
|
|
258
|
+
) -> Tuple[bool, List[str]]:
|
|
259
|
+
if where == "cloud":
|
|
260
|
+
success, list_of_files = self.list_raw(
|
|
261
|
+
suffix=f"{object_name}/",
|
|
262
|
+
recursive=True,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
return success, sorted(
|
|
266
|
+
[
|
|
267
|
+
filename
|
|
268
|
+
for filename in [
|
|
269
|
+
filename.split(f"{env.WEBDAV_LOGIN}/{object_name}/", 1)[1]
|
|
270
|
+
for filename in list_of_files
|
|
271
|
+
if not filename.endswith("/")
|
|
272
|
+
]
|
|
273
|
+
if filename
|
|
274
|
+
]
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return super().ls(
|
|
278
|
+
object_name=object_name,
|
|
279
|
+
where=where,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
def upload(
|
|
283
|
+
self,
|
|
284
|
+
object_name: str,
|
|
285
|
+
filename: str = "",
|
|
286
|
+
public: bool = False,
|
|
287
|
+
zip: bool = False,
|
|
288
|
+
log: bool = True,
|
|
289
|
+
) -> bool:
|
|
290
|
+
if public or zip:
|
|
291
|
+
logger.error("public/zip upload not supported.")
|
|
292
|
+
return False
|
|
293
|
+
|
|
294
|
+
if filename:
|
|
295
|
+
if not self.mkdir(
|
|
296
|
+
path="{}/{}".format(
|
|
297
|
+
object_name,
|
|
298
|
+
file.path(filename),
|
|
299
|
+
),
|
|
300
|
+
log=log,
|
|
301
|
+
):
|
|
302
|
+
return False
|
|
303
|
+
|
|
304
|
+
url = f"{env.WEBDAV_HOSTNAME}/{object_name}/{filename}"
|
|
305
|
+
|
|
306
|
+
local_path = objects.path_of(
|
|
307
|
+
object_name=object_name,
|
|
308
|
+
filename=filename,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
try:
|
|
312
|
+
with open(local_path, "rb") as file_data:
|
|
313
|
+
response = requests.put(
|
|
314
|
+
url,
|
|
315
|
+
data=file_data,
|
|
316
|
+
auth=HTTPBasicAuth(
|
|
317
|
+
env.WEBDAV_LOGIN,
|
|
318
|
+
env.WEBDAV_PASSWORD,
|
|
319
|
+
),
|
|
320
|
+
)
|
|
321
|
+
except Exception as e:
|
|
322
|
+
logger.error(e)
|
|
323
|
+
return False
|
|
324
|
+
|
|
325
|
+
if response.status_code in [200, 201, 204]:
|
|
326
|
+
return super().upload(
|
|
327
|
+
object_name=object_name,
|
|
328
|
+
filename=filename,
|
|
329
|
+
public=public,
|
|
330
|
+
zip=zip,
|
|
331
|
+
log=log,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
logger.error(f"failed to upload: {response.status_code} - {response.text}")
|
|
335
|
+
return False
|
|
336
|
+
|
|
337
|
+
object_path = "{}/".format(objects.object_path(object_name=object_name))
|
|
338
|
+
for filename_ in tqdm(
|
|
339
|
+
sorted(
|
|
340
|
+
glob.glob(
|
|
341
|
+
objects.path_of(
|
|
342
|
+
object_name=object_name,
|
|
343
|
+
filename="**",
|
|
344
|
+
),
|
|
345
|
+
recursive=True,
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
):
|
|
349
|
+
if not file.exists(filename_):
|
|
350
|
+
continue
|
|
351
|
+
|
|
352
|
+
if not self.upload(
|
|
353
|
+
object_name=object_name,
|
|
354
|
+
filename=filename_.split(object_path, 1)[1],
|
|
355
|
+
public=public,
|
|
356
|
+
log=log,
|
|
357
|
+
):
|
|
358
|
+
return False
|
|
359
|
+
|
|
360
|
+
return True
|
|
@@ -5,15 +5,16 @@ from webdav3.client import Client
|
|
|
5
5
|
from tqdm import tqdm
|
|
6
6
|
|
|
7
7
|
from bluer_objects.storage.base import StorageInterface
|
|
8
|
-
from bluer_objects import env
|
|
8
|
+
from bluer_objects import env
|
|
9
9
|
from bluer_objects import objects
|
|
10
|
-
from bluer_objects.host import
|
|
10
|
+
from bluer_objects.host import unzip
|
|
11
|
+
from bluer_objects.storage.policies import DownloadPolicy
|
|
11
12
|
from bluer_objects.logger import logger
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
# tars the objects to avoid 'content-length' - see WebDAVInterface.
|
|
15
16
|
class WebDAVzipInterface(StorageInterface):
|
|
16
|
-
name = "
|
|
17
|
+
name = "webdav-zip"
|
|
17
18
|
|
|
18
19
|
def __init__(self):
|
|
19
20
|
super().__init__()
|
|
@@ -29,13 +30,15 @@ class WebDAVzipInterface(StorageInterface):
|
|
|
29
30
|
def clear(
|
|
30
31
|
self,
|
|
31
32
|
do_dryrun: bool = True,
|
|
33
|
+
log: bool = True,
|
|
34
|
+
public: bool = False,
|
|
32
35
|
) -> bool:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
if not super().clear(
|
|
37
|
+
do_dryrun=do_dryrun,
|
|
38
|
+
log=log,
|
|
39
|
+
public=public,
|
|
40
|
+
):
|
|
41
|
+
return False
|
|
39
42
|
|
|
40
43
|
count: int = 0
|
|
41
44
|
for thing in tqdm(self.client.list()):
|
|
@@ -65,6 +68,7 @@ class WebDAVzipInterface(StorageInterface):
|
|
|
65
68
|
object_name: str,
|
|
66
69
|
filename: str = "",
|
|
67
70
|
log: bool = True,
|
|
71
|
+
policy: DownloadPolicy = DownloadPolicy.NONE,
|
|
68
72
|
) -> bool:
|
|
69
73
|
object_path = objects.object_path(
|
|
70
74
|
object_name=object_name,
|
|
@@ -99,6 +103,7 @@ class WebDAVzipInterface(StorageInterface):
|
|
|
99
103
|
return super().download(
|
|
100
104
|
object_name=object_name,
|
|
101
105
|
log=log,
|
|
106
|
+
policy=policy,
|
|
102
107
|
)
|
|
103
108
|
|
|
104
109
|
def ls(
|
|
@@ -106,24 +111,6 @@ class WebDAVzipInterface(StorageInterface):
|
|
|
106
111
|
object_name: str,
|
|
107
112
|
where: str = "local",
|
|
108
113
|
) -> 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
114
|
if where == "cloud":
|
|
128
115
|
try:
|
|
129
116
|
if self.client.check(remote_path=f"{object_name}.zip"):
|
|
@@ -134,15 +121,23 @@ class WebDAVzipInterface(StorageInterface):
|
|
|
134
121
|
|
|
135
122
|
return True, []
|
|
136
123
|
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
return super().ls(
|
|
125
|
+
object_name=object_name,
|
|
126
|
+
where=where,
|
|
127
|
+
)
|
|
139
128
|
|
|
140
129
|
def upload(
|
|
141
130
|
self,
|
|
142
131
|
object_name: str,
|
|
143
132
|
filename: str = "",
|
|
133
|
+
public: bool = False,
|
|
134
|
+
zip: bool = False,
|
|
144
135
|
log: bool = True,
|
|
145
136
|
) -> bool:
|
|
137
|
+
if public or zip:
|
|
138
|
+
logger.error("public/zip upload not supported.")
|
|
139
|
+
return False
|
|
140
|
+
|
|
146
141
|
object_path = objects.object_path(object_name=object_name)
|
|
147
142
|
|
|
148
143
|
if not zip(
|
|
@@ -165,5 +160,7 @@ class WebDAVzipInterface(StorageInterface):
|
|
|
165
160
|
|
|
166
161
|
return super().upload(
|
|
167
162
|
object_name=object_name,
|
|
163
|
+
public=public,
|
|
164
|
+
zip=zip,
|
|
168
165
|
log=log,
|
|
169
166
|
)
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
from typing import Tuple, List
|
|
2
2
|
|
|
3
|
+
from bluer_objects.storage.s3 import S3Interface
|
|
3
4
|
from bluer_objects.storage.base import StorageInterface
|
|
4
5
|
from bluer_objects.storage.WebDAV import WebDAVInterface
|
|
6
|
+
from bluer_objects.storage.WebDAVrequest import WebDAVRequestInterface
|
|
5
7
|
from bluer_objects.storage.WebDAVzip import WebDAVzipInterface
|
|
8
|
+
from bluer_objects.storage.policies import DownloadPolicy
|
|
6
9
|
from bluer_objects import env
|
|
7
10
|
from bluer_objects.logger import logger
|
|
8
11
|
|
|
9
12
|
interface = StorageInterface()
|
|
10
13
|
|
|
11
|
-
if env.BLUER_OBJECTS_STORAGE_INTERFACE ==
|
|
14
|
+
if env.BLUER_OBJECTS_STORAGE_INTERFACE == S3Interface.name:
|
|
15
|
+
interface = S3Interface()
|
|
16
|
+
elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVInterface.name:
|
|
12
17
|
interface = WebDAVInterface()
|
|
18
|
+
elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVRequestInterface.name:
|
|
19
|
+
interface = WebDAVRequestInterface()
|
|
13
20
|
elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVzipInterface.name:
|
|
14
21
|
interface = WebDAVzipInterface()
|
|
15
22
|
else:
|
|
@@ -19,9 +26,13 @@ else:
|
|
|
19
26
|
|
|
20
27
|
def clear(
|
|
21
28
|
do_dryrun: bool = True,
|
|
29
|
+
log: bool = True,
|
|
30
|
+
public: bool = False,
|
|
22
31
|
) -> bool:
|
|
23
32
|
return interface.clear(
|
|
24
33
|
do_dryrun=do_dryrun,
|
|
34
|
+
log=log,
|
|
35
|
+
public=public,
|
|
25
36
|
)
|
|
26
37
|
|
|
27
38
|
|
|
@@ -29,11 +40,13 @@ def download(
|
|
|
29
40
|
object_name: str,
|
|
30
41
|
filename: str = "",
|
|
31
42
|
log: bool = True,
|
|
43
|
+
policy: DownloadPolicy = DownloadPolicy.NONE,
|
|
32
44
|
) -> bool:
|
|
33
45
|
return interface.download(
|
|
34
46
|
object_name=object_name,
|
|
35
47
|
filename=filename,
|
|
36
48
|
log=log,
|
|
49
|
+
policy=policy,
|
|
37
50
|
)
|
|
38
51
|
|
|
39
52
|
|
|
@@ -47,13 +60,27 @@ def ls(
|
|
|
47
60
|
)
|
|
48
61
|
|
|
49
62
|
|
|
63
|
+
def ls_objects(
|
|
64
|
+
prefix: str,
|
|
65
|
+
where: str = "local",
|
|
66
|
+
) -> Tuple[bool, List[str]]:
|
|
67
|
+
return interface.ls_objects(
|
|
68
|
+
prefix=prefix,
|
|
69
|
+
where=where,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
50
73
|
def upload(
|
|
51
74
|
object_name: str,
|
|
52
75
|
filename: str = "",
|
|
76
|
+
public: bool = False,
|
|
77
|
+
zip: bool = False,
|
|
53
78
|
log: bool = True,
|
|
54
79
|
) -> bool:
|
|
55
80
|
return interface.upload(
|
|
56
81
|
object_name=object_name,
|
|
57
82
|
filename=filename,
|
|
83
|
+
public=public,
|
|
84
|
+
zip=zip,
|
|
58
85
|
log=log,
|
|
59
86
|
)
|