bluer-objects 6.3.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/abcli.sh +9 -0
- bluer_objects/.abcli/actions.sh +11 -0
- bluer_objects/.abcli/aka.sh +3 -0
- bluer_objects/.abcli/alias.sh +36 -0
- bluer_objects/.abcli/blue_objects.sh +11 -0
- bluer_objects/.abcli/cache.sh +5 -0
- bluer_objects/.abcli/clone.sh +94 -0
- bluer_objects/.abcli/download.sh +53 -0
- bluer_objects/.abcli/file.sh +8 -0
- bluer_objects/.abcli/gif.sh +27 -0
- bluer_objects/.abcli/host.sh +29 -0
- bluer_objects/.abcli/ls.sh +24 -0
- bluer_objects/.abcli/metadata/get.sh +24 -0
- bluer_objects/.abcli/metadata/post.sh +22 -0
- bluer_objects/.abcli/metadata.sh +16 -0
- bluer_objects/.abcli/mlflow/browse.sh +36 -0
- bluer_objects/.abcli/mlflow/cache.sh +31 -0
- bluer_objects/.abcli/mlflow/list_registered_models.sh +9 -0
- bluer_objects/.abcli/mlflow/log_artifacts.sh +10 -0
- bluer_objects/.abcli/mlflow/log_run.sh +10 -0
- bluer_objects/.abcli/mlflow/run.sh +11 -0
- bluer_objects/.abcli/mlflow/tags/clone.sh +15 -0
- bluer_objects/.abcli/mlflow/tags/get.sh +10 -0
- bluer_objects/.abcli/mlflow/tags/search.sh +12 -0
- bluer_objects/.abcli/mlflow/tags/set.sh +13 -0
- bluer_objects/.abcli/mlflow/tags.sh +16 -0
- bluer_objects/.abcli/mlflow/test.sh +11 -0
- bluer_objects/.abcli/mlflow/transition.sh +20 -0
- bluer_objects/.abcli/mlflow.sh +29 -0
- bluer_objects/.abcli/mysql/cache.sh +65 -0
- bluer_objects/.abcli/mysql/relations.sh +83 -0
- bluer_objects/.abcli/mysql/tags.sh +85 -0
- bluer_objects/.abcli/mysql.sh +16 -0
- bluer_objects/.abcli/object.sh +54 -0
- bluer_objects/.abcli/publish.sh +58 -0
- bluer_objects/.abcli/select.sh +34 -0
- bluer_objects/.abcli/storage/clear.sh +45 -0
- bluer_objects/.abcli/storage/download_file.sh +9 -0
- bluer_objects/.abcli/storage/exists.sh +8 -0
- bluer_objects/.abcli/storage/list.sh +8 -0
- bluer_objects/.abcli/storage/rm.sh +11 -0
- bluer_objects/.abcli/storage/status.sh +11 -0
- bluer_objects/.abcli/storage.sh +15 -0
- bluer_objects/.abcli/tags.sh +5 -0
- bluer_objects/.abcli/tests/README.sh +8 -0
- bluer_objects/.abcli/tests/clone.sh +32 -0
- bluer_objects/.abcli/tests/help.sh +85 -0
- bluer_objects/.abcli/tests/host.sh +7 -0
- bluer_objects/.abcli/tests/ls.sh +13 -0
- bluer_objects/.abcli/tests/metadata.sh +53 -0
- bluer_objects/.abcli/tests/mlflow_cache.sh +14 -0
- bluer_objects/.abcli/tests/mlflow_logging.sh +12 -0
- bluer_objects/.abcli/tests/mlflow_tags.sh +29 -0
- bluer_objects/.abcli/tests/mlflow_test.sh +7 -0
- bluer_objects/.abcli/tests/mysql_cache.sh +15 -0
- bluer_objects/.abcli/tests/mysql_relations.sh +20 -0
- bluer_objects/.abcli/tests/mysql_tags.sh +16 -0
- bluer_objects/.abcli/tests/test_gif.sh +13 -0
- bluer_objects/.abcli/tests/version.sh +10 -0
- bluer_objects/.abcli/upload.sh +73 -0
- bluer_objects/README/__init__.py +29 -0
- bluer_objects/README/functions.py +285 -0
- bluer_objects/README/items.py +30 -0
- bluer_objects/__init__.py +19 -0
- bluer_objects/__main__.py +16 -0
- bluer_objects/config.env +22 -0
- bluer_objects/env.py +72 -0
- bluer_objects/file/__init__.py +41 -0
- bluer_objects/file/__main__.py +51 -0
- bluer_objects/file/classes.py +38 -0
- bluer_objects/file/functions.py +290 -0
- bluer_objects/file/load.py +219 -0
- bluer_objects/file/save.py +280 -0
- bluer_objects/graphics/__init__.py +4 -0
- bluer_objects/graphics/__main__.py +84 -0
- bluer_objects/graphics/frame.py +15 -0
- bluer_objects/graphics/gif.py +86 -0
- bluer_objects/graphics/screen.py +63 -0
- bluer_objects/graphics/signature.py +97 -0
- bluer_objects/graphics/text.py +165 -0
- bluer_objects/help/__init__.py +0 -0
- bluer_objects/help/__main__.py +10 -0
- bluer_objects/help/functions.py +5 -0
- bluer_objects/host/__init__.py +1 -0
- bluer_objects/host/__main__.py +84 -0
- bluer_objects/host/functions.py +66 -0
- bluer_objects/logger/__init__.py +4 -0
- bluer_objects/logger/matrix.py +209 -0
- bluer_objects/markdown.py +43 -0
- bluer_objects/metadata/__init__.py +8 -0
- bluer_objects/metadata/__main__.py +110 -0
- bluer_objects/metadata/enums.py +29 -0
- bluer_objects/metadata/get.py +89 -0
- bluer_objects/metadata/post.py +101 -0
- bluer_objects/mlflow/__init__.py +28 -0
- bluer_objects/mlflow/__main__.py +271 -0
- bluer_objects/mlflow/cache.py +13 -0
- bluer_objects/mlflow/logging.py +81 -0
- bluer_objects/mlflow/models.py +57 -0
- bluer_objects/mlflow/objects.py +76 -0
- bluer_objects/mlflow/runs.py +100 -0
- bluer_objects/mlflow/tags.py +90 -0
- bluer_objects/mlflow/testing.py +39 -0
- bluer_objects/mysql/cache/__init__.py +8 -0
- bluer_objects/mysql/cache/__main__.py +91 -0
- bluer_objects/mysql/cache/functions.py +181 -0
- bluer_objects/mysql/relations/__init__.py +9 -0
- bluer_objects/mysql/relations/__main__.py +138 -0
- bluer_objects/mysql/relations/functions.py +180 -0
- bluer_objects/mysql/table.py +144 -0
- bluer_objects/mysql/tags/__init__.py +1 -0
- bluer_objects/mysql/tags/__main__.py +130 -0
- bluer_objects/mysql/tags/functions.py +203 -0
- bluer_objects/objects.py +167 -0
- bluer_objects/path.py +194 -0
- bluer_objects/sample.env +16 -0
- bluer_objects/storage/__init__.py +3 -0
- bluer_objects/storage/__main__.py +114 -0
- bluer_objects/storage/classes.py +237 -0
- bluer_objects/tests/__init__.py +0 -0
- bluer_objects/tests/test_README.py +5 -0
- bluer_objects/tests/test_env.py +27 -0
- bluer_objects/tests/test_file_load_save.py +105 -0
- bluer_objects/tests/test_fullname.py +5 -0
- bluer_objects/tests/test_graphics.py +28 -0
- bluer_objects/tests/test_graphics_frame.py +11 -0
- bluer_objects/tests/test_graphics_gif.py +29 -0
- bluer_objects/tests/test_graphics_screen.py +8 -0
- bluer_objects/tests/test_graphics_signature.py +80 -0
- bluer_objects/tests/test_graphics_text.py +14 -0
- bluer_objects/tests/test_logger.py +5 -0
- bluer_objects/tests/test_logger_matrix.py +73 -0
- bluer_objects/tests/test_markdown.py +10 -0
- bluer_objects/tests/test_metadata.py +204 -0
- bluer_objects/tests/test_mlflow.py +60 -0
- bluer_objects/tests/test_mysql_cache.py +14 -0
- bluer_objects/tests/test_mysql_relations.py +16 -0
- bluer_objects/tests/test_mysql_table.py +9 -0
- bluer_objects/tests/test_mysql_tags.py +13 -0
- bluer_objects/tests/test_objects.py +180 -0
- bluer_objects/tests/test_path.py +7 -0
- bluer_objects/tests/test_storage.py +7 -0
- bluer_objects/tests/test_version.py +5 -0
- bluer_objects/urls.py +3 -0
- bluer_objects-6.3.1.dist-info/METADATA +57 -0
- bluer_objects-6.3.1.dist-info/RECORD +149 -0
- bluer_objects-6.3.1.dist-info/WHEEL +5 -0
- bluer_objects-6.3.1.dist-info/licenses/LICENSE +121 -0
- bluer_objects-6.3.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,130 @@
|
|
|
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.mysql.tags.functions import clone, create, get, search, set_
|
|
8
|
+
from bluer_objects.logger import logger
|
|
9
|
+
|
|
10
|
+
NAME = module.name(__file__, NAME)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
parser = argparse.ArgumentParser(NAME)
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"task",
|
|
16
|
+
type=str,
|
|
17
|
+
default="get",
|
|
18
|
+
help="clone|create|get|search|set",
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"--after",
|
|
22
|
+
type=str,
|
|
23
|
+
default="",
|
|
24
|
+
help="123-4-e",
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--before",
|
|
28
|
+
type=str,
|
|
29
|
+
default="",
|
|
30
|
+
)
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"--count",
|
|
33
|
+
type=int,
|
|
34
|
+
default=-1,
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--offset",
|
|
38
|
+
type=int,
|
|
39
|
+
default=0,
|
|
40
|
+
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--delim",
|
|
43
|
+
type=str,
|
|
44
|
+
default=", ",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"--host",
|
|
48
|
+
default=-1,
|
|
49
|
+
type=int,
|
|
50
|
+
help="0|1|-1",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--item_name",
|
|
54
|
+
default="object",
|
|
55
|
+
type=str,
|
|
56
|
+
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--log",
|
|
59
|
+
default=1,
|
|
60
|
+
type=int,
|
|
61
|
+
help="0|1",
|
|
62
|
+
)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--object",
|
|
65
|
+
type=str,
|
|
66
|
+
default="",
|
|
67
|
+
)
|
|
68
|
+
parser.add_argument(
|
|
69
|
+
"--object_2",
|
|
70
|
+
type=str,
|
|
71
|
+
default="",
|
|
72
|
+
)
|
|
73
|
+
parser.add_argument(
|
|
74
|
+
"--shuffle",
|
|
75
|
+
default=0,
|
|
76
|
+
type=int,
|
|
77
|
+
help="0|1",
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--tag",
|
|
81
|
+
type=str,
|
|
82
|
+
default="",
|
|
83
|
+
)
|
|
84
|
+
parser.add_argument(
|
|
85
|
+
"--tags",
|
|
86
|
+
type=str,
|
|
87
|
+
default="",
|
|
88
|
+
help="tag_1,~tag_2",
|
|
89
|
+
)
|
|
90
|
+
parser.add_argument(
|
|
91
|
+
"--type",
|
|
92
|
+
type=str,
|
|
93
|
+
default="",
|
|
94
|
+
)
|
|
95
|
+
args = parser.parse_args()
|
|
96
|
+
|
|
97
|
+
delim = " " if args.delim == "space" else args.delim
|
|
98
|
+
|
|
99
|
+
success = False
|
|
100
|
+
output = None
|
|
101
|
+
if args.task == "clone":
|
|
102
|
+
success = clone(args.object, args.object_2)
|
|
103
|
+
elif args.task == "create":
|
|
104
|
+
success = create()
|
|
105
|
+
elif args.task == "get":
|
|
106
|
+
output = get(args.object)
|
|
107
|
+
success = True
|
|
108
|
+
elif args.task == "search":
|
|
109
|
+
output = search(
|
|
110
|
+
args.tags,
|
|
111
|
+
after=args.after,
|
|
112
|
+
before=args.before,
|
|
113
|
+
count=args.count,
|
|
114
|
+
host=args.host,
|
|
115
|
+
shuffle=args.shuffle,
|
|
116
|
+
offset=args.offset,
|
|
117
|
+
)
|
|
118
|
+
success = True
|
|
119
|
+
elif args.task == "set":
|
|
120
|
+
success = set_(args.object, args.tags)
|
|
121
|
+
else:
|
|
122
|
+
success = None
|
|
123
|
+
|
|
124
|
+
if success is True and output is not None:
|
|
125
|
+
if args.log:
|
|
126
|
+
logger.info(f"{len(output):,} {args.item_name}(s): {delim.join(output)}")
|
|
127
|
+
else:
|
|
128
|
+
print(delim.join(output))
|
|
129
|
+
|
|
130
|
+
sys_exit(logger, NAME, args.task, success, log=args.log)
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from functools import reduce
|
|
3
|
+
import random
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
from blue_options.options import Options
|
|
7
|
+
|
|
8
|
+
from bluer_objects.mysql.table import Table
|
|
9
|
+
from bluer_objects.logger import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def clone(
|
|
13
|
+
object_1: str,
|
|
14
|
+
object_2: str,
|
|
15
|
+
) -> bool:
|
|
16
|
+
return set_(object_2, get(object_1))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create() -> bool:
|
|
20
|
+
return Table.Create(
|
|
21
|
+
"tags",
|
|
22
|
+
[
|
|
23
|
+
"keyword VARCHAR(256) NOT NULL",
|
|
24
|
+
"tag VARCHAR(4096) NOT NULL",
|
|
25
|
+
"value BIT NOT NULL",
|
|
26
|
+
],
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get(keyword: str) -> List[str]:
|
|
31
|
+
table = Table(name="tags")
|
|
32
|
+
|
|
33
|
+
if not table.connect():
|
|
34
|
+
return []
|
|
35
|
+
|
|
36
|
+
success, output = table.execute(
|
|
37
|
+
"SELECT t.tag,t.value "
|
|
38
|
+
f"FROM {table.name} t "
|
|
39
|
+
"INNER JOIN ( "
|
|
40
|
+
"SELECT tag, MAX(timestamp) AS max_timestamp "
|
|
41
|
+
f"FROM {table.name} "
|
|
42
|
+
f'WHERE keyword="{keyword}" GROUP BY tag '
|
|
43
|
+
") tm "
|
|
44
|
+
"ON t.tag=tm.tag AND t.timestamp=tm.max_timestamp "
|
|
45
|
+
f'WHERE keyword="{keyword}";',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if success:
|
|
49
|
+
success = table.disconnect()
|
|
50
|
+
|
|
51
|
+
if not success:
|
|
52
|
+
return []
|
|
53
|
+
|
|
54
|
+
return sorted([thing[0] for thing in output if thing[1] == b"\x01"])
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def search(
|
|
58
|
+
tags: List[str],
|
|
59
|
+
after: str = "",
|
|
60
|
+
before: str = "",
|
|
61
|
+
count: int = -1,
|
|
62
|
+
host: int = -1, # limit to/exclude/ignore (1/0/-1) hosts.
|
|
63
|
+
return_timestamp: bool = False,
|
|
64
|
+
shuffle: bool = False,
|
|
65
|
+
offset: int = 0,
|
|
66
|
+
) -> List[str]:
|
|
67
|
+
if isinstance(tags, str):
|
|
68
|
+
tags = tags.split(",")
|
|
69
|
+
|
|
70
|
+
included_tags = []
|
|
71
|
+
excluded_tags = []
|
|
72
|
+
for tag in tags:
|
|
73
|
+
if tag:
|
|
74
|
+
if tag[0] in "~-!":
|
|
75
|
+
excluded_tags += [tag[1:]]
|
|
76
|
+
else:
|
|
77
|
+
included_tags += [tag]
|
|
78
|
+
|
|
79
|
+
table = Table(name="tags")
|
|
80
|
+
|
|
81
|
+
table.connect()
|
|
82
|
+
|
|
83
|
+
list_of_keywords = None
|
|
84
|
+
timestamp = {}
|
|
85
|
+
for tag in included_tags:
|
|
86
|
+
success, output = table.execute(
|
|
87
|
+
"SELECT t.keyword,t.value,t.timestamp "
|
|
88
|
+
"FROM abcli.tags t "
|
|
89
|
+
"INNER JOIN ( "
|
|
90
|
+
"SELECT keyword, MAX(timestamp) AS max_timestamp "
|
|
91
|
+
"FROM abcli.tags "
|
|
92
|
+
f'WHERE tag="{tag}" GROUP BY keyword '
|
|
93
|
+
") tm "
|
|
94
|
+
"ON t.keyword=tm.keyword AND t.timestamp=tm.max_timestamp "
|
|
95
|
+
f'WHERE tag="{tag}"; '
|
|
96
|
+
)
|
|
97
|
+
if not success:
|
|
98
|
+
list_of_keywords = []
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
list_of_keywords_ = [thing[0] for thing in output if thing[1] == b"\x01"]
|
|
102
|
+
|
|
103
|
+
if return_timestamp:
|
|
104
|
+
for thing in output:
|
|
105
|
+
if thing[1] == b"\x01":
|
|
106
|
+
timestamp[thing[0]] = thing[2]
|
|
107
|
+
|
|
108
|
+
list_of_keywords = (
|
|
109
|
+
list_of_keywords_
|
|
110
|
+
if list_of_keywords is None
|
|
111
|
+
else [
|
|
112
|
+
keyword for keyword in list_of_keywords if keyword in list_of_keywords_
|
|
113
|
+
]
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
table.disconnect()
|
|
117
|
+
|
|
118
|
+
list_of_keywords = [] if list_of_keywords is None else sorted(list_of_keywords)
|
|
119
|
+
|
|
120
|
+
if after:
|
|
121
|
+
list_of_keywords = [keyword for keyword in list_of_keywords if keyword >= after]
|
|
122
|
+
|
|
123
|
+
if before:
|
|
124
|
+
list_of_keywords = [
|
|
125
|
+
keyword for keyword in list_of_keywords if keyword <= before
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
excluded_keywords = reduce(
|
|
129
|
+
lambda x, y: x + y,
|
|
130
|
+
[
|
|
131
|
+
search(
|
|
132
|
+
tag,
|
|
133
|
+
after=after,
|
|
134
|
+
before=before,
|
|
135
|
+
count=-1,
|
|
136
|
+
host=host,
|
|
137
|
+
)
|
|
138
|
+
for tag in excluded_tags
|
|
139
|
+
],
|
|
140
|
+
[],
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
list_of_keywords = [
|
|
144
|
+
keyword for keyword in list_of_keywords if keyword not in excluded_keywords
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
if shuffle:
|
|
148
|
+
random.shuffle(list_of_keywords)
|
|
149
|
+
else:
|
|
150
|
+
list_of_keywords = list_of_keywords[::-1]
|
|
151
|
+
|
|
152
|
+
p = re.compile("([0-9]{13}|(0|1)[0-9,a-z]{15}|i-[0-9,a-z]{17})")
|
|
153
|
+
if host == 1:
|
|
154
|
+
list_of_keywords = [keyword for keyword in list_of_keywords if p.match(keyword)]
|
|
155
|
+
if host == 0:
|
|
156
|
+
list_of_keywords = [
|
|
157
|
+
keyword for keyword in list_of_keywords if not p.match(keyword)
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
list_of_keywords = list_of_keywords[offset:]
|
|
161
|
+
|
|
162
|
+
list_of_keywords = (
|
|
163
|
+
list_of_keywords[:count]
|
|
164
|
+
if count > 0
|
|
165
|
+
else [] if count != -1 else list_of_keywords
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return (list_of_keywords, timestamp) if return_timestamp else list_of_keywords
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def set_(
|
|
172
|
+
keyword: str,
|
|
173
|
+
tags: List[str],
|
|
174
|
+
) -> bool:
|
|
175
|
+
table = Table(name="tags")
|
|
176
|
+
|
|
177
|
+
if isinstance(tags, list):
|
|
178
|
+
tags = ",".join(tags)
|
|
179
|
+
if isinstance(tags, str):
|
|
180
|
+
tags = Options(tags)
|
|
181
|
+
|
|
182
|
+
if not table.connect():
|
|
183
|
+
return False
|
|
184
|
+
|
|
185
|
+
tags = {tag.strip(): value for tag, value in tags.items()}
|
|
186
|
+
|
|
187
|
+
success = True
|
|
188
|
+
for tag in tags:
|
|
189
|
+
if not table.insert(
|
|
190
|
+
"keyword,tag,value".split(","),
|
|
191
|
+
[keyword, tag, 1 if tags[tag] else 0],
|
|
192
|
+
):
|
|
193
|
+
success = False
|
|
194
|
+
else:
|
|
195
|
+
if tags[tag]:
|
|
196
|
+
logger.info(f"{keyword} += #{tag}.")
|
|
197
|
+
else:
|
|
198
|
+
logger.info(f"{keyword} -= #{tag}.")
|
|
199
|
+
|
|
200
|
+
if not table.disconnect():
|
|
201
|
+
return False
|
|
202
|
+
|
|
203
|
+
return success
|
bluer_objects/objects.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from blue_options import string
|
|
4
|
+
|
|
5
|
+
from bluer_objects import file, path
|
|
6
|
+
from bluer_objects.env import (
|
|
7
|
+
ABCLI_OBJECT_ROOT,
|
|
8
|
+
abcli_object_name,
|
|
9
|
+
ABCLI_S3_OBJECT_PREFIX,
|
|
10
|
+
)
|
|
11
|
+
from bluer_objects.host import shell
|
|
12
|
+
from bluer_objects.logger import logger
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def download(
|
|
16
|
+
object_name: str,
|
|
17
|
+
filename: str = "",
|
|
18
|
+
overwrite: bool = False,
|
|
19
|
+
) -> bool:
|
|
20
|
+
if not ABCLI_S3_OBJECT_PREFIX:
|
|
21
|
+
logger.error("ABCLI_S3_OBJECT_PREFIX is not set.")
|
|
22
|
+
return False
|
|
23
|
+
|
|
24
|
+
if not object_name:
|
|
25
|
+
logger.error("object_name not found.")
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
filename
|
|
30
|
+
and not overwrite
|
|
31
|
+
and file.exists(
|
|
32
|
+
path_of(
|
|
33
|
+
object_name=object_name,
|
|
34
|
+
filename=filename,
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
):
|
|
38
|
+
return True
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
shell(
|
|
42
|
+
"aws s3 cp {}/{}/{} {}".format(
|
|
43
|
+
ABCLI_S3_OBJECT_PREFIX,
|
|
44
|
+
object_name,
|
|
45
|
+
filename,
|
|
46
|
+
object_path(object_name, create=True),
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
if filename
|
|
50
|
+
else shell(
|
|
51
|
+
"aws s3 sync {}/{}/ {}".format(
|
|
52
|
+
ABCLI_S3_OBJECT_PREFIX,
|
|
53
|
+
object_name,
|
|
54
|
+
object_path(object_name, create=True),
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def list_of_files(
|
|
61
|
+
object_name: str,
|
|
62
|
+
cloud: bool = False,
|
|
63
|
+
**kwargs,
|
|
64
|
+
):
|
|
65
|
+
if cloud:
|
|
66
|
+
from bluer_objects.storage import instance as storage
|
|
67
|
+
|
|
68
|
+
return storage.list_of_objects(
|
|
69
|
+
object_name,
|
|
70
|
+
**kwargs,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
return file.list_of(
|
|
74
|
+
os.path.join(
|
|
75
|
+
ABCLI_OBJECT_ROOT,
|
|
76
|
+
object_name,
|
|
77
|
+
"*",
|
|
78
|
+
),
|
|
79
|
+
**kwargs,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def object_path(
|
|
84
|
+
object_name=".",
|
|
85
|
+
create=False,
|
|
86
|
+
):
|
|
87
|
+
output = os.path.join(
|
|
88
|
+
ABCLI_OBJECT_ROOT,
|
|
89
|
+
abcli_object_name if object_name == "." else object_name,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if create:
|
|
93
|
+
os.makedirs(output, exist_ok=True)
|
|
94
|
+
|
|
95
|
+
return output
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def path_of(
|
|
99
|
+
filename,
|
|
100
|
+
object_name=".",
|
|
101
|
+
create=False,
|
|
102
|
+
):
|
|
103
|
+
return os.path.join(
|
|
104
|
+
object_path(object_name, create),
|
|
105
|
+
filename,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def signature(info=None, object_name="."):
|
|
110
|
+
return [
|
|
111
|
+
"{}{}".format(
|
|
112
|
+
abcli_object_name if object_name == "." else object_name,
|
|
113
|
+
"" if info is None else f"/{str(info)}",
|
|
114
|
+
),
|
|
115
|
+
string.pretty_date(include_time=False),
|
|
116
|
+
string.pretty_date(include_date=False, include_zone=True),
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def unique_object(
|
|
121
|
+
prefix: str = "",
|
|
122
|
+
include_time: bool = True,
|
|
123
|
+
):
|
|
124
|
+
object_name = string.pretty_date(
|
|
125
|
+
as_filename=True,
|
|
126
|
+
include_time=include_time,
|
|
127
|
+
unique=True,
|
|
128
|
+
)
|
|
129
|
+
if prefix:
|
|
130
|
+
object_name = f"{prefix}-{object_name}"
|
|
131
|
+
|
|
132
|
+
path.create(object_path(object_name))
|
|
133
|
+
|
|
134
|
+
logger.info(f"📂 {object_name}")
|
|
135
|
+
|
|
136
|
+
return object_name
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def upload(
|
|
140
|
+
object_name: str,
|
|
141
|
+
filename: str = "",
|
|
142
|
+
) -> bool:
|
|
143
|
+
if not ABCLI_S3_OBJECT_PREFIX:
|
|
144
|
+
logger.error("ABCLI_S3_OBJECT_PREFIX is not set.")
|
|
145
|
+
return False
|
|
146
|
+
|
|
147
|
+
if not object_name:
|
|
148
|
+
logger.error("object_name not found.")
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
shell(
|
|
153
|
+
"aws s3 cp {} {}/{}/".format(
|
|
154
|
+
path_of(filename=filename, object_name=object_name),
|
|
155
|
+
ABCLI_S3_OBJECT_PREFIX,
|
|
156
|
+
object_name,
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
if filename
|
|
160
|
+
else shell(
|
|
161
|
+
"aws s3 sync {} {}/{}/".format(
|
|
162
|
+
object_path(object_name, create=True),
|
|
163
|
+
ABCLI_S3_OBJECT_PREFIX,
|
|
164
|
+
object_name,
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
)
|
bluer_objects/path.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any, Union, List
|
|
3
|
+
import pathlib
|
|
4
|
+
import shutil
|
|
5
|
+
|
|
6
|
+
from blueness import module
|
|
7
|
+
from blue_options import string
|
|
8
|
+
from blue_options.logger import crash_report
|
|
9
|
+
|
|
10
|
+
from bluer_objects import NAME
|
|
11
|
+
from bluer_objects.logger import logger
|
|
12
|
+
from bluer_objects.env import abcli_object_path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
NAME = module.name(__file__, NAME)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def absolute(
|
|
19
|
+
path: str,
|
|
20
|
+
reference: Union[None, str] = None,
|
|
21
|
+
):
|
|
22
|
+
if reference is None:
|
|
23
|
+
reference = current()
|
|
24
|
+
assert isinstance(reference, str)
|
|
25
|
+
|
|
26
|
+
path = path.replace("/", os.sep)
|
|
27
|
+
reference = reference.replace("/", os.sep)
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
reference
|
|
31
|
+
if not path
|
|
32
|
+
else (
|
|
33
|
+
path
|
|
34
|
+
if path[0] != "."
|
|
35
|
+
else str(pathlib.Path(os.path.join(reference, path)).resolve())
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def auxiliary(
|
|
41
|
+
nickname: str,
|
|
42
|
+
add_timestamp: bool = True,
|
|
43
|
+
):
|
|
44
|
+
path = os.path.join(
|
|
45
|
+
abcli_object_path,
|
|
46
|
+
"auxiliary",
|
|
47
|
+
"-".join(
|
|
48
|
+
[nickname]
|
|
49
|
+
+ (
|
|
50
|
+
[
|
|
51
|
+
string.pretty_date(
|
|
52
|
+
as_filename=True,
|
|
53
|
+
squeeze=True,
|
|
54
|
+
unique=True,
|
|
55
|
+
)
|
|
56
|
+
]
|
|
57
|
+
if add_timestamp
|
|
58
|
+
else []
|
|
59
|
+
)
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
assert create(path)
|
|
64
|
+
|
|
65
|
+
return path
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def copy(
|
|
69
|
+
source: str,
|
|
70
|
+
destination: str,
|
|
71
|
+
) -> bool:
|
|
72
|
+
if not create(parent(destination)):
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
shutil.copytree(source, destination)
|
|
77
|
+
return True
|
|
78
|
+
except:
|
|
79
|
+
crash_report(f"{NAME}: copy({source},{destination}): failed.")
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def create(
|
|
84
|
+
path: str,
|
|
85
|
+
log: bool = False,
|
|
86
|
+
) -> bool:
|
|
87
|
+
if not path or exists(path):
|
|
88
|
+
return True
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
os.makedirs(path)
|
|
92
|
+
except:
|
|
93
|
+
crash_report(f"{NAME}: create({path}): failed.")
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
if log:
|
|
97
|
+
logger.info(f"{NAME}.create({path})")
|
|
98
|
+
|
|
99
|
+
return True
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def current() -> str:
|
|
103
|
+
return os.getcwd()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def delete(
|
|
107
|
+
path: str,
|
|
108
|
+
) -> bool:
|
|
109
|
+
try:
|
|
110
|
+
# https://docs.python.org/3/library/shutil.html#shutil.rmtree
|
|
111
|
+
shutil.rmtree(path)
|
|
112
|
+
return True
|
|
113
|
+
except:
|
|
114
|
+
crash_report(f"{NAME}: delete({path}): failed.")
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def exists(path: str) -> bool:
|
|
119
|
+
return os.path.exists(path) and os.path.isdir(path)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def list_of(
|
|
123
|
+
path: str,
|
|
124
|
+
recursive: bool = False,
|
|
125
|
+
) -> List[str]:
|
|
126
|
+
if not exists(path):
|
|
127
|
+
return []
|
|
128
|
+
|
|
129
|
+
# http://stackabuse.com/python-list-files-in-a-directory/
|
|
130
|
+
output = []
|
|
131
|
+
try:
|
|
132
|
+
for entry in os.scandir(path):
|
|
133
|
+
if entry.is_file():
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
path_name = os.path.join(path, entry.name)
|
|
137
|
+
|
|
138
|
+
output.append(path_name)
|
|
139
|
+
|
|
140
|
+
if recursive:
|
|
141
|
+
output += list_of(path_name, recursive=recursive)
|
|
142
|
+
except:
|
|
143
|
+
crash_report(f"-{NAME}: list_of({path}): failed.")
|
|
144
|
+
|
|
145
|
+
return output
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def move(
|
|
149
|
+
source: str,
|
|
150
|
+
destination: str,
|
|
151
|
+
) -> bool:
|
|
152
|
+
if not create(parent(destination)):
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
shutil.move(source, destination)
|
|
157
|
+
return True
|
|
158
|
+
except:
|
|
159
|
+
crash_report(f"{NAME}: move({source},{destination}): failed.")
|
|
160
|
+
return False
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def name(path: str) -> str:
|
|
164
|
+
if not path:
|
|
165
|
+
return path
|
|
166
|
+
|
|
167
|
+
if path[-1] == os.sep:
|
|
168
|
+
path = path[:-1]
|
|
169
|
+
|
|
170
|
+
path_components = path.split(os.sep)
|
|
171
|
+
return "" if not path_components else path_components[-1]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def parent(
|
|
175
|
+
path: str,
|
|
176
|
+
depth: int = 1,
|
|
177
|
+
) -> str:
|
|
178
|
+
# Add os.sep at the end of path, if it already does not exist.
|
|
179
|
+
if path:
|
|
180
|
+
if path[-1] != os.sep:
|
|
181
|
+
path = path + os.sep
|
|
182
|
+
|
|
183
|
+
return os.sep.join(path.split(os.sep)[: -depth - 1]) + os.sep
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def relative(
|
|
187
|
+
path: str,
|
|
188
|
+
reference: Union[Any, str] = None,
|
|
189
|
+
):
|
|
190
|
+
# https://stackoverflow.com/a/918174
|
|
191
|
+
return os.path.relpath(
|
|
192
|
+
path,
|
|
193
|
+
current() if reference is None else reference,
|
|
194
|
+
)
|
bluer_objects/sample.env
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# to complete the `rds` section create a database as follows:
|
|
2
|
+
# go to `AWS Management Console` -> `RDS` -> `Create database`.
|
|
3
|
+
# use `Standard Create` -> `MySQL` -> `MySQL 8.0.20` -> `Dev/Test`.
|
|
4
|
+
# set `DB instance identifier` to `abcli`.
|
|
5
|
+
# set `Credentials Settings` -> `Master username` and `Master Password` and update `host`, `username`, and `password` here.
|
|
6
|
+
# set `DB instance size` to `Burstable Classes` and select `db.t3.small`.
|
|
7
|
+
# set `Storage` to `20` and disable `Storage autoscaling`.
|
|
8
|
+
# in `Connectivity` set `Public Access` to `Yes`.
|
|
9
|
+
# in `Additional Configuration` set `initial database name` to `abcli`.
|
|
10
|
+
ABCLI_AWS_RDS_HOST=
|
|
11
|
+
ABCLI_AWS_RDS_PASSWORD=
|
|
12
|
+
|
|
13
|
+
# https://docs.databricks.com/en/mlflow/tracking.html
|
|
14
|
+
# https://docs.databricks.com/en/dev-tools/auth/pat.html#databricks-personal-access-tokens-for-workspace-users
|
|
15
|
+
DATABRICKS_HOST=
|
|
16
|
+
DATABRICKS_TOKEN=
|