Coverage for src / rendercv / cli / render_command / render_command.py: 100%
24 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 13:49 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 13:49 +0000
1import pathlib
2from typing import Annotated
4import typer
6from rendercv.schema.rendercv_model_builder import (
7 BuildRendercvModelArguments,
8)
10from ..app import app
11from ..error_handler import handle_user_errors
12from .parse_override_arguments import parse_override_arguments
13from .progress_panel import ProgressPanel
14from .run_rendercv import collect_input_file_paths, run_rendercv
15from .watcher import run_function_if_files_change
18@app.command(
19 name="render",
20 help=(
21 "Render a YAML input file. Example: [yellow]rendercv render"
22 " John_Doe_CV.yaml[/yellow]. Details: [cyan]rendercv render --help[/cyan]"
23 ),
24 # allow extra arguments for updating the old_data model (for overriding the values of
25 # the input file):
26 context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
27)
28@handle_user_errors
29def cli_command_render(
30 input_file_name: Annotated[
31 pathlib.Path, typer.Argument(help="The YAML input file.")
32 ],
33 output_folder: Annotated[
34 pathlib.Path | None,
35 typer.Option(
36 "--output-folder",
37 "-o",
38 help=(
39 "Base output folder for all generated files. Replaces the default"
40 " 'rendercv_output' folder."
41 ),
42 ),
43 ] = None,
44 design: Annotated[
45 pathlib.Path | None,
46 typer.Option(
47 "--design",
48 "-d",
49 help='The "design" field\'s YAML input file.',
50 ),
51 ] = None,
52 locale: Annotated[
53 pathlib.Path | None,
54 typer.Option(
55 "--locale-catalog",
56 "-lc",
57 help='The "locale" field\'s YAML input file.',
58 ),
59 ] = None,
60 settings: Annotated[
61 pathlib.Path | None,
62 typer.Option(
63 "--settings",
64 "-s",
65 help='The "settings" field\'s YAML input file.',
66 ),
67 ] = None,
68 typst_path: Annotated[
69 pathlib.Path | None,
70 typer.Option(
71 "--typst-path",
72 "-typ",
73 help=(
74 "Save the generated Typst file to the specified path, relative to the"
75 " input file."
76 ),
77 ),
78 ] = None,
79 pdf_path: Annotated[
80 pathlib.Path | None,
81 typer.Option(
82 "--pdf-path",
83 "-pdf",
84 help=(
85 "Save the generated PDF file to the specified path, relative to the"
86 " input file."
87 ),
88 ),
89 ] = None,
90 markdown_path: Annotated[
91 pathlib.Path | None,
92 typer.Option(
93 "--markdown-path",
94 "-md",
95 help=(
96 "Save the generated Markdown file to the specified path, relative to"
97 " the input file."
98 ),
99 ),
100 ] = None,
101 html_path: Annotated[
102 pathlib.Path | None,
103 typer.Option(
104 "--html-path",
105 "-html",
106 help=(
107 "Save the generated HTML file to the specified path, relative to the"
108 " input file."
109 ),
110 ),
111 ] = None,
112 png_path: Annotated[
113 pathlib.Path | None,
114 typer.Option(
115 "--png-path",
116 "-png",
117 help=(
118 "Save the generated PNG files to the specified path, relative to the"
119 " input file."
120 ),
121 ),
122 ] = None,
123 dont_generate_markdown: Annotated[
124 bool | None,
125 typer.Option(
126 "--dont-generate-markdown",
127 "-nomd",
128 help=(
129 "If provided, the Markdown file will not be generated. Disabling"
130 " Markdown generation implicitly disables HTML."
131 ),
132 ),
133 ] = None,
134 dont_generate_html: Annotated[
135 bool | None,
136 typer.Option(
137 "--dont-generate-html",
138 "-nohtml",
139 help="If provided, the HTML file will not be generated.",
140 ),
141 ] = None,
142 dont_generate_typst: Annotated[
143 bool | None,
144 typer.Option(
145 "--dont-generate-typst",
146 "-notyp",
147 help=(
148 "If provided, the Typst file will not be generated. Disabling Typst"
149 " generation implicitly disables PDF and PNG."
150 ),
151 ),
152 ] = None,
153 dont_generate_pdf: Annotated[
154 bool | None,
155 typer.Option(
156 "--dont-generate-pdf",
157 "-nopdf",
158 help="If provided, the PDF file will not be generated.",
159 ),
160 ] = None,
161 dont_generate_png: Annotated[
162 bool | None,
163 typer.Option(
164 "--dont-generate-png",
165 "-nopng",
166 help="If provided, the PNG file will not be generated.",
167 ),
168 ] = None,
169 watch: Annotated[
170 bool | None,
171 typer.Option(
172 "--watch",
173 "-w",
174 help=(
175 "If provided, RenderCV will automatically re-run when the input file is"
176 " updated."
177 ),
178 ),
179 ] = None,
180 quiet: Annotated[
181 bool,
182 typer.Option(
183 "--quiet",
184 "-q",
185 help="If provided, RenderCV will not print any messages.",
186 ),
187 ] = False,
188 # Dummy argument that only exists to show the override syntax in --help:
189 yaml_field_override: Annotated[ # noqa: ARG001
190 str | None,
191 typer.Option(
192 "--YAMLLOCATION",
193 help="Overrides the value of YAMLLOCATION. For example,"
194 ' [cyan bold]--cv.phone "123-456-7890"[/cyan bold].',
195 ),
196 ] = None,
197 extra_data_model_override_arguments: typer.Context = None, # ty: ignore[invalid-parameter-default]
198) -> None:
199 input_file_path = pathlib.Path(input_file_name).absolute()
201 # Resolve design/locale overlay files from YAML settings when not
202 # provided via CLI flags. collect_input_file_paths already handles
203 # parsing the YAML and resolving paths relative to the input file.
204 resolved_files = collect_input_file_paths(input_file_path, design, locale, settings)
205 if design is None and "design" in resolved_files:
206 design = resolved_files["design"]
207 if locale is None and "locale" in resolved_files:
208 locale = resolved_files["locale"]
210 arguments: BuildRendercvModelArguments = {
211 "design_yaml_file": design.read_text(encoding="utf-8") if design else None,
212 "locale_yaml_file": locale.read_text(encoding="utf-8") if locale else None,
213 "settings_yaml_file": (
214 settings.read_text(encoding="utf-8") if settings else None
215 ),
216 "output_folder": output_folder,
217 "typst_path": typst_path,
218 "pdf_path": pdf_path,
219 "markdown_path": markdown_path,
220 "html_path": html_path,
221 "png_path": png_path,
222 "dont_generate_typst": dont_generate_typst,
223 "dont_generate_html": dont_generate_html,
224 "dont_generate_markdown": dont_generate_markdown,
225 "dont_generate_pdf": dont_generate_pdf,
226 "dont_generate_png": dont_generate_png,
227 "overrides": parse_override_arguments(extra_data_model_override_arguments),
228 }
230 with ProgressPanel(quiet=quiet) as progress_panel:
231 if watch:
232 run_function_if_files_change(
233 list(resolved_files.values()),
234 lambda: run_rendercv(input_file_path, progress_panel, **arguments),
235 )
236 else:
237 run_rendercv(input_file_path, progress_panel, **arguments)