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
@@ -9,8 +9,7 @@ def help_read(
9
9
  ) -> str:
10
10
  return show_usage(
11
11
  [
12
- "@mlflow",
13
- "cache",
12
+ "@cache",
14
13
  "read",
15
14
  "<keyword>",
16
15
  ],
@@ -25,8 +24,7 @@ def help_write(
25
24
  ) -> str:
26
25
  return show_usage(
27
26
  [
28
- "@mlflow",
29
- "cache",
27
+ "@cache",
30
28
  "write",
31
29
  "<keyword>",
32
30
  "<value>",
@@ -0,0 +1,52 @@
1
+ from typing import List
2
+
3
+ from bluer_options.terminal import show_usage, xtra
4
+
5
+
6
+ def help_lock(
7
+ tokens: List[str],
8
+ mono: bool,
9
+ ) -> str:
10
+ args = [
11
+ "[--lock <lock-name>]",
12
+ "[--timeout <10>]",
13
+ "[--verbose 0]",
14
+ ]
15
+
16
+ return show_usage(
17
+ [
18
+ "@lock",
19
+ "lock",
20
+ "[.|<object-name>]",
21
+ ]
22
+ + args,
23
+ "lock <object-name>.",
24
+ mono=mono,
25
+ )
26
+
27
+
28
+ def help_unlock(
29
+ tokens: List[str],
30
+ mono: bool,
31
+ ) -> str:
32
+ args = [
33
+ "[--lock <lock-name>]",
34
+ "[--verbose 0]",
35
+ ]
36
+
37
+ return show_usage(
38
+ [
39
+ "@lock",
40
+ "unlock",
41
+ "[.|<object-name>]",
42
+ ]
43
+ + args,
44
+ "unlock <object-name>.",
45
+ mono=mono,
46
+ )
47
+
48
+
49
+ help_functions = {
50
+ "lock": help_lock,
51
+ "unlock": help_unlock,
52
+ }
@@ -1,6 +1,8 @@
1
1
  from typing import List
2
2
 
3
- from bluer_options.terminal import show_usage, xtra
3
+ from bluer_options.terminal import show_usage
4
+
5
+ from bluer_objects import env
4
6
 
5
7
  search_args = [
6
8
  "[--count <-1>]",
@@ -16,8 +18,7 @@ def help_clone(
16
18
  ) -> str:
17
19
  return show_usage(
18
20
  [
19
- "@mlflow",
20
- "tags",
21
+ "@tags",
21
22
  "clone",
22
23
  "[..|<object-1>]",
23
24
  "[.|<object-2>]",
@@ -35,8 +36,7 @@ def help_get(
35
36
 
36
37
  return show_usage(
37
38
  [
38
- "@mlflow",
39
- "tags",
39
+ "@tags",
40
40
  "get",
41
41
  "[.|<object-name>]",
42
42
  ]
@@ -50,40 +50,47 @@ def help_search(
50
50
  tokens: List[str],
51
51
  mono: bool,
52
52
  ) -> str:
53
- options = "explicit"
53
+ options = "<keyword-1>=<value-1>,<keyword-2>,~<keyword-3>"
54
54
 
55
55
  usage_1 = show_usage(
56
56
  [
57
- "@mlflow",
58
- "tags",
57
+ "@tags",
59
58
  "search",
60
59
  f"[{options}]",
61
60
  ]
62
- + search_args
63
- + ["[--filter_string <filter-string>]"],
64
- "search mlflow for <filter-string>",
65
- {
66
- "<finter-string>: https://www.mlflow.org/docs/latest/search-experiments.html": ""
67
- },
61
+ + search_args,
62
+ "search mlflow.",
68
63
  mono=mono,
69
64
  )
70
65
 
66
+ if env.MLFLOW_IS_SERVERLESS:
67
+ return usage_1
68
+
71
69
  # ---
72
70
 
73
- options = "<keyword-1>=<value-1>,<keyword-2>,~<keyword-3>"
71
+ args = sorted(
72
+ [
73
+ "[--server_style 1]",
74
+ "[--filter_string <filter-string>]",
75
+ ]
76
+ + search_args
77
+ )
74
78
 
75
79
  usage_2 = show_usage(
76
80
  [
77
- "@mlflow",
78
- "tags",
81
+ "@tags",
79
82
  "search",
80
- f"[{options}]",
81
83
  ]
82
- + search_args,
83
- "search mlflow.",
84
+ + args,
85
+ "search mlflow server for <filter-string>.",
86
+ {
87
+ "<filter-string>: https://www.mlflow.org/docs/latest/search-experiments.html": ""
88
+ },
84
89
  mono=mono,
85
90
  )
86
91
 
92
+ # ---
93
+
87
94
  return "\n".join(
88
95
  [
89
96
  usage_1,
@@ -98,14 +105,18 @@ def help_set(
98
105
  ) -> str:
99
106
  options = "<keyword-1>=<value>,<keyword-2>,~<keyword-3>"
100
107
 
108
+ args = [
109
+ "[--verbose 1]",
110
+ ]
111
+
101
112
  return show_usage(
102
113
  [
103
- "@mlflow",
104
- "tags",
114
+ "@tags",
105
115
  "set",
106
116
  "[.|<object-name>]",
107
117
  f"[{options}]",
108
- ],
118
+ ]
119
+ + args,
109
120
  "set tags in mlflow.",
110
121
  mono=mono,
111
122
  )
@@ -0,0 +1,67 @@
1
+ from typing import List
2
+
3
+ from bluer_options.terminal import show_usage, xtra
4
+
5
+
6
+ def help_convert(
7
+ tokens: List[str],
8
+ mono: bool,
9
+ ) -> str:
10
+ options = "".join(
11
+ [
12
+ "combine",
13
+ xtra(",~compress,filename=<release.pdf>,install,", mono=mono),
14
+ "upload",
15
+ ]
16
+ )
17
+
18
+ args = [
19
+ "[--count <2>]",
20
+ ]
21
+
22
+ # ---
23
+
24
+ usage_1 = show_usage(
25
+ [
26
+ "@pdf",
27
+ "convert",
28
+ "[{}]".format(f"inline,{options}"),
29
+ "<module-name>",
30
+ "<.,this,this/that.md,this/that.jpg,this/that.pdf>",
31
+ "[-|<object-name>]",
32
+ ]
33
+ + args,
34
+ "md -> pdf.",
35
+ mono=mono,
36
+ )
37
+
38
+ # ---
39
+
40
+ usage_2 = show_usage(
41
+ [
42
+ "@pdf",
43
+ "convert",
44
+ f"[{options}]",
45
+ "[.|<object-name>]",
46
+ ]
47
+ + args
48
+ + [
49
+ "[--list_missing 0]",
50
+ ],
51
+ "md -> pdf.",
52
+ mono=mono,
53
+ )
54
+
55
+ # ---
56
+
57
+ return "\n".join(
58
+ [
59
+ usage_1,
60
+ usage_2,
61
+ ]
62
+ )
63
+
64
+
65
+ help_functions = {
66
+ "convert": help_convert,
67
+ }
@@ -3,16 +3,23 @@ from typing import List
3
3
  from bluer_options.terminal import show_usage, xtra
4
4
 
5
5
 
6
+ def options(mono: bool) -> str:
7
+ return "".join(
8
+ [
9
+ "filename=<filename>",
10
+ xtra(",public,zip", mono=mono),
11
+ ]
12
+ )
13
+
14
+
6
15
  def help_upload(
7
16
  tokens: List[str],
8
17
  mono: bool,
9
18
  ) -> str:
10
- options = "filename=<filename>"
11
-
12
19
  return show_usage(
13
20
  [
14
21
  "@upload",
15
- f"[{options}]",
22
+ f"[{options(mono=mono)}]",
16
23
  "[.|<object-name>]",
17
24
  ],
18
25
  "upload <object-name>.",
@@ -11,7 +11,7 @@ NAME = module.name(__file__, NAME)
11
11
 
12
12
 
13
13
  def shell(
14
- command: str,
14
+ command: Union[str, List[str]],
15
15
  clean_after: bool = False,
16
16
  return_output: bool = False,
17
17
  work_dir: str = ".",
@@ -20,6 +20,9 @@ def shell(
20
20
  bool,
21
21
  Tuple[bool, List[str]],
22
22
  ]:
23
+ if isinstance(command, list):
24
+ command = " ".join(command)
25
+
23
26
  if log:
24
27
  logger.info(f"{NAME}.shell({command})")
25
28
 
@@ -0,0 +1,76 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ from typing import List
4
+
5
+ from bluer_objects.graphics.signature import justify_text
6
+ from bluer_objects import file
7
+
8
+
9
+ def log_confusion_matrix(
10
+ confusion_matrix: np.ndarray,
11
+ filename: str,
12
+ header: List[str] = [],
13
+ footer: List[str] = [],
14
+ x_classes: List[str] = [],
15
+ y_classes: List[str] = [],
16
+ x_name: str = "prediction",
17
+ y_name: str = "label",
18
+ line_width: int = 80,
19
+ log: bool = True,
20
+ figsize: tuple = (10, 10),
21
+ ) -> bool:
22
+ fig, ax = plt.subplots(figsize=figsize)
23
+ cax = ax.imshow(
24
+ confusion_matrix,
25
+ interpolation="nearest",
26
+ cmap=plt.cm.Blues,
27
+ )
28
+ fig.colorbar(cax)
29
+ ax.set_title(
30
+ justify_text(
31
+ " | ".join(header),
32
+ line_width=line_width,
33
+ return_str=True,
34
+ )
35
+ )
36
+ ax.set_xlabel(
37
+ justify_text(
38
+ " | ".join([x_name] + footer),
39
+ line_width=line_width,
40
+ return_str=True,
41
+ )
42
+ )
43
+ ax.set_ylabel(y_name)
44
+
45
+ if not x_classes:
46
+ x_classes = [f"class #{index}" for index in range(confusion_matrix.shape[1])]
47
+ if not y_classes:
48
+ y_classes = [f"class #{index}" for index in range(confusion_matrix.shape[0])]
49
+
50
+ ax.set_xticks(np.arange(confusion_matrix.shape[1]))
51
+ ax.set_yticks(np.arange(confusion_matrix.shape[0]))
52
+ ax.set_xticklabels(
53
+ x_classes,
54
+ rotation=45,
55
+ ha="right",
56
+ )
57
+ ax.set_yticklabels(y_classes)
58
+
59
+ threshold = confusion_matrix.max() / 2.0
60
+ for i in range(confusion_matrix.shape[0]):
61
+ for j in range(confusion_matrix.shape[1]):
62
+ ax.text(
63
+ j,
64
+ i,
65
+ f"{100*confusion_matrix[i, j]:.1f}%",
66
+ ha="center",
67
+ va="center",
68
+ color="white" if confusion_matrix[i, j] > threshold else "black",
69
+ )
70
+
71
+ plt.tight_layout()
72
+
73
+ return file.save_fig(
74
+ filename,
75
+ log=log,
76
+ )
@@ -0,0 +1,110 @@
1
+ import matplotlib.pyplot as plt
2
+ from typing import Dict, Any, Union, List
3
+ import pandas as pd
4
+ import random
5
+ import os
6
+
7
+ from bluer_options import string
8
+
9
+ from bluer_objects import file, objects, path
10
+ from bluer_objects.graphics.signature import sign_filename
11
+
12
+ LOG_IMAGE_GRID_COLS = 5
13
+ LOG_IMAGE_GRID_ROWS = 3
14
+
15
+
16
+ def log_image_grid(
17
+ items: Union[
18
+ List[Dict[str, Any]],
19
+ pd.DataFrame,
20
+ ],
21
+ filename: str,
22
+ rows: int = LOG_IMAGE_GRID_ROWS,
23
+ cols: int = LOG_IMAGE_GRID_COLS,
24
+ log: bool = True,
25
+ verbose: bool = False,
26
+ scale: int = 2,
27
+ shuffle: bool = False,
28
+ header: List[str] = [],
29
+ footer: List[str] = [],
30
+ relative_path: bool = False,
31
+ ) -> bool:
32
+ if isinstance(items, pd.DataFrame):
33
+ items = items.to_dict("records")
34
+
35
+ while len(items) < rows * cols:
36
+ items += [{"pass": True}]
37
+ if shuffle:
38
+ random.shuffle(items)
39
+
40
+ items = items[: rows * cols]
41
+
42
+ if relative_path:
43
+ root_path = file.path(filename)
44
+ for item in items:
45
+ if item.get("filename", ""):
46
+ item["filename"] = os.path.join(
47
+ root_path,
48
+ item["filename"],
49
+ )
50
+
51
+ _, axes = plt.subplots(
52
+ rows,
53
+ cols,
54
+ figsize=(
55
+ scale * cols,
56
+ scale * rows,
57
+ ),
58
+ )
59
+ axes = axes.flatten()
60
+
61
+ image_shape = ""
62
+ for i, item in enumerate(items):
63
+ if item.get("pass", False):
64
+ axes[i].axis("off")
65
+ continue
66
+
67
+ if item.get("filename", ""):
68
+ success, item["image"] = file.load_image(
69
+ item.get("filename", ""),
70
+ log=verbose,
71
+ )
72
+ if not success:
73
+ return False
74
+
75
+ ax = axes[i]
76
+ image = item["image"]
77
+ image_shape = string.pretty_shape_of_matrix(image)
78
+ ax.imshow(
79
+ image,
80
+ cmap="gray" if image.ndim == 2 else None,
81
+ )
82
+ ax.set_title(
83
+ item.get("title", f"#{i}"),
84
+ color=item.get("color", "black"),
85
+ fontsize=10,
86
+ )
87
+ ax.axis("off")
88
+
89
+ plt.tight_layout()
90
+
91
+ if not file.save_fig(
92
+ filename,
93
+ log=verbose,
94
+ ):
95
+ return False
96
+
97
+ return sign_filename(
98
+ filename,
99
+ [
100
+ " | ".join(
101
+ objects.signature(
102
+ info=file.name_and_extension(filename),
103
+ object_name=path.name(file.path(filename)),
104
+ )
105
+ + [image_shape]
106
+ + header
107
+ )
108
+ ],
109
+ [" | ".join(footer)],
110
+ )
@@ -0,0 +1,107 @@
1
+ from typing import List
2
+ import numpy as np
3
+
4
+ from blueness import module
5
+ from bluer_options import string
6
+
7
+ from bluer_objects import NAME
8
+ from bluer_objects.logger import logger
9
+
10
+ NAME = module.name(__file__, NAME)
11
+
12
+
13
+ def stitch_images(
14
+ list_of_images: List[np.ndarray],
15
+ cols: int = -1,
16
+ rows: int = -1,
17
+ log: bool = False,
18
+ ) -> np.ndarray:
19
+ if not list_of_images:
20
+ return np.zeros((1, 1, 3), dtype=np.uint8)
21
+
22
+ list_of_images = list_of_images.copy()
23
+
24
+ if rows == -1:
25
+ rows = int(np.floor(np.sqrt(len(list_of_images))))
26
+ cols = -1
27
+
28
+ if cols == -1:
29
+ cols = int(np.ceil(len(list_of_images) / rows))
30
+
31
+ if log:
32
+ logger.info(
33
+ "{}.stitch_images[{}x{}]({}): {}".format(
34
+ NAME,
35
+ rows,
36
+ cols,
37
+ len(list_of_images),
38
+ ", ".join(
39
+ [string.pretty_shape_of_matrix(image) for image in list_of_images]
40
+ ),
41
+ )
42
+ )
43
+
44
+ for image in list_of_images:
45
+ if len(image.shape) == 2:
46
+ image = np.stack([image, image, image], axis=2)
47
+
48
+ if rows == 1:
49
+ output = np.zeros(
50
+ (
51
+ max([image.shape[0] for image in list_of_images]),
52
+ sum([image.shape[1] for image in list_of_images]),
53
+ 3,
54
+ ),
55
+ dtype=np.uint8,
56
+ )
57
+ x: int = 0
58
+ for image in list_of_images:
59
+ x_new = x + image.shape[1]
60
+
61
+ output[
62
+ : image.shape[0],
63
+ x:x_new,
64
+ :,
65
+ ] = image
66
+
67
+ x = x_new
68
+
69
+ return output
70
+
71
+ if cols == 1:
72
+ output = np.zeros(
73
+ (
74
+ sum([image.shape[0] for image in list_of_images]),
75
+ max([image.shape[1] for image in list_of_images]),
76
+ 3,
77
+ ),
78
+ dtype=np.uint8,
79
+ )
80
+ y: int = 0
81
+ for image in list_of_images:
82
+ y_new = y + image.shape[0]
83
+
84
+ output[
85
+ y:y_new,
86
+ : image.shape[1],
87
+ :,
88
+ ] = image
89
+
90
+ y = y_new
91
+
92
+ return output
93
+
94
+ return stitch_images(
95
+ list_of_images=[
96
+ stitch_images(
97
+ list_of_images[row * cols : (row + 1) * cols],
98
+ cols=cols,
99
+ rows=1,
100
+ log=log,
101
+ )
102
+ for row in range(rows)
103
+ ],
104
+ cols=1,
105
+ rows=rows,
106
+ log=log,
107
+ )
bluer_objects/markdown.py CHANGED
@@ -12,6 +12,7 @@ NAME = module.name(__file__, NAME)
12
12
  def generate_table(
13
13
  items: List[str],
14
14
  cols: int = 3,
15
+ log: bool = True,
15
16
  ) -> List[str]:
16
17
  if not items:
17
18
  return []
@@ -22,13 +23,14 @@ def generate_table(
22
23
 
23
24
  row_count = int(math.ceil(len(items) / cols))
24
25
 
25
- logger.info(
26
- "{}.generate_table(): {} item(s), {} row(s)".format(
27
- NAME,
28
- len(items),
29
- row_count,
26
+ if log:
27
+ logger.info(
28
+ "{}.generate_table(): {} item(s), {} row(s)".format(
29
+ NAME,
30
+ len(items),
31
+ row_count,
32
+ )
30
33
  )
31
- )
32
34
 
33
35
  return [
34
36
  "| {} |".format(" | ".join(cols * [" "])),
@@ -5,4 +5,5 @@ from bluer_objects.metadata.get import (
5
5
  get_from_object,
6
6
  get_from_path,
7
7
  )
8
+ from bluer_objects.metadata.flatten import flatten
8
9
  from bluer_objects.metadata.post import post, post_to_file, post_to_object, post_to_path
@@ -0,0 +1,27 @@
1
+ from typing import Any
2
+ import numpy as np
3
+
4
+
5
+ def flatten(obj: Any) -> Any:
6
+ if isinstance(obj, dict):
7
+ return {k: flatten(v) for k, v in obj.items()}
8
+
9
+ if isinstance(obj, list):
10
+ return [flatten(x) for x in obj]
11
+
12
+ if isinstance(obj, tuple):
13
+ return tuple(flatten(x) for x in obj)
14
+
15
+ if isinstance(obj, np.ndarray):
16
+ return obj.tolist()
17
+
18
+ if hasattr(obj, "__dict__"):
19
+ return flatten(vars(obj))
20
+
21
+ if isinstance(obj, (int, float, str)):
22
+ return obj
23
+
24
+ try:
25
+ return str(obj)
26
+ except:
27
+ return obj.__class__.__name__
@@ -18,7 +18,7 @@ from bluer_objects.mlflow.runs import (
18
18
  start_run,
19
19
  )
20
20
  from bluer_objects.mlflow.tags import (
21
- create_filter_string,
21
+ create_server_style_filter_string,
22
22
  get_tags,
23
23
  search,
24
24
  set_tags,