Skip to content

Commit fe301f4

Browse files
committed
Use click for proper CLI handling, user can change verbosity
1 parent 25f1e9c commit fe301f4

File tree

4 files changed

+64
-58
lines changed

4 files changed

+64
-58
lines changed

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[MASTER]
22
score=n
33
generated-members=PyPDF2.*
4-
ignored-modules=cairosvg,jinja2,pypdf,yaml
4+
ignored-modules=cairosvg,click,jinja2,pypdf,yaml
55

66
[REPORTS]
77
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pipx ensurepath
4040
Generate your documents with:
4141

4242
```
43-
pdfbaker <path_to_config_file>
43+
pdfbaker bake <path_to_config_file>
4444
```
4545

4646
This will create a `build/` directory and a `dist/` directory where your configuration

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ authors = [
77
]
88
dependencies = [
99
"cairosvg",
10+
"click",
1011
"jinja2",
1112
"pypdf",
1213
"pyyaml",
@@ -15,7 +16,7 @@ readme = "README.md"
1516
requires-python = ">= 3.11"
1617

1718
[project.scripts]
18-
pdfbaker = "pdfbaker.__main__:main"
19+
pdfbaker = "pdfbaker.__main__:cli"
1920

2021
[build-system]
2122
requires = ["hatchling==1.26.3"] # https://github.com/astral-sh/rye/issues/1446

src/pdfbaker/__main__.py

Lines changed: 60 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,53 @@
66
import sys
77
from pathlib import Path
88

9+
import click
910
import yaml
1011

1112
from .common import deep_merge
1213
from .render import create_env
1314

14-
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
15+
logging.basicConfig(
16+
level=logging.INFO,
17+
format="%(levelname)s: %(message)s"
18+
)
1519
logger = logging.getLogger(__name__)
1620

21+
@click.group()
22+
@click.option(
23+
"-v", "--verbose", is_flag=True,
24+
help="Show debug information"
25+
)
26+
@click.option(
27+
"-q", "--quiet", is_flag=True,
28+
help="Show errors only"
29+
)
30+
def cli(verbose, quiet):
31+
"""PDF document generator from YAML-configured SVG templates."""
32+
if quiet:
33+
logging.getLogger().setLevel(logging.ERROR)
34+
elif verbose:
35+
logging.getLogger().setLevel(logging.DEBUG)
36+
else:
37+
logging.getLogger().setLevel(logging.INFO)
38+
39+
@cli.command()
40+
@click.argument("config_path", type=click.Path(exists=True, path_type=Path))
41+
def bake(config_path):
42+
"""Generate PDF documents from YAML-configured SVG templates.
43+
44+
CONFIG_PATH is the path to your configuration YAML file.
45+
"""
46+
config = _load_config(config_path)
47+
base_dir = config_path.parent
48+
document_paths = _get_document_paths(base_dir, config.get("documents", []))
49+
build_dir, dist_dir = _setup_output_directories(base_dir)
1750

18-
def _get_config_path(config_path=None):
19-
"""Get and validate the configuration file path."""
20-
if config_path is None:
21-
if len(sys.argv) < 2:
22-
logger.error("Config file path is required")
23-
logger.error("Usage: python -m pdfbaker <config_file_path>")
24-
return None
25-
config_path = sys.argv[1]
26-
27-
config_path = Path(config_path).resolve()
28-
if not config_path.exists():
29-
logger.error("Configuration file not found: %s", config_path)
30-
return None
51+
for doc_name, doc_path in document_paths.items():
52+
_process_document(doc_name, doc_path, config, build_dir, dist_dir)
3153

32-
return config_path
54+
logger.info("Done.")
55+
return 0
3356

3457

3558
def _load_config(config_path):
@@ -84,32 +107,6 @@ def _validate_document_path(doc_name, doc_path):
84107
return bake_path, config_yml_path
85108

86109

87-
def _load_document_bake_module(doc_name, bake_path):
88-
"""Load the document's bake.py module."""
89-
doc_bake = importlib.util.spec_from_file_location(
90-
f"documents.{doc_name}.bake", bake_path
91-
)
92-
module = importlib.util.module_from_spec(doc_bake)
93-
doc_bake.loader.exec_module(module)
94-
return module
95-
96-
97-
def _setup_document_output_directories(build_dir, dist_dir, doc_name):
98-
"""Set up and clean document-specific build and dist directories."""
99-
doc_build_dir = build_dir / doc_name
100-
doc_dist_dir = dist_dir / doc_name
101-
os.makedirs(doc_build_dir, exist_ok=True)
102-
os.makedirs(doc_dist_dir, exist_ok=True)
103-
104-
for dir_path in [doc_build_dir, doc_dist_dir]:
105-
for file in os.listdir(dir_path):
106-
file_path = dir_path / file
107-
if os.path.isfile(file_path):
108-
os.remove(file_path)
109-
110-
return doc_build_dir, doc_dist_dir
111-
112-
113110
def _process_document(doc_name, doc_path, config, build_dir, dist_dir):
114111
"""Process an individual document."""
115112
validation_result = _validate_document_path(doc_name, doc_path)
@@ -142,23 +139,31 @@ def _process_document(doc_name, doc_path, config, build_dir, dist_dir):
142139
)
143140

144141

145-
def main(config_path=None):
146-
"""Main function for the document generator."""
147-
config_path = _get_config_path(config_path)
148-
if config_path is None:
149-
return 1
142+
def _load_document_bake_module(doc_name, bake_path):
143+
"""Load the document's bake.py module."""
144+
doc_bake = importlib.util.spec_from_file_location(
145+
f"documents.{doc_name}.bake", bake_path
146+
)
147+
module = importlib.util.module_from_spec(doc_bake)
148+
doc_bake.loader.exec_module(module)
149+
return module
150150

151-
config = _load_config(config_path)
152-
base_dir = config_path.parent
153-
document_paths = _get_document_paths(base_dir, config.get("documents", []))
154-
build_dir, dist_dir = _setup_output_directories(base_dir)
155151

156-
for doc_name, doc_path in document_paths.items():
157-
_process_document(doc_name, doc_path, config, build_dir, dist_dir)
152+
def _setup_document_output_directories(build_dir, dist_dir, doc_name):
153+
"""Set up and clean document-specific build and dist directories."""
154+
doc_build_dir = build_dir / doc_name
155+
doc_dist_dir = dist_dir / doc_name
156+
os.makedirs(doc_build_dir, exist_ok=True)
157+
os.makedirs(doc_dist_dir, exist_ok=True)
158158

159-
logger.info("Done.")
160-
return 0
159+
for dir_path in [doc_build_dir, doc_dist_dir]:
160+
for file in os.listdir(dir_path):
161+
file_path = dir_path / file
162+
if os.path.isfile(file_path):
163+
os.remove(file_path)
164+
165+
return doc_build_dir, doc_dist_dir
161166

162167

163168
if __name__ == "__main__":
164-
sys.exit(main())
169+
sys.exit(cli())

0 commit comments

Comments
 (0)