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,42 @@
|
|
|
1
|
+
from typing import Dict, Union
|
|
2
|
+
|
|
3
|
+
from blueness import module
|
|
4
|
+
from bluer_options.options import Options
|
|
5
|
+
|
|
6
|
+
from bluer_objects import NAME
|
|
7
|
+
from bluer_objects.mlflow.serverless import api
|
|
8
|
+
from bluer_objects.logger import logger
|
|
9
|
+
|
|
10
|
+
NAME = module.name(__file__, NAME)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def set_tags(
|
|
14
|
+
object_name: str,
|
|
15
|
+
tags: Union[str, Dict[str, str]],
|
|
16
|
+
log: bool = True,
|
|
17
|
+
verbose: bool = False,
|
|
18
|
+
icon="#️⃣ ",
|
|
19
|
+
) -> bool:
|
|
20
|
+
tags = Options(tags)
|
|
21
|
+
|
|
22
|
+
if not api.write(
|
|
23
|
+
object_name="_serverless_objects",
|
|
24
|
+
filename=f"{object_name}.yaml",
|
|
25
|
+
data=tags,
|
|
26
|
+
log=verbose,
|
|
27
|
+
):
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
for key, value in tags.items():
|
|
31
|
+
if not api.write(
|
|
32
|
+
object_name="_serverless_keys",
|
|
33
|
+
filename=f"{key}.yaml",
|
|
34
|
+
data={object_name: value},
|
|
35
|
+
log=verbose,
|
|
36
|
+
):
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
if log:
|
|
40
|
+
logger.info("{} {}.{}={}".format(icon, object_name, key, value))
|
|
41
|
+
|
|
42
|
+
return True
|
bluer_objects/mlflow/tags.py
CHANGED
|
@@ -7,13 +7,17 @@ from bluer_options.options import Options
|
|
|
7
7
|
from bluer_options.logger import crash_report
|
|
8
8
|
|
|
9
9
|
from bluer_objects import NAME
|
|
10
|
+
from bluer_objects import env
|
|
11
|
+
from bluer_objects.mlflow import serverless
|
|
10
12
|
from bluer_objects.mlflow.objects import to_experiment_name, to_object_name
|
|
11
13
|
from bluer_objects.logger import logger
|
|
12
14
|
|
|
13
15
|
NAME = module.name(__file__, NAME)
|
|
14
16
|
|
|
15
17
|
|
|
16
|
-
def
|
|
18
|
+
def create_server_style_filter_string(
|
|
19
|
+
tags: Union[str, dict],
|
|
20
|
+
) -> str:
|
|
17
21
|
tags_options = Options(tags)
|
|
18
22
|
|
|
19
23
|
# https://www.mlflow.org/docs/latest/search-experiments.html
|
|
@@ -25,7 +29,14 @@ def create_filter_string(tags: str) -> str:
|
|
|
25
29
|
def get_tags(
|
|
26
30
|
object_name: str,
|
|
27
31
|
exclude_system_tags: bool = True,
|
|
32
|
+
verbose: bool = False,
|
|
28
33
|
) -> Tuple[bool, Dict[str, str]]:
|
|
34
|
+
if env.MLFLOW_IS_SERVERLESS:
|
|
35
|
+
return serverless.get_tags(
|
|
36
|
+
object_name,
|
|
37
|
+
verbose=verbose,
|
|
38
|
+
)
|
|
39
|
+
|
|
29
40
|
experiment_name = to_experiment_name(object_name)
|
|
30
41
|
|
|
31
42
|
try:
|
|
@@ -48,16 +59,45 @@ def get_tags(
|
|
|
48
59
|
|
|
49
60
|
|
|
50
61
|
# https://www.mlflow.org/docs/latest/search-experiments.html
|
|
51
|
-
def search(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
def search(
|
|
63
|
+
filter_string: Union[str, dict],
|
|
64
|
+
server_style: bool = False,
|
|
65
|
+
verbose: bool = False,
|
|
66
|
+
) -> Tuple[bool, List[str]]:
|
|
67
|
+
if server_style and env.MLFLOW_IS_SERVERLESS:
|
|
68
|
+
logger.error("server_style search is not supported when mlflow is serverless.")
|
|
69
|
+
return False, []
|
|
70
|
+
|
|
71
|
+
if filter_string == "-":
|
|
72
|
+
filter_string = ""
|
|
73
|
+
|
|
74
|
+
if env.MLFLOW_IS_SERVERLESS:
|
|
75
|
+
return serverless.search(
|
|
57
76
|
filter_string=filter_string,
|
|
58
|
-
|
|
77
|
+
log=verbose,
|
|
59
78
|
)
|
|
60
|
-
|
|
79
|
+
|
|
80
|
+
if not server_style:
|
|
81
|
+
filter_string = create_server_style_filter_string(filter_string)
|
|
82
|
+
|
|
83
|
+
client = MlflowClient()
|
|
84
|
+
|
|
85
|
+
success = False
|
|
86
|
+
output = []
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
output = [
|
|
90
|
+
to_object_name(experiment.name)
|
|
91
|
+
for experiment in client.search_experiments(
|
|
92
|
+
filter_string=filter_string,
|
|
93
|
+
view_type=ViewType.ALL,
|
|
94
|
+
)
|
|
95
|
+
]
|
|
96
|
+
success = True
|
|
97
|
+
except Exception as e:
|
|
98
|
+
logger.error(e)
|
|
99
|
+
|
|
100
|
+
return success, output
|
|
61
101
|
|
|
62
102
|
|
|
63
103
|
def set_tags(
|
|
@@ -65,7 +105,17 @@ def set_tags(
|
|
|
65
105
|
tags: Union[str, Dict[str, str]],
|
|
66
106
|
log: bool = True,
|
|
67
107
|
icon="#️⃣ ",
|
|
108
|
+
verbose: bool = False,
|
|
68
109
|
) -> bool:
|
|
110
|
+
if env.MLFLOW_IS_SERVERLESS:
|
|
111
|
+
return serverless.set_tags(
|
|
112
|
+
object_name,
|
|
113
|
+
tags=tags,
|
|
114
|
+
log=log,
|
|
115
|
+
verbose=verbose,
|
|
116
|
+
icon=icon,
|
|
117
|
+
)
|
|
118
|
+
|
|
69
119
|
experiment_name = to_experiment_name(object_name)
|
|
70
120
|
|
|
71
121
|
try:
|
bluer_objects/objects.py
CHANGED
|
@@ -69,6 +69,7 @@ def signature(info=None, object_name="."):
|
|
|
69
69
|
def unique_object(
|
|
70
70
|
prefix: str = "",
|
|
71
71
|
include_time: bool = True,
|
|
72
|
+
log: bool = True,
|
|
72
73
|
):
|
|
73
74
|
object_name = string.pretty_date(
|
|
74
75
|
as_filename=True,
|
|
@@ -80,6 +81,7 @@ def unique_object(
|
|
|
80
81
|
|
|
81
82
|
path.create(object_path(object_name))
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
if log:
|
|
85
|
+
logger.info(f"📂 {object_name}")
|
|
84
86
|
|
|
85
87
|
return object_name
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
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.pdf.convert.batch import batch as batch_convert
|
|
8
|
+
from bluer_objects.pdf.convert.convert import convert
|
|
9
|
+
from bluer_objects.logger import logger
|
|
10
|
+
|
|
11
|
+
NAME = module.name(__file__, NAME)
|
|
12
|
+
|
|
13
|
+
parser = argparse.ArgumentParser(NAME)
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"task",
|
|
16
|
+
type=str,
|
|
17
|
+
help="convert",
|
|
18
|
+
)
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
"--path_prefix",
|
|
21
|
+
type=str,
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"--object_name",
|
|
25
|
+
type=str,
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--suffixes",
|
|
29
|
+
type=str,
|
|
30
|
+
)
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"--combine",
|
|
33
|
+
type=int,
|
|
34
|
+
default=0,
|
|
35
|
+
help="0 | 1",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
parser.add_argument(
|
|
39
|
+
"--count",
|
|
40
|
+
type=int,
|
|
41
|
+
default=-1,
|
|
42
|
+
help="-1: all",
|
|
43
|
+
)
|
|
44
|
+
parser.add_argument(
|
|
45
|
+
"--list_missing",
|
|
46
|
+
type=int,
|
|
47
|
+
default=1,
|
|
48
|
+
help="0 | 1",
|
|
49
|
+
)
|
|
50
|
+
parser.add_argument(
|
|
51
|
+
"--use_metadata",
|
|
52
|
+
type=int,
|
|
53
|
+
default=0,
|
|
54
|
+
help="0 | 1",
|
|
55
|
+
)
|
|
56
|
+
args = parser.parse_args()
|
|
57
|
+
|
|
58
|
+
success = False
|
|
59
|
+
if args.task == "convert":
|
|
60
|
+
if args.use_metadata == 1:
|
|
61
|
+
success = batch_convert(
|
|
62
|
+
object_name=args.object_name,
|
|
63
|
+
combine=args.combine == 1,
|
|
64
|
+
count=args.count,
|
|
65
|
+
list_missing=args.list_missing == 1,
|
|
66
|
+
)
|
|
67
|
+
else:
|
|
68
|
+
success = convert(
|
|
69
|
+
path_prefix=args.path_prefix,
|
|
70
|
+
list_of_suffixes=args.suffixes.split(","),
|
|
71
|
+
object_name=args.object_name,
|
|
72
|
+
combine=args.combine == 1,
|
|
73
|
+
count=args.count,
|
|
74
|
+
)
|
|
75
|
+
else:
|
|
76
|
+
success = None
|
|
77
|
+
|
|
78
|
+
sys_exit(logger, NAME, args.task, success)
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blueness import module
|
|
4
|
+
|
|
5
|
+
from bluer_objects import NAME
|
|
6
|
+
from bluer_objects.metadata import get_from_object
|
|
7
|
+
from bluer_objects.pdf.convert.convert import convert
|
|
8
|
+
from bluer_objects.pdf.convert.missing import list_missing_docs
|
|
9
|
+
from bluer_objects.env import abcli_path_git
|
|
10
|
+
from bluer_objects.logger import logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
NAME = module.name(__file__, NAME)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def batch(
|
|
17
|
+
object_name: str,
|
|
18
|
+
combine: bool,
|
|
19
|
+
count: int = -1,
|
|
20
|
+
list_missing: bool = True,
|
|
21
|
+
) -> bool:
|
|
22
|
+
logger.info(
|
|
23
|
+
"{}.batch: {}{}{}{}".format(
|
|
24
|
+
NAME,
|
|
25
|
+
object_name,
|
|
26
|
+
" + combine" if combine else "",
|
|
27
|
+
"" if count == -1 else f" {count} files",
|
|
28
|
+
" + list missing" if list_missing else "",
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
list_of_suffixes: List[str] = get_from_object(
|
|
33
|
+
object_name,
|
|
34
|
+
"pdf",
|
|
35
|
+
[],
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if not convert(
|
|
39
|
+
path_prefix=abcli_path_git,
|
|
40
|
+
list_of_suffixes=list_of_suffixes,
|
|
41
|
+
object_name=object_name,
|
|
42
|
+
combine=combine,
|
|
43
|
+
count=count,
|
|
44
|
+
incremental=False,
|
|
45
|
+
):
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
if list_missing:
|
|
49
|
+
list_missing_docs(
|
|
50
|
+
object_name=object_name,
|
|
51
|
+
list_of_suffixes=list_of_suffixes,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return True
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from PyPDF2 import PdfMerger
|
|
3
|
+
|
|
4
|
+
from bluer_options.logger import crash_report
|
|
5
|
+
|
|
6
|
+
from bluer_objects import objects
|
|
7
|
+
from bluer_objects.logger import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def combine_pdfs(
|
|
11
|
+
list_of_pdfs: List[str],
|
|
12
|
+
object_name: str,
|
|
13
|
+
) -> bool:
|
|
14
|
+
logger.info(f"combining {len(list_of_pdfs)} pdf(s)...")
|
|
15
|
+
combined_filename = objects.path_of(
|
|
16
|
+
filename="release.pdf",
|
|
17
|
+
object_name=object_name,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
merger = PdfMerger()
|
|
22
|
+
for filename in list_of_pdfs:
|
|
23
|
+
merger.append(filename)
|
|
24
|
+
|
|
25
|
+
merger.write(combined_filename)
|
|
26
|
+
merger.close()
|
|
27
|
+
except Exception as e:
|
|
28
|
+
crash_report(e)
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
logger.info(f"-> {combined_filename}")
|
|
32
|
+
return True
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from tqdm import tqdm
|
|
2
|
+
from typing import List
|
|
3
|
+
import os
|
|
4
|
+
from PIL import Image
|
|
5
|
+
|
|
6
|
+
from blueness import module
|
|
7
|
+
|
|
8
|
+
from bluer_objects import NAME
|
|
9
|
+
from bluer_objects import file, path
|
|
10
|
+
from bluer_objects.metadata import get_from_object, post_to_object
|
|
11
|
+
from bluer_objects.pdf.convert.combination import combine_pdfs
|
|
12
|
+
from bluer_objects.pdf.convert.image import convert_image
|
|
13
|
+
from bluer_objects.pdf.convert.md import convert_md
|
|
14
|
+
from bluer_objects.pdf.convert.pdf import convert_pdf
|
|
15
|
+
from bluer_objects.logger import logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
NAME = module.name(__file__, NAME)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def convert(
|
|
22
|
+
path_prefix: str,
|
|
23
|
+
list_of_suffixes: List[str],
|
|
24
|
+
object_name: str,
|
|
25
|
+
combine: bool,
|
|
26
|
+
count: int = -1,
|
|
27
|
+
incremental: bool = True,
|
|
28
|
+
) -> bool:
|
|
29
|
+
logger.info(f"path_prefix: {path_prefix}")
|
|
30
|
+
|
|
31
|
+
list_of_pdfs: List[str] = (
|
|
32
|
+
get_from_object(
|
|
33
|
+
object_name,
|
|
34
|
+
"list_of_pdfs",
|
|
35
|
+
[],
|
|
36
|
+
)
|
|
37
|
+
if incremental
|
|
38
|
+
else []
|
|
39
|
+
)
|
|
40
|
+
if incremental:
|
|
41
|
+
logger.info(f"found {len(list_of_pdfs)} pdf(s)...")
|
|
42
|
+
|
|
43
|
+
list_of_pdfs_len_target = -1 if count == -1 else len(list_of_pdfs) + count
|
|
44
|
+
for suffix in tqdm(list_of_suffixes):
|
|
45
|
+
if (
|
|
46
|
+
list_of_pdfs_len_target != -1
|
|
47
|
+
and len(list_of_pdfs) >= list_of_pdfs_len_target
|
|
48
|
+
):
|
|
49
|
+
logger.info(f"max count {count}, stopping.")
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
logger.info(
|
|
53
|
+
"{}.convert {} -> {}".format(
|
|
54
|
+
NAME,
|
|
55
|
+
suffix,
|
|
56
|
+
object_name,
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
source_filename = os.path.join(path_prefix, suffix)
|
|
61
|
+
if path.exists(source_filename):
|
|
62
|
+
source_filename = os.path.join(source_filename, "README.md")
|
|
63
|
+
suffix = os.path.join(suffix, "README.md")
|
|
64
|
+
|
|
65
|
+
if source_filename.endswith(".md"):
|
|
66
|
+
if not convert_md(
|
|
67
|
+
source_filename,
|
|
68
|
+
suffix,
|
|
69
|
+
object_name,
|
|
70
|
+
list_of_pdfs,
|
|
71
|
+
):
|
|
72
|
+
return False
|
|
73
|
+
elif file.extension(source_filename) == "pdf":
|
|
74
|
+
if not convert_pdf(
|
|
75
|
+
source_filename,
|
|
76
|
+
suffix,
|
|
77
|
+
object_name,
|
|
78
|
+
list_of_pdfs,
|
|
79
|
+
):
|
|
80
|
+
return False
|
|
81
|
+
elif file.extension(source_filename) in [
|
|
82
|
+
extension.split(".", 1)[1] for extension in Image.registered_extensions()
|
|
83
|
+
]:
|
|
84
|
+
if not convert_image(
|
|
85
|
+
source_filename,
|
|
86
|
+
suffix,
|
|
87
|
+
object_name,
|
|
88
|
+
list_of_pdfs,
|
|
89
|
+
):
|
|
90
|
+
return False
|
|
91
|
+
else:
|
|
92
|
+
logger.error(f"{source_filename}: cannot convert to pdf.")
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
if incremental:
|
|
96
|
+
logger.info(f"{len(list_of_pdfs)} pdf(s) so far ...")
|
|
97
|
+
if not post_to_object(
|
|
98
|
+
object_name,
|
|
99
|
+
"list_of_pdfs",
|
|
100
|
+
list_of_pdfs,
|
|
101
|
+
):
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
if combine:
|
|
105
|
+
return combine_pdfs(
|
|
106
|
+
list_of_pdfs,
|
|
107
|
+
object_name,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return True
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from PIL import Image
|
|
2
|
+
|
|
3
|
+
from bluer_options.logger import crash_report
|
|
4
|
+
|
|
5
|
+
from bluer_objects import file, objects, path
|
|
6
|
+
from bluer_objects.env import abcli_path_git
|
|
7
|
+
from bluer_objects.logger import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def convert_image(
|
|
11
|
+
source_filename: str,
|
|
12
|
+
suffix: str,
|
|
13
|
+
object_name: str,
|
|
14
|
+
list_of_pdfs: list[str],
|
|
15
|
+
) -> bool:
|
|
16
|
+
logger.info("🌠 image found!")
|
|
17
|
+
filename_pdf = file.add_extension(
|
|
18
|
+
objects.path_of(
|
|
19
|
+
filename="docs/{}".format(
|
|
20
|
+
(
|
|
21
|
+
suffix.split(abcli_path_git, 1)[1]
|
|
22
|
+
if abcli_path_git in suffix
|
|
23
|
+
else suffix
|
|
24
|
+
),
|
|
25
|
+
),
|
|
26
|
+
object_name=object_name,
|
|
27
|
+
),
|
|
28
|
+
"pdf",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
if filename_pdf not in list_of_pdfs:
|
|
32
|
+
list_of_pdfs.append(filename_pdf)
|
|
33
|
+
|
|
34
|
+
if file.exists(filename_pdf):
|
|
35
|
+
logger.info(f"✅ {filename_pdf}")
|
|
36
|
+
return True
|
|
37
|
+
|
|
38
|
+
if not path.create(
|
|
39
|
+
file.path(filename_pdf),
|
|
40
|
+
log=True,
|
|
41
|
+
):
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
image = Image.open(source_filename)
|
|
46
|
+
image = image.convert("RGB")
|
|
47
|
+
image.save(filename_pdf)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
crash_report(e)
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
logger.info(f"-> {filename_pdf}")
|
|
53
|
+
return True
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import pypandoc
|
|
2
|
+
import subprocess
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from bluer_options.logger import crash_report
|
|
6
|
+
|
|
7
|
+
from bluer_objects import file, objects, path
|
|
8
|
+
from bluer_objects.env import abcli_path_git
|
|
9
|
+
from bluer_objects.logger import logger
|
|
10
|
+
|
|
11
|
+
css = """
|
|
12
|
+
<style>
|
|
13
|
+
body { font-family: sans-serif; margin: 2cm; }
|
|
14
|
+
img { max-width: 100%; height: auto; }
|
|
15
|
+
table { width: 100%; border-collapse: collapse; word-break: break-word; }
|
|
16
|
+
th, td { border: 1px solid #ccc; padding: 4px; vertical-align: top; }
|
|
17
|
+
code, pre { white-space: pre-wrap; }
|
|
18
|
+
</style>
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def convert_md(
|
|
23
|
+
source_filename: str,
|
|
24
|
+
suffix: str,
|
|
25
|
+
object_name: str,
|
|
26
|
+
list_of_pdfs: list[str],
|
|
27
|
+
) -> bool:
|
|
28
|
+
filename_html = file.add_extension(
|
|
29
|
+
objects.path_of(
|
|
30
|
+
filename="docs/{}".format(
|
|
31
|
+
(
|
|
32
|
+
suffix.split(abcli_path_git, 1)[1]
|
|
33
|
+
if abcli_path_git in suffix
|
|
34
|
+
else suffix
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
object_name=object_name,
|
|
38
|
+
),
|
|
39
|
+
"html",
|
|
40
|
+
)
|
|
41
|
+
filename_pdf = file.add_extension(
|
|
42
|
+
filename_html,
|
|
43
|
+
"pdf",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if filename_pdf not in list_of_pdfs:
|
|
47
|
+
list_of_pdfs.append(filename_pdf)
|
|
48
|
+
|
|
49
|
+
if file.exists(filename_pdf):
|
|
50
|
+
logger.info(f"✅ {filename_pdf}")
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
logger.info(f"{source_filename} -> {filename_pdf}")
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
with open(source_filename, "r", encoding="utf-8") as f:
|
|
57
|
+
markdown_text = f.read()
|
|
58
|
+
|
|
59
|
+
html_text = pypandoc.convert_text(
|
|
60
|
+
markdown_text,
|
|
61
|
+
"html",
|
|
62
|
+
format="md",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
html_text = (
|
|
66
|
+
f"<!DOCTYPE html><html><head>{css}</head><body>{html_text}</body></html>"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if not path.create(
|
|
70
|
+
file.path(filename_html),
|
|
71
|
+
log=True,
|
|
72
|
+
):
|
|
73
|
+
return (False,)
|
|
74
|
+
|
|
75
|
+
with open(
|
|
76
|
+
filename_html,
|
|
77
|
+
"w",
|
|
78
|
+
encoding="utf-8",
|
|
79
|
+
) as f:
|
|
80
|
+
f.write(html_text)
|
|
81
|
+
|
|
82
|
+
subprocess.run(
|
|
83
|
+
[
|
|
84
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
85
|
+
"--headless",
|
|
86
|
+
"--disable-gpu",
|
|
87
|
+
"--no-margins",
|
|
88
|
+
f"--print-to-pdf={filename_pdf}",
|
|
89
|
+
os.path.abspath(filename_html),
|
|
90
|
+
],
|
|
91
|
+
check=True,
|
|
92
|
+
)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
crash_report(e)
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
return True
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
import os
|
|
3
|
+
from functools import reduce
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
from blueness import module
|
|
7
|
+
from bluer_options.logger.config import log_list
|
|
8
|
+
|
|
9
|
+
from bluer_objects import NAME
|
|
10
|
+
from bluer_objects import file
|
|
11
|
+
from bluer_objects.metadata import get_from_object
|
|
12
|
+
from bluer_objects.pdf.convert.convert import convert
|
|
13
|
+
from bluer_objects.env import abcli_path_git
|
|
14
|
+
from bluer_objects.logger import logger
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def list_missing_docs(
|
|
18
|
+
object_name: str,
|
|
19
|
+
list_of_suffixes: List[str],
|
|
20
|
+
):
|
|
21
|
+
logger.info(f"{NAME}.list_missing_docs: {object_name}")
|
|
22
|
+
|
|
23
|
+
list_of_suffixes_fullpath = [
|
|
24
|
+
os.path.join(abcli_path_git, suffix) for suffix in list_of_suffixes
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
list_of_prefixes_to_ignore: List[str] = [
|
|
28
|
+
os.path.join(abcli_path_git, prefix)
|
|
29
|
+
for prefix in get_from_object(
|
|
30
|
+
object_name,
|
|
31
|
+
"ignore",
|
|
32
|
+
[],
|
|
33
|
+
)
|
|
34
|
+
]
|
|
35
|
+
log_list(
|
|
36
|
+
logger,
|
|
37
|
+
"ignoring",
|
|
38
|
+
list_of_prefixes_to_ignore,
|
|
39
|
+
"prefix(s)",
|
|
40
|
+
max_count=-1,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
list_of_prefixes: List[str] = sorted(
|
|
44
|
+
list({suffix.split(os.sep)[0] for suffix in list_of_suffixes})
|
|
45
|
+
)
|
|
46
|
+
log_list(
|
|
47
|
+
logger,
|
|
48
|
+
"found",
|
|
49
|
+
list_of_prefixes,
|
|
50
|
+
"prefix(s)",
|
|
51
|
+
max_count=-1,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
list_of_missing_docs: List[str] = [
|
|
55
|
+
filename
|
|
56
|
+
for filename in reduce(
|
|
57
|
+
lambda x, y: x + y,
|
|
58
|
+
[
|
|
59
|
+
file.list_of(
|
|
60
|
+
os.path.join(
|
|
61
|
+
abcli_path_git,
|
|
62
|
+
prefix,
|
|
63
|
+
"*.md",
|
|
64
|
+
),
|
|
65
|
+
recursive=True,
|
|
66
|
+
)
|
|
67
|
+
for prefix in list_of_prefixes
|
|
68
|
+
],
|
|
69
|
+
[],
|
|
70
|
+
)
|
|
71
|
+
if not any(
|
|
72
|
+
thing in filename
|
|
73
|
+
for thing in [
|
|
74
|
+
"template",
|
|
75
|
+
"pytest_cache",
|
|
76
|
+
]
|
|
77
|
+
)
|
|
78
|
+
and filename not in list_of_suffixes_fullpath
|
|
79
|
+
and not any(
|
|
80
|
+
filename.startswith(prefix) for prefix in list_of_prefixes_to_ignore
|
|
81
|
+
)
|
|
82
|
+
and re.search(r"(?:^|-)v(\d+)\.md$", file.name_and_extension(filename)) is None
|
|
83
|
+
and file.name_and_extension(filename) != "README.md"
|
|
84
|
+
]
|
|
85
|
+
if list_of_missing_docs:
|
|
86
|
+
logger.warning("missing docs.")
|
|
87
|
+
log_list(
|
|
88
|
+
logger,
|
|
89
|
+
"found",
|
|
90
|
+
list_of_missing_docs,
|
|
91
|
+
"missing doc(s)",
|
|
92
|
+
max_count=-1,
|
|
93
|
+
max_length=-1,
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
logger.info("✅ no missing docs.")
|