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.
Files changed (170) hide show
  1. bluer_objects/.abcli/abcli.sh +6 -0
  2. bluer_objects/.abcli/alias.sh +13 -6
  3. bluer_objects/.abcli/assets/cd.sh +20 -0
  4. bluer_objects/.abcli/assets/mv.sh +34 -0
  5. bluer_objects/.abcli/assets/publish.sh +40 -0
  6. bluer_objects/.abcli/assets.sh +15 -0
  7. bluer_objects/.abcli/create_test_asset.sh +10 -0
  8. bluer_objects/.abcli/download.sh +3 -1
  9. bluer_objects/.abcli/file.sh +15 -4
  10. bluer_objects/.abcli/gif.sh +18 -0
  11. bluer_objects/.abcli/host.sh +23 -7
  12. bluer_objects/.abcli/ls.sh +19 -8
  13. bluer_objects/.abcli/metadata/download.sh +9 -0
  14. bluer_objects/.abcli/metadata/edit.sh +15 -0
  15. bluer_objects/.abcli/metadata/upload.sh +9 -0
  16. bluer_objects/.abcli/mlflow/browse.sh +2 -0
  17. bluer_objects/.abcli/mlflow/deploy.sh +21 -5
  18. bluer_objects/.abcli/mlflow/lock/lock.sh +11 -0
  19. bluer_objects/.abcli/mlflow/lock/unlock.sh +12 -0
  20. bluer_objects/.abcli/mlflow/lock.sh +15 -0
  21. bluer_objects/.abcli/mlflow/tags/search.sh +1 -5
  22. bluer_objects/.abcli/mlflow.sh +0 -2
  23. bluer_objects/.abcli/pdf/convert.sh +92 -0
  24. bluer_objects/.abcli/pdf.sh +15 -0
  25. bluer_objects/.abcli/storage/clear.sh +2 -0
  26. bluer_objects/.abcli/tests/clone.sh +2 -3
  27. bluer_objects/.abcli/tests/create_test_asset.sh +16 -0
  28. bluer_objects/.abcli/tests/file.sh +64 -0
  29. bluer_objects/.abcli/tests/gif.sh +3 -3
  30. bluer_objects/.abcli/tests/help.sh +23 -7
  31. bluer_objects/.abcli/tests/ls.sh +11 -4
  32. bluer_objects/.abcli/tests/metadata.sh +35 -0
  33. bluer_objects/.abcli/tests/mlflow_lock.sh +30 -0
  34. bluer_objects/.abcli/tests/mlflow_tags.sh +1 -1
  35. bluer_objects/.abcli/tests/open.sh +11 -0
  36. bluer_objects/.abcli/tests/open_gif_open.sh +14 -0
  37. bluer_objects/.abcli/tests/pdf.sh +39 -0
  38. bluer_objects/.abcli/tests/storage_clear.sh +11 -0
  39. bluer_objects/.abcli/tests/storage_public_upload.sh +25 -0
  40. bluer_objects/.abcli/tests/storage_status.sh +12 -0
  41. bluer_objects/.abcli/tests/{storage.sh → storage_upload_download.sh} +26 -8
  42. bluer_objects/.abcli/upload.sh +26 -2
  43. bluer_objects/README/__init__.py +7 -22
  44. bluer_objects/README/alias.py +67 -0
  45. bluer_objects/README/build/__init__.py +0 -0
  46. bluer_objects/README/build/aliases.py +23 -0
  47. bluer_objects/README/build/docs.py +23 -0
  48. bluer_objects/README/build/modules.py +9 -0
  49. bluer_objects/README/consts.py +44 -0
  50. bluer_objects/README/functions.py +154 -204
  51. bluer_objects/README/items.py +78 -6
  52. bluer_objects/README/process/__init__.py +0 -0
  53. bluer_objects/README/process/assets.py +36 -0
  54. bluer_objects/README/process/details.py +20 -0
  55. bluer_objects/README/process/envs.py +23 -0
  56. bluer_objects/README/process/help.py +27 -0
  57. bluer_objects/README/process/include.py +40 -0
  58. bluer_objects/README/process/legacy.py +21 -0
  59. bluer_objects/README/process/mermaid.py +20 -0
  60. bluer_objects/README/process/national_internet.py +55 -0
  61. bluer_objects/README/process/objects.py +32 -0
  62. bluer_objects/README/process/signature.py +35 -0
  63. bluer_objects/README/process/title.py +44 -0
  64. bluer_objects/README/process/variables.py +12 -0
  65. bluer_objects/__init__.py +1 -1
  66. bluer_objects/assets/__init__.py +0 -0
  67. bluer_objects/assets/__main__.py +57 -0
  68. bluer_objects/assets/functions.py +62 -0
  69. bluer_objects/config.env +13 -1
  70. bluer_objects/env.py +27 -1
  71. bluer_objects/file/__main__.py +52 -7
  72. bluer_objects/file/functions.py +21 -4
  73. bluer_objects/file/load.py +2 -9
  74. bluer_objects/file/save.py +17 -24
  75. bluer_objects/graphics/__main__.py +7 -0
  76. bluer_objects/graphics/gif.py +11 -7
  77. bluer_objects/graphics/screen.py +9 -8
  78. bluer_objects/help/assets.py +93 -0
  79. bluer_objects/help/create_test_asset.py +22 -0
  80. bluer_objects/help/download.py +17 -3
  81. bluer_objects/help/file.py +59 -0
  82. bluer_objects/help/functions.py +9 -1
  83. bluer_objects/help/gif.py +25 -0
  84. bluer_objects/help/host.py +6 -4
  85. bluer_objects/help/ls.py +26 -3
  86. bluer_objects/help/metadata.py +51 -0
  87. bluer_objects/help/mlflow/__init__.py +23 -2
  88. bluer_objects/help/mlflow/cache.py +2 -4
  89. bluer_objects/help/mlflow/lock.py +52 -0
  90. bluer_objects/help/mlflow/tags.py +34 -23
  91. bluer_objects/help/pdf.py +67 -0
  92. bluer_objects/help/upload.py +10 -3
  93. bluer_objects/host/functions.py +4 -1
  94. bluer_objects/logger/confusion_matrix.py +76 -0
  95. bluer_objects/logger/image.py +110 -0
  96. bluer_objects/logger/stitch.py +107 -0
  97. bluer_objects/markdown.py +8 -6
  98. bluer_objects/metadata/__init__.py +1 -0
  99. bluer_objects/metadata/flatten.py +27 -0
  100. bluer_objects/mlflow/__init__.py +1 -1
  101. bluer_objects/mlflow/__main__.py +49 -31
  102. bluer_objects/mlflow/lock/__init__.py +1 -0
  103. bluer_objects/mlflow/lock/__main__.py +58 -0
  104. bluer_objects/mlflow/lock/functions.py +121 -0
  105. bluer_objects/mlflow/logging.py +53 -41
  106. bluer_objects/mlflow/models.py +7 -0
  107. bluer_objects/mlflow/objects.py +7 -0
  108. bluer_objects/mlflow/runs.py +10 -1
  109. bluer_objects/mlflow/serverless/__init__.py +3 -0
  110. bluer_objects/mlflow/serverless/api.py +88 -0
  111. bluer_objects/mlflow/serverless/read.py +19 -0
  112. bluer_objects/mlflow/serverless/search.py +35 -0
  113. bluer_objects/mlflow/serverless/write.py +42 -0
  114. bluer_objects/mlflow/tags.py +59 -9
  115. bluer_objects/objects.py +3 -1
  116. bluer_objects/pdf/__init__.py +1 -0
  117. bluer_objects/pdf/__main__.py +78 -0
  118. bluer_objects/pdf/convert/__init__.py +0 -0
  119. bluer_objects/pdf/convert/batch.py +54 -0
  120. bluer_objects/pdf/convert/combination.py +32 -0
  121. bluer_objects/pdf/convert/convert.py +110 -0
  122. bluer_objects/pdf/convert/image.py +53 -0
  123. bluer_objects/pdf/convert/md.py +97 -0
  124. bluer_objects/pdf/convert/missing.py +96 -0
  125. bluer_objects/pdf/convert/pdf.py +37 -0
  126. bluer_objects/sample.env +6 -0
  127. bluer_objects/storage/WebDAV.py +11 -7
  128. bluer_objects/storage/WebDAVrequest.py +360 -0
  129. bluer_objects/storage/WebDAVzip.py +26 -29
  130. bluer_objects/storage/__init__.py +28 -1
  131. bluer_objects/storage/__main__.py +40 -6
  132. bluer_objects/storage/base.py +84 -5
  133. bluer_objects/storage/policies.py +7 -0
  134. bluer_objects/storage/s3.py +367 -0
  135. bluer_objects/testing/__main__.py +6 -0
  136. bluer_objects/tests/test_README_consts.py +71 -0
  137. bluer_objects/tests/test_README_items.py +128 -0
  138. bluer_objects/tests/test_alias.py +33 -0
  139. bluer_objects/tests/test_env.py +42 -7
  140. bluer_objects/tests/test_file_download.py +30 -0
  141. bluer_objects/tests/test_file_load_save.py +1 -2
  142. bluer_objects/tests/test_file_load_save_text.py +46 -0
  143. bluer_objects/tests/test_graphics_gif.py +2 -0
  144. bluer_objects/tests/test_log_image_grid.py +29 -0
  145. bluer_objects/tests/test_logger_confusion_matrix.py +18 -0
  146. bluer_objects/tests/test_logger_matrix.py +2 -2
  147. bluer_objects/tests/test_logger_stitch_images.py +47 -0
  148. bluer_objects/tests/test_metadata.py +12 -6
  149. bluer_objects/tests/test_metadata_flatten.py +109 -0
  150. bluer_objects/tests/test_mlflow.py +114 -5
  151. bluer_objects/tests/test_mlflow_lock.py +26 -0
  152. bluer_objects/tests/test_objects.py +2 -0
  153. bluer_objects/tests/test_shell.py +34 -0
  154. bluer_objects/tests/test_storage.py +8 -21
  155. bluer_objects/tests/test_storage_base.py +39 -0
  156. bluer_objects/tests/test_storage_s3.py +67 -0
  157. bluer_objects/tests/test_storage_webdav_request.py +75 -0
  158. bluer_objects/tests/test_storage_webdav_zip.py +42 -0
  159. bluer_objects/tests/test_web_is_accessible.py +11 -0
  160. {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/METADATA +20 -11
  161. bluer_objects-6.464.1.dist-info/RECORD +228 -0
  162. {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/WHEEL +1 -1
  163. bluer_objects/.abcli/storage/download_file.sh +0 -9
  164. bluer_objects/.abcli/storage/exists.sh +0 -8
  165. bluer_objects/.abcli/storage/list.sh +0 -8
  166. bluer_objects/.abcli/storage/rm.sh +0 -11
  167. bluer_objects/.abcli/tests/mlflow_test.sh +0 -7
  168. bluer_objects-6.104.1.dist-info/RECORD +0 -143
  169. {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/licenses/LICENSE +0 -0
  170. {bluer_objects-6.104.1.dist-info → bluer_objects-6.464.1.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,6 @@ from bluer_objects.mlflow.runs import (
24
24
  start_run,
25
25
  )
26
26
  from bluer_objects.mlflow.tags import (
27
- create_filter_string,
28
27
  get_tags,
29
28
  search,
30
29
  set_tags,
@@ -42,7 +41,23 @@ parser.add_argument(
42
41
  "task",
43
42
  type=str,
44
43
  default="",
45
- help="clone_tags|create_filter_string|get_id|get_run_id|get_tags|list_registered_models|log_artifacts|log_run|rm|search|set_tags|start_end_run|test|transition",
44
+ help=" | ".join(
45
+ [
46
+ "clone_tags",
47
+ "get_id",
48
+ "get_run_id",
49
+ "get_tags",
50
+ "list_registered_models",
51
+ "log_artifacts",
52
+ "log_run",
53
+ "rm",
54
+ "search",
55
+ "set_tags",
56
+ "start_end_run",
57
+ "test",
58
+ "transition",
59
+ ]
60
+ ),
46
61
  )
47
62
  parser.add_argument(
48
63
  "--count",
@@ -115,13 +130,13 @@ parser.add_argument(
115
130
  "--log",
116
131
  type=int,
117
132
  default=1,
118
- help="0|1",
133
+ help="0 | 1",
119
134
  )
120
135
  parser.add_argument(
121
- "--explicit_query",
136
+ "--server_style",
122
137
  type=int,
123
138
  default=0,
124
- help="0|1",
139
+ help="0 | 1",
125
140
  )
126
141
  parser.add_argument(
127
142
  "--start_end",
@@ -162,6 +177,12 @@ parser.add_argument(
162
177
  default="",
163
178
  help="",
164
179
  )
180
+ parser.add_argument(
181
+ "--verbose",
182
+ type=int,
183
+ default=0,
184
+ help="0 | 1",
185
+ )
165
186
  args = parser.parse_args()
166
187
 
167
188
  delim = " " if args.delim == "space" else args.delim
@@ -171,9 +192,6 @@ if args.task == "clone_tags":
171
192
  success, tags = get_tags(args.source_objects)
172
193
  if success:
173
194
  success = set_tags(args.destination_object, tags)
174
- elif args.task == "create_filter_string":
175
- success = True
176
- print(create_filter_string(args.tags))
177
195
  elif args.task == "rm":
178
196
  success = reduce(
179
197
  lambda x, y: x and y,
@@ -188,7 +206,10 @@ elif args.task == "rm":
188
206
  True,
189
207
  )
190
208
  elif args.task == "get_tags":
191
- success, tags = get_tags(args.object_name)
209
+ success, tags = get_tags(
210
+ args.object_name,
211
+ verbose=args.verbose == 1,
212
+ )
192
213
  print(tags if not args.tag else tags.get(args.tag, args.default))
193
214
  elif args.task == "get_id":
194
215
  success, id = get_id(args.object_name)
@@ -217,36 +238,33 @@ elif args.task == "log_artifacts":
217
238
  elif args.task == "log_run":
218
239
  success = log_run(args.object_name)
219
240
  elif args.task == "search":
220
- success = True
221
-
222
- filter_string = (
223
- create_filter_string(args.tags)
224
- if args.explicit_query == 0
225
- else "" if args.filter_string == "-" else args.filter_string
241
+ success, list_of_objects = search(
242
+ filter_string=args.tags,
243
+ server_style=args.server_style == 1,
226
244
  )
227
245
 
228
- list_of_objects = search(filter_string)
229
-
230
- list_of_objects = list_of_objects[args.offset :]
246
+ if success:
247
+ list_of_objects = list_of_objects[args.offset :]
231
248
 
232
- if args.count != -1:
233
- list_of_objects = list_of_objects[: args.count]
249
+ if args.count != -1:
250
+ list_of_objects = list_of_objects[: args.count]
234
251
 
235
- if args.log:
236
- logger.info(
237
- "{:,} {}.".format(
238
- len(list_of_objects),
239
- args.item_name_plural,
240
- ),
241
- )
242
- for index, object_name in enumerate(list_of_objects):
243
- logger.info(f"#{index+1: 4d} - {object_name}")
244
- else:
245
- print(delim.join(list_of_objects))
252
+ if args.log:
253
+ logger.info(
254
+ "{:,} {}.".format(
255
+ len(list_of_objects),
256
+ args.item_name_plural,
257
+ ),
258
+ )
259
+ for index, object_name in enumerate(list_of_objects):
260
+ logger.info(f"#{index+1: 4d} - {object_name}")
261
+ else:
262
+ print(delim.join(list_of_objects))
246
263
  elif args.task == "set_tags":
247
264
  success = set_tags(
248
265
  args.object_name,
249
266
  args.tags,
267
+ verbose=args.verbose == 1,
250
268
  )
251
269
  elif args.task == "transition":
252
270
  success = transition(
@@ -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 time.time() - start_time > timeout > 0:
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
+ )
@@ -6,7 +6,7 @@ import mlflow
6
6
  from blueness import module
7
7
  from bluer_options.logger import crash_report
8
8
 
9
- from bluer_objects import file, objects, NAME
9
+ from bluer_objects import file, objects, NAME, env
10
10
  from bluer_objects.mlflow.runs import start_run, end_run
11
11
  from bluer_objects.logger import logger
12
12
 
@@ -17,65 +17,77 @@ def log_artifacts(
17
17
  object_name: str,
18
18
  model_name: str = "",
19
19
  ) -> bool:
20
+ if env.MLFLOW_IS_SERVERLESS:
21
+ return True
22
+
20
23
  if not start_run(object_name):
21
24
  return False
22
25
 
23
26
  object_path = objects.object_path(object_name, create=True)
24
27
 
25
- try:
26
- mlflow.log_artifacts(object_path)
28
+ if env.MLFLOW_LOG_ARTIFACTS:
29
+ try:
30
+ mlflow.log_artifacts(object_path)
27
31
 
28
- logger.info("⬆️ {}".format(object_name))
32
+ logger.info("⬆️ {}".format(object_name))
29
33
 
30
- # https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.register_model
31
- # https://stackoverflow.com/a/71447758/17619982
32
- if model_name:
33
- mv = mlflow.register_model(
34
- "runs:/{}".format(mlflow.active_run().info.run_id),
35
- model_name,
36
- await_registration_for=0,
37
- )
34
+ # https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.register_model
35
+ # https://stackoverflow.com/a/71447758/17619982
36
+ if model_name:
37
+ mv = mlflow.register_model(
38
+ "runs:/{}".format(mlflow.active_run().info.run_id),
39
+ model_name,
40
+ await_registration_for=0,
41
+ )
38
42
 
39
- logger.info("*️⃣ {} -> {}.{}".format(object_name, mv.name, mv.version))
43
+ logger.info("*️⃣ {} -> {}.{}".format(object_name, mv.name, mv.version))
40
44
 
41
- except:
42
- crash_report(f"{NAME}.log_artifacts({object_name})")
43
- return False
45
+ except:
46
+ crash_report(f"{NAME}.log_artifacts({object_name})")
47
+ return False
48
+ else:
49
+ logger.info("skipped log artifacts.")
44
50
 
45
51
  return end_run(object_name)
46
52
 
47
53
 
48
54
  def log_run(object_name: str) -> bool:
55
+ if env.MLFLOW_IS_SERVERLESS:
56
+ return True
57
+
49
58
  if not start_run(object_name):
50
59
  return False
51
60
 
52
61
  object_path = objects.object_path(object_name, create=True)
53
62
 
54
- counts: Dict[str, int] = {}
55
- skipped_count = 0
56
- for extension in "dot,gif,jpeg,jpg,json,png,sh,xml,yaml".split(","):
57
- for filename in glob.glob(
58
- os.path.join(object_path, f"*.{extension}"),
59
- ):
60
- filename_name = file.name(filename)
61
-
62
- counts[len(filename_name)] = counts.get(len(filename_name), 0) + 1
63
-
64
- if any(
65
- [
66
- file.size(filename) > 10 * 1024 * 1024,
67
- filename_name.startswith("thumbnail"),
68
- counts[len(filename_name)] > 20,
69
- ]
63
+ if env.MLFLOW_LOG_ARTIFACTS:
64
+ counts: Dict[str, int] = {}
65
+ skipped_count = 0
66
+ for extension in "dot,gif,jpeg,jpg,json,png,sh,xml,yaml".split(","):
67
+ for filename in glob.glob(
68
+ os.path.join(object_path, f"*.{extension}"),
70
69
  ):
71
- logger.info(f"skipping {filename}")
72
- skipped_count += 1
73
- continue
74
-
75
- mlflow.log_artifact(filename)
76
- logger.info(f"⬆️ {filename}")
77
-
78
- if skipped_count:
79
- logger.info(f"skipped {skipped_count:,} file(s).")
70
+ filename_name = file.name(filename)
71
+
72
+ counts[len(filename_name)] = counts.get(len(filename_name), 0) + 1
73
+
74
+ if any(
75
+ [
76
+ file.size(filename) > 10 * 1024 * 1024,
77
+ filename_name.startswith("thumbnail"),
78
+ counts[len(filename_name)] > 20,
79
+ ]
80
+ ):
81
+ logger.info(f"skipping {filename}")
82
+ skipped_count += 1
83
+ continue
84
+
85
+ mlflow.log_artifact(filename)
86
+ logger.info(f"⬆️ {filename}")
87
+
88
+ if skipped_count:
89
+ logger.info(f"skipped {skipped_count:,} file(s).")
90
+ else:
91
+ logger.info("skipped log artifacts.")
80
92
 
81
93
  return end_run(object_name)
@@ -5,6 +5,7 @@ from blueness import module
5
5
  from bluer_options.logger import crash_report
6
6
 
7
7
  from bluer_objects import NAME
8
+ from bluer_objects import env
8
9
  from bluer_objects.logger import logger
9
10
 
10
11
  NAME = module.name(__file__, NAME)
@@ -14,6 +15,9 @@ def list_registered_models() -> Tuple[
14
15
  bool,
15
16
  List[str],
16
17
  ]:
18
+ if env.MLFLOW_IS_SERVERLESS:
19
+ return True, []
20
+
17
21
  try:
18
22
  client = MlflowClient()
19
23
  return True, [dict(rm)["name"] for rm in client.search_registered_models()]
@@ -29,6 +33,9 @@ def transition(
29
33
  stage_name: str,
30
34
  description: str,
31
35
  ) -> bool:
36
+ if env.MLFLOW_IS_SERVERLESS:
37
+ return True
38
+
32
39
  logger.info(
33
40
  '{}.transition: {}(#{}) -> {} - "{}")'.format(
34
41
  NAME,
@@ -6,6 +6,7 @@ from blueness import module
6
6
  from bluer_options.logger import crash_report
7
7
 
8
8
  from bluer_objects import NAME
9
+ from bluer_objects import env
9
10
  from bluer_objects.env import ABCLI_MLFLOW_EXPERIMENT_PREFIX
10
11
  from bluer_objects.logger import logger
11
12
 
@@ -16,6 +17,9 @@ def get_id(
16
17
  object_name: str,
17
18
  create: bool = False,
18
19
  ) -> Tuple[bool, str]:
20
+ if env.MLFLOW_IS_SERVERLESS:
21
+ return True, "serverless-id"
22
+
19
23
  experiment_name = to_experiment_name(object_name)
20
24
 
21
25
  try:
@@ -38,6 +42,9 @@ def rm(
38
42
  object_name: str,
39
43
  is_id: bool = False,
40
44
  ) -> bool:
45
+ if env.MLFLOW_IS_SERVERLESS:
46
+ return True
47
+
41
48
  if is_id:
42
49
  experiment_id = object_name
43
50
  else:
@@ -5,10 +5,10 @@ from mlflow.tracking import MlflowClient
5
5
  from mlflow.entities import ViewType
6
6
 
7
7
  from blueness import module
8
- from bluer_options import string
9
8
  from bluer_options.logger import crash_report
10
9
 
11
10
  from bluer_objects import NAME
11
+ from bluer_objects import env
12
12
  from bluer_objects.mlflow.objects import get_id
13
13
  from bluer_objects.mlflow.tags import get_tags
14
14
  from bluer_objects.logger import logger
@@ -19,6 +19,9 @@ NAME = module.name(__file__, NAME)
19
19
  def end_run(
20
20
  object_name: str,
21
21
  ) -> bool:
22
+ if env.MLFLOW_IS_SERVERLESS:
23
+ return True
24
+
22
25
  try:
23
26
  mlflow.end_run()
24
27
  logger.info("⏹️ {}".format(object_name))
@@ -36,6 +39,9 @@ def get_run_id(
36
39
  create: bool = False,
37
40
  is_id: bool = False,
38
41
  ) -> Tuple[bool, List[str]]:
42
+ if env.MLFLOW_IS_SERVERLESS:
43
+ return True, []
44
+
39
45
  if is_id:
40
46
  experiment_id = object_name
41
47
  else:
@@ -62,6 +68,9 @@ def get_run_id(
62
68
  def start_run(
63
69
  object_name: str,
64
70
  ) -> bool:
71
+ if env.MLFLOW_IS_SERVERLESS:
72
+ return True
73
+
65
74
  success, experiment_id = get_id(object_name, create=True)
66
75
  if not success:
67
76
  return False
@@ -0,0 +1,3 @@
1
+ from bluer_objects.mlflow.serverless.read import get_tags
2
+ from bluer_objects.mlflow.serverless.search import search
3
+ from bluer_objects.mlflow.serverless.write import set_tags
@@ -0,0 +1,88 @@
1
+ from typing import Dict, Tuple
2
+
3
+ from blueness import module
4
+
5
+ from bluer_objects import NAME
6
+ from bluer_objects import file
7
+ from bluer_objects import objects
8
+ from bluer_objects import storage
9
+ from bluer_objects.logger import logger
10
+
11
+ NAME = module.name(__file__, NAME)
12
+
13
+
14
+ def write(
15
+ object_name: str,
16
+ filename: str,
17
+ data: Dict,
18
+ log: bool = False,
19
+ ) -> bool:
20
+ if log:
21
+ logger.info(f"{NAME}.update({object_name}/{filename})")
22
+
23
+ if not storage.download(
24
+ object_name=object_name,
25
+ filename=filename,
26
+ log=log,
27
+ ):
28
+ return False
29
+
30
+ full_filename = objects.path_of(
31
+ object_name=object_name,
32
+ filename=filename,
33
+ )
34
+
35
+ _, current_data = file.load_yaml(
36
+ full_filename,
37
+ ignore_error=True,
38
+ default={},
39
+ )
40
+ if not isinstance(current_data, dict):
41
+ logger.error(
42
+ "dict expected, {} received".format(
43
+ current_data.__class__.__name__,
44
+ )
45
+ )
46
+ return False
47
+
48
+ current_data.update(data)
49
+
50
+ if not file.save_yaml(
51
+ full_filename,
52
+ current_data,
53
+ log=log,
54
+ ):
55
+ return False
56
+
57
+ if not storage.upload(
58
+ object_name=object_name,
59
+ filename=filename,
60
+ log=log,
61
+ ):
62
+ return False
63
+
64
+ return True
65
+
66
+
67
+ def read(
68
+ object_name: str,
69
+ filename: str,
70
+ verbose: bool = False,
71
+ ) -> Tuple[bool, Dict]:
72
+ if not storage.download(
73
+ object_name=object_name,
74
+ filename=filename,
75
+ log=verbose,
76
+ ):
77
+ return True, {}
78
+
79
+ _, data = file.load_yaml(
80
+ objects.path_of(
81
+ object_name=object_name,
82
+ filename=filename,
83
+ ),
84
+ ignore_error=True,
85
+ default={},
86
+ )
87
+
88
+ return True, data
@@ -0,0 +1,19 @@
1
+ from typing import Tuple, Dict
2
+
3
+ from blueness import module
4
+
5
+ from bluer_objects import NAME
6
+ from bluer_objects.mlflow.serverless import api
7
+
8
+ NAME = module.name(__file__, NAME)
9
+
10
+
11
+ def get_tags(
12
+ object_name: str,
13
+ verbose: bool = False,
14
+ ) -> Tuple[bool, Dict[str, str]]:
15
+ return api.read(
16
+ object_name="_serverless_objects",
17
+ filename=f"{object_name}.yaml",
18
+ verbose=verbose,
19
+ )
@@ -0,0 +1,35 @@
1
+ from typing import List, Tuple, Union
2
+
3
+ from bluer_options.options import Options
4
+
5
+ from bluer_objects.mlflow.serverless import api
6
+ from bluer_objects.logger import logger
7
+
8
+
9
+ def search(
10
+ filter_string: Union[str, dict],
11
+ log: bool = False,
12
+ ) -> Tuple[bool, List[str]]:
13
+ query = Options(filter_string)
14
+
15
+ output: Union[List[str], None] = None
16
+ for key, value in query.items():
17
+ success, dict_of_objects = api.read(
18
+ object_name="_serverless_keys",
19
+ filename=f"{key}.yaml",
20
+ verbose=log,
21
+ )
22
+ if not success:
23
+ return False, []
24
+
25
+ output = [
26
+ object_name
27
+ for object_name in (dict_of_objects if output is None else output)
28
+ if dict_of_objects.get(
29
+ object_name,
30
+ False if isinstance(value, bool) else None,
31
+ )
32
+ == value
33
+ ]
34
+
35
+ return True, [] if output is None else output