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

1import pathlib 

2from typing import Annotated 

3 

4import typer 

5 

6from rendercv.schema.rendercv_model_builder import ( 

7 BuildRendercvModelArguments, 

8) 

9 

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 

16 

17 

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() 

200 

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"] 

209 

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 } 

229 

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)