bluer-objects 6.166.1__py3-none-any.whl → 6.170.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/__init__.py +1 -1
- 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/storage/s3.py +98 -0
- {bluer_objects-6.166.1.dist-info → bluer_objects-6.170.1.dist-info}/METADATA +2 -2
- {bluer_objects-6.166.1.dist-info → bluer_objects-6.170.1.dist-info}/RECORD +10 -7
- {bluer_objects-6.166.1.dist-info → bluer_objects-6.170.1.dist-info}/WHEEL +0 -0
- {bluer_objects-6.166.1.dist-info → bluer_objects-6.170.1.dist-info}/licenses/LICENSE +0 -0
- {bluer_objects-6.166.1.dist-info → bluer_objects-6.170.1.dist-info}/top_level.txt +0 -0
bluer_objects/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from blueness import module
|
|
4
|
+
from blueness.argparse.generic import sys_exit
|
|
5
|
+
|
|
6
|
+
from bluer_objects import NAME
|
|
7
|
+
from bluer_objects.mlflow.lock.functions import lock, unlock
|
|
8
|
+
from bluer_objects.logger import logger
|
|
9
|
+
|
|
10
|
+
NAME = module.name(__file__, NAME)
|
|
11
|
+
|
|
12
|
+
parser = argparse.ArgumentParser(NAME)
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"task",
|
|
15
|
+
type=str,
|
|
16
|
+
help="lock | unlock",
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--object_name",
|
|
20
|
+
type=str,
|
|
21
|
+
)
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"--lock",
|
|
24
|
+
type=str,
|
|
25
|
+
default="lock",
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--timeout",
|
|
29
|
+
type=int,
|
|
30
|
+
default=-1,
|
|
31
|
+
help="in seconds",
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--verbose",
|
|
35
|
+
type=int,
|
|
36
|
+
default=1,
|
|
37
|
+
help="0 | 1",
|
|
38
|
+
)
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
|
|
41
|
+
success = False
|
|
42
|
+
if args.task == "lock":
|
|
43
|
+
success = lock(
|
|
44
|
+
object_name=args.object_name,
|
|
45
|
+
lock_name=args.lock,
|
|
46
|
+
timeout=args.timeout,
|
|
47
|
+
verbose=args.verbose == 1,
|
|
48
|
+
)
|
|
49
|
+
elif args.task == "unlock":
|
|
50
|
+
success = unlock(
|
|
51
|
+
object_name=args.object_name,
|
|
52
|
+
lock_name=args.lock,
|
|
53
|
+
verbose=args.verbose == 1,
|
|
54
|
+
)
|
|
55
|
+
else:
|
|
56
|
+
success = None
|
|
57
|
+
|
|
58
|
+
sys_exit(logger, NAME, args.task, success)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from blueness import module
|
|
4
|
+
from bluer_options import string
|
|
5
|
+
|
|
6
|
+
from bluer_objects import NAME, env
|
|
7
|
+
from bluer_objects.mlflow.tags import get_tags, set_tags
|
|
8
|
+
from bluer_objects.logger import logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
NAME = module.name(__file__, NAME)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def lock(
|
|
15
|
+
object_name: str,
|
|
16
|
+
lock_name: str = "lock",
|
|
17
|
+
timeout: int = -1,
|
|
18
|
+
verbose: bool = True,
|
|
19
|
+
) -> bool:
|
|
20
|
+
logger.info(
|
|
21
|
+
"{}.lock: {}.{}{}".format(
|
|
22
|
+
NAME,
|
|
23
|
+
object_name,
|
|
24
|
+
lock_name,
|
|
25
|
+
"" if timeout == -1 else " @ {}".format(string.pretty_duration(timeout)),
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
start_time = time.time()
|
|
30
|
+
while True:
|
|
31
|
+
if timeout > 0 and time.time() - start_time > timeout:
|
|
32
|
+
if verbose:
|
|
33
|
+
logger.warning(
|
|
34
|
+
"{}.lock: {}.{} timeout.".format(
|
|
35
|
+
NAME,
|
|
36
|
+
object_name,
|
|
37
|
+
lock_name,
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
success, list_of_tags = get_tags(object_name=object_name)
|
|
43
|
+
if not success:
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
lock_value = list_of_tags.get(lock_name, "")
|
|
47
|
+
if lock_value:
|
|
48
|
+
if verbose:
|
|
49
|
+
logger.warning(
|
|
50
|
+
"{}.lock: {}.{} is locked by {}.".format(
|
|
51
|
+
NAME,
|
|
52
|
+
object_name,
|
|
53
|
+
lock_name,
|
|
54
|
+
lock_value,
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
time.sleep(env.MLFLOW_LOCK_WAIT_FOR_CLEARANCE)
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
lock_value = string.random()
|
|
61
|
+
if not set_tags(
|
|
62
|
+
object_name=object_name,
|
|
63
|
+
tags={lock_name: lock_value},
|
|
64
|
+
log=verbose,
|
|
65
|
+
icon="🔒",
|
|
66
|
+
):
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
time.sleep(env.MLFLOW_LOCK_WAIT_FOR_EXCLUSIVITY)
|
|
70
|
+
|
|
71
|
+
success, list_of_tags = get_tags(object_name=object_name)
|
|
72
|
+
if not success:
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
lock_value_read = list_of_tags.get(lock_name, "")
|
|
76
|
+
if lock_value_read != lock_value:
|
|
77
|
+
if verbose:
|
|
78
|
+
logger.warning(
|
|
79
|
+
"{}.lock: {}.{} is relocked by {} != {}.".format(
|
|
80
|
+
NAME,
|
|
81
|
+
object_name,
|
|
82
|
+
lock_name,
|
|
83
|
+
lock_value_read,
|
|
84
|
+
lock_value,
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
time.sleep(env.MLFLOW_LOCK_WAIT_FOR_CLEARANCE)
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
logger.info(
|
|
93
|
+
"{}.lock: {}.{} is locked by {}.".format(
|
|
94
|
+
NAME,
|
|
95
|
+
object_name,
|
|
96
|
+
lock_name,
|
|
97
|
+
lock_value,
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def unlock(
|
|
104
|
+
object_name: str,
|
|
105
|
+
lock_name: str = "lock",
|
|
106
|
+
verbose: bool = True,
|
|
107
|
+
) -> bool:
|
|
108
|
+
logger.info(
|
|
109
|
+
"{}.unlock: {}.{}".format(
|
|
110
|
+
NAME,
|
|
111
|
+
object_name,
|
|
112
|
+
lock_name,
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return set_tags(
|
|
117
|
+
object_name=object_name,
|
|
118
|
+
tags={lock_name: ""},
|
|
119
|
+
log=verbose,
|
|
120
|
+
icon="🔒",
|
|
121
|
+
)
|
bluer_objects/storage/s3.py
CHANGED
|
@@ -16,6 +16,104 @@ from bluer_objects.logger import logger
|
|
|
16
16
|
class S3Interface(StorageInterface):
|
|
17
17
|
name = "s3"
|
|
18
18
|
|
|
19
|
+
def clear(
|
|
20
|
+
self,
|
|
21
|
+
do_dryrun: bool = True,
|
|
22
|
+
log: bool = True,
|
|
23
|
+
) -> bool:
|
|
24
|
+
logger.info(
|
|
25
|
+
"{}.clear({})".format(
|
|
26
|
+
self.__class__.__name__,
|
|
27
|
+
"dryrun" if do_dryrun else "",
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
s3 = boto3.client(
|
|
33
|
+
"s3",
|
|
34
|
+
endpoint_url=env.S3_STORAGE_ENDPOINT_URL,
|
|
35
|
+
aws_access_key_id=env.S3_STORAGE_AWS_ACCESS_KEY_ID,
|
|
36
|
+
aws_secret_access_key=env.S3_STORAGE_AWS_SECRET_ACCESS_KEY,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
paginator = s3.get_paginator("list_objects_v2")
|
|
40
|
+
pages = paginator.paginate(
|
|
41
|
+
Bucket=env.S3_STORAGE_BUCKET,
|
|
42
|
+
Prefix="test",
|
|
43
|
+
)
|
|
44
|
+
except Exception as e:
|
|
45
|
+
logger.error(e)
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
list_of_objects = sorted(
|
|
49
|
+
list(
|
|
50
|
+
set(
|
|
51
|
+
reduce(
|
|
52
|
+
lambda x, y: x + y,
|
|
53
|
+
[
|
|
54
|
+
[
|
|
55
|
+
obj["Key"].split("/", 1)[0]
|
|
56
|
+
for obj in page.get("Contents", [])
|
|
57
|
+
]
|
|
58
|
+
for page in pages
|
|
59
|
+
],
|
|
60
|
+
[],
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
logger.info(f"{len(list_of_objects)} object(s) to delete.")
|
|
67
|
+
|
|
68
|
+
for object_name in tqdm(list_of_objects):
|
|
69
|
+
if not self.delete(
|
|
70
|
+
object_name=object_name,
|
|
71
|
+
do_dryrun=do_dryrun,
|
|
72
|
+
):
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
def delete(
|
|
78
|
+
self,
|
|
79
|
+
object_name: str,
|
|
80
|
+
do_dryrun: bool = True,
|
|
81
|
+
log: bool = True,
|
|
82
|
+
) -> bool:
|
|
83
|
+
if log:
|
|
84
|
+
logger.info(
|
|
85
|
+
"{}.delete({}){}".format(
|
|
86
|
+
self.__class__.__name__,
|
|
87
|
+
object_name,
|
|
88
|
+
" dryrun" if do_dryrun else "",
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
if do_dryrun:
|
|
92
|
+
return True
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
s3 = boto3.resource(
|
|
96
|
+
"s3",
|
|
97
|
+
endpoint_url=env.S3_STORAGE_ENDPOINT_URL,
|
|
98
|
+
aws_access_key_id=env.S3_STORAGE_AWS_ACCESS_KEY_ID,
|
|
99
|
+
aws_secret_access_key=env.S3_STORAGE_AWS_SECRET_ACCESS_KEY,
|
|
100
|
+
)
|
|
101
|
+
bucket = s3.Bucket(env.S3_STORAGE_BUCKET)
|
|
102
|
+
|
|
103
|
+
objects_to_delete = bucket.objects.filter(Prefix=f"{object_name}/")
|
|
104
|
+
delete_requests = [{"Key": obj.key} for obj in objects_to_delete]
|
|
105
|
+
|
|
106
|
+
if not delete_requests:
|
|
107
|
+
logger.warning(f"no files found under {object_name}.")
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
bucket.delete_objects(Delete={"Objects": delete_requests})
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(e)
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
return True
|
|
116
|
+
|
|
19
117
|
def download(
|
|
20
118
|
self,
|
|
21
119
|
object_name: str,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bluer_objects
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.170.1
|
|
4
4
|
Summary: 🌀 Object management in Bash.
|
|
5
5
|
Home-page: https://github.com/kamangir/bluer-objects
|
|
6
6
|
Author: Arash Abadpour (Kamangir)
|
|
@@ -64,6 +64,6 @@ pip install bluer-objects
|
|
|
64
64
|
|
|
65
65
|
[](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)
|
|
66
66
|
|
|
67
|
-
built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.
|
|
67
|
+
built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.170.1`](https://github.com/kamangir/bluer-objects).
|
|
68
68
|
|
|
69
69
|
built by 🌀 [`blueness-3.118.1`](https://github.com/kamangir/blueness).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
bluer_objects/__init__.py,sha256=
|
|
1
|
+
bluer_objects/__init__.py,sha256=Up7uiCfpaTfzOTrjFhSTVfEQQ9DtDCzeqOFsRvZ45Gw,315
|
|
2
2
|
bluer_objects/__main__.py,sha256=Yqfov833_hJuRne19WrGhT5DWAPtdffpoMxeSXS7EGw,359
|
|
3
3
|
bluer_objects/config.env,sha256=cpmtTuKHIBvVjX30MpAImFgwM0g24qTHwoO-lCJRInA,175
|
|
4
4
|
bluer_objects/env.py,sha256=aImjtNh8NKaua2rpQVFXWp86QF7nY87fDuMOO14O58E,1956
|
|
@@ -115,13 +115,16 @@ bluer_objects/mlflow/objects.py,sha256=aXYHLRCTt1FtDQoyPOG-doCFms7qF6Krz00Fg3kzJ
|
|
|
115
115
|
bluer_objects/mlflow/runs.py,sha256=v1IKRvxbuKkengESnG-xdUXxxNSkALMeBmfMQwrUKSs,2416
|
|
116
116
|
bluer_objects/mlflow/tags.py,sha256=8uBYRrE4weTLrwPqo-c4M21FEVRANf7SGCcxpoCPhuM,2475
|
|
117
117
|
bluer_objects/mlflow/testing.py,sha256=cJH5Ki02fJN_Xos1j9yvwQChXvMkOa9i12vtDKmkbNc,842
|
|
118
|
+
bluer_objects/mlflow/lock/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
119
|
+
bluer_objects/mlflow/lock/__main__.py,sha256=xF_xq2UqAsEohSOHjxaFXaw9KopOEDg6LRDM5a4VAPQ,1138
|
|
120
|
+
bluer_objects/mlflow/lock/functions.py,sha256=MOslqblNAOsRvILzLF4q6m2EAwCk4f4zEWQpsy8lVnM,3045
|
|
118
121
|
bluer_objects/storage/WebDAV.py,sha256=IvYZDST6Cg1rgRhQ5eh3Hrq8V7S3oon9O29MH55QLxA,2922
|
|
119
122
|
bluer_objects/storage/WebDAVrequest.py,sha256=ihWOxP7h28qj0-5AZ0SsERSBrViq9p4iNVeR4pGBWQo,9836
|
|
120
123
|
bluer_objects/storage/WebDAVzip.py,sha256=Sd_rU57pJaRa05sKNQiMr85Bg3w7O5k8N1pSN1u8omA,3872
|
|
121
124
|
bluer_objects/storage/__init__.py,sha256=XosPRjB20wDS-QMwQtr3zqKC9UM7U8z-PHwySGBegcQ,1646
|
|
122
125
|
bluer_objects/storage/__main__.py,sha256=vZI6rUkrekf1eYUgWOOUnFhl4qPfpByzwb-tihTOiIo,1776
|
|
123
126
|
bluer_objects/storage/base.py,sha256=72I1zvlpbQbFU20TxqcTodR4m8PYgBPXMfteek8V0_A,1949
|
|
124
|
-
bluer_objects/storage/s3.py,sha256=
|
|
127
|
+
bluer_objects/storage/s3.py,sha256=evUFpPk6PUv1KCXTMq_QCbygqNk0YNAOQr_B4gYrjBE,8342
|
|
125
128
|
bluer_objects/testing/__init__.py,sha256=DWY5ZtvCnHG_t9BDiqy_ArLOZi-nlyAtPVMLA1PPAMU,62
|
|
126
129
|
bluer_objects/testing/__main__.py,sha256=hhJV9qn0V_8FxzNDcoHCHr4A7zf9UudnNGJCAPkTBGU,750
|
|
127
130
|
bluer_objects/testing/functions.py,sha256=AXAfzWLcEPkbSYTehdahshjKJ45C4IJkRs_TgrHOntc,1355
|
|
@@ -153,8 +156,8 @@ bluer_objects/tests/test_storage_webdav_request.py,sha256=h2b8PeIx0-hQ2d6PmQcJZy
|
|
|
153
156
|
bluer_objects/tests/test_storage_webdav_zip.py,sha256=C19qxhkcHyTwVFzW35vL85SOcXJPkqXXaWUNll0Uyqc,1017
|
|
154
157
|
bluer_objects/tests/test_testing.py,sha256=d2NH435yqJBl9wmfMqGGd-f0Y0jsL2QhHUXkty9AwPA,235
|
|
155
158
|
bluer_objects/tests/test_version.py,sha256=Lyf3PMcA22e17BNRk_2VgPrtao6dWEgVoXo68Uds8SE,75
|
|
156
|
-
bluer_objects-6.
|
|
157
|
-
bluer_objects-6.
|
|
158
|
-
bluer_objects-6.
|
|
159
|
-
bluer_objects-6.
|
|
160
|
-
bluer_objects-6.
|
|
159
|
+
bluer_objects-6.170.1.dist-info/licenses/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
|
|
160
|
+
bluer_objects-6.170.1.dist-info/METADATA,sha256=ELD0riVQPhS4tFIUH_2uAloiFQl-_KJuL7nc5xozizw,3678
|
|
161
|
+
bluer_objects-6.170.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
162
|
+
bluer_objects-6.170.1.dist-info/top_level.txt,sha256=RX2TpddbnRkurda3G_pAdyeTztP2IhhRPx949GlEvQo,14
|
|
163
|
+
bluer_objects-6.170.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|