The rendercv.renderer.renderer
module contains the necessary functions for rendering
Typst, PDF, Markdown, HTML, and PNG files from the RenderCVDataModel
object.
TypstCompiler
A singleton class for the Typst compiler.
Source code in rendercv/renderer/renderer.py
| class TypstCompiler:
"""A singleton class for the Typst compiler."""
instance: "TypstCompiler"
compiler: Any
file_path: pathlib.Path
def __new__(cls, file_path: pathlib.Path):
if not hasattr(cls, "instance") or cls.instance.file_path != file_path:
try:
import rendercv_fonts
import typst
except Exception as e:
from .. import _parial_install_error_message
raise ImportError(_parial_install_error_message) from e
cls.instance = super().__new__(cls)
cls.instance.file_path = file_path
cls.instance.compiler = typst.Compiler(
file_path, font_paths=rendercv_fonts.paths_to_font_folders
)
return cls.instance
def run(
self,
output: pathlib.Path,
format: Literal["png", "pdf"],
ppi: Optional[float] = None,
) -> pathlib.Path | list[pathlib.Path]:
return self.instance.compiler.compile(format=format, output=output, ppi=ppi)
|
create_a_file_name_without_extension_from_name(name)
Create a file name from the given name by replacing the spaces with underscores
and removing typst commands.
Parameters:
-
name
(Optional[str]
)
–
The name to be converted.
Returns:
-
str
–
The converted name (without the extension).
Source code in rendercv/renderer/renderer.py
| def create_a_file_name_without_extension_from_name(name: Optional[str]) -> str:
"""Create a file name from the given name by replacing the spaces with underscores
and removing typst commands.
Args:
name: The name to be converted.
Returns:
The converted name (without the extension).
"""
name_without_typst_commands = templater.remove_typst_commands(str(name))
return f"{name_without_typst_commands.replace(' ', '_')}_CV"
|
create_a_file_and_write_contents_to_it(contents, file_name, output_directory)
Create a file with the given contents in the output directory.
Parameters:
-
contents
(str
)
–
The contents of the file.
-
file_name
(str
)
–
-
output_directory
(Path
)
–
Path to the output directory.
Returns:
-
Path
–
The path to the created file.
Source code in rendercv/renderer/renderer.py
| def create_a_file_and_write_contents_to_it(
contents: str, file_name: str, output_directory: pathlib.Path
) -> pathlib.Path:
"""Create a file with the given contents in the output directory.
Args:
contents: The contents of the file.
file_name: The name of the file.
output_directory: Path to the output directory.
Returns:
The path to the created file.
"""
# Create output directory if it doesn't exist:
if not output_directory.is_dir():
output_directory.mkdir(parents=True)
file_path = output_directory / file_name
file_path.write_text(contents, encoding="utf-8")
return file_path
|
copy_theme_files_to_output_directory(theme_name, output_directory_path)
Copy the auxiliary files (all the files that don't end with .j2.typ
and .py
)
of the theme to the output directory.
Parameters:
-
theme_name
(str
)
–
-
output_directory_path
(Path
)
–
Path to the output directory.
Source code in rendercv/renderer/renderer.py
| def copy_theme_files_to_output_directory(
theme_name: str,
output_directory_path: pathlib.Path,
):
"""Copy the auxiliary files (all the files that don't end with `.j2.typ` and `.py`)
of the theme to the output directory.
Args:
theme_name: The name of the theme.
output_directory_path: Path to the output directory.
"""
if theme_name in data.available_themes:
theme_directory_path = importlib.resources.files(
f"rendercv.themes.{theme_name}"
)
else:
# Then it means the theme is a custom theme. If theme_directory is not given
# as an argument, then look for the theme in the current working directory.
theme_directory_path = pathlib.Path.cwd() / theme_name
if not theme_directory_path.is_dir():
message = (
f"The theme {theme_name} doesn't exist in the available themes and"
" the current working directory!"
)
raise FileNotFoundError(message)
dont_copy_files_with_these_extensions = [".py", ".j2.typ"]
for theme_file in theme_directory_path.iterdir():
# theme_file.suffix returns the latest part of the file name after the last dot.
# But we need the latest part of the file name after the first dot:
try:
suffix = re.search(r"\..*", theme_file.name)[0] # type: ignore
except TypeError:
suffix = ""
if suffix not in dont_copy_files_with_these_extensions:
if theme_file.is_dir():
shutil.copytree(
str(theme_file),
output_directory_path / theme_file.name,
dirs_exist_ok=True,
)
else:
shutil.copyfile(
str(theme_file), output_directory_path / theme_file.name
)
|
create_contents_of_a_typst_file(rendercv_data_model)
Create a Typst file with the given data model and return it as a string.
Parameters:
Returns:
-
str
–
The path to the generated Typst file.
Source code in rendercv/renderer/renderer.py
| def create_contents_of_a_typst_file(
rendercv_data_model: data.RenderCVDataModel,
) -> str:
"""Create a Typst file with the given data model and return it as a string.
Args:
rendercv_data_model: The data model.
Returns:
The path to the generated Typst file.
"""
jinja2_environment = templater.Jinja2Environment().environment
file_object = templater.TypstFile(
rendercv_data_model,
jinja2_environment,
)
return file_object.get_full_code()
|
create_a_typst_file(rendercv_data_model, output_directory)
Create a Typst file (depending on the theme) with the given data model and write
it to the output directory.
Parameters:
-
rendercv_data_model
(RenderCVDataModel
)
–
-
output_directory
(Path
)
–
Path to the output directory. If not given, the Typst file
will be returned as a string.
Returns:
-
Path
–
The path to the generated Typst file.
Source code in rendercv/renderer/renderer.py
| def create_a_typst_file(
rendercv_data_model: data.RenderCVDataModel,
output_directory: pathlib.Path,
) -> pathlib.Path:
"""Create a Typst file (depending on the theme) with the given data model and write
it to the output directory.
Args:
rendercv_data_model: The data model.
output_directory: Path to the output directory. If not given, the Typst file
will be returned as a string.
Returns:
The path to the generated Typst file.
"""
typst_contents = create_contents_of_a_typst_file(rendercv_data_model)
file_name_without_extension = create_a_file_name_without_extension_from_name(
rendercv_data_model.cv.name
)
file_name = f"{file_name_without_extension}.typ"
return create_a_file_and_write_contents_to_it(
typst_contents,
file_name,
output_directory,
)
|
create_contents_of_a_markdown_file(rendercv_data_model)
Create a Markdown file with the given data model and return it as a string.
Parameters:
Returns:
-
str
–
The path to the generated Markdown file.
Source code in rendercv/renderer/renderer.py
| def create_contents_of_a_markdown_file(
rendercv_data_model: data.RenderCVDataModel,
) -> str:
"""Create a Markdown file with the given data model and return it as a string.
Args:
rendercv_data_model: The data model.
Returns:
The path to the generated Markdown file.
"""
jinja2_environment = templater.Jinja2Environment().environment
markdown_file_object = templater.MarkdownFile(
rendercv_data_model,
jinja2_environment,
)
return markdown_file_object.get_full_code()
|
create_a_markdown_file(rendercv_data_model, output_directory)
Render the Markdown file with the given data model and write it to the output
directory.
Parameters:
-
rendercv_data_model
(RenderCVDataModel
)
–
-
output_directory
(Path
)
–
Path to the output directory.
Returns:
-
Path
–
The path to the rendered Markdown file.
Source code in rendercv/renderer/renderer.py
| def create_a_markdown_file(
rendercv_data_model: data.RenderCVDataModel, output_directory: pathlib.Path
) -> pathlib.Path:
"""Render the Markdown file with the given data model and write it to the output
directory.
Args:
rendercv_data_model: The data model.
output_directory: Path to the output directory.
Returns:
The path to the rendered Markdown file.
"""
markdown_contents = create_contents_of_a_markdown_file(rendercv_data_model)
file_name_without_extension = create_a_file_name_without_extension_from_name(
rendercv_data_model.cv.name
)
file_name = f"{file_name_without_extension}.md"
return create_a_file_and_write_contents_to_it(
markdown_contents,
file_name,
output_directory,
)
|
create_a_typst_file_and_copy_theme_files(rendercv_data_model, output_directory)
Render the Typst file with the given data model in the output directory and
copy the auxiliary theme files to the output directory.
Parameters:
-
rendercv_data_model
(RenderCVDataModel
)
–
-
output_directory
(Path
)
–
Path to the output directory.
Returns:
-
Path
–
The path to the rendered Typst file.
Source code in rendercv/renderer/renderer.py
| def create_a_typst_file_and_copy_theme_files(
rendercv_data_model: data.RenderCVDataModel, output_directory: pathlib.Path
) -> pathlib.Path:
"""Render the Typst file with the given data model in the output directory and
copy the auxiliary theme files to the output directory.
Args:
rendercv_data_model: The data model.
output_directory: Path to the output directory.
Returns:
The path to the rendered Typst file.
"""
file_path = create_a_typst_file(rendercv_data_model, output_directory)
copy_theme_files_to_output_directory(
rendercv_data_model.design.theme, output_directory
)
# Copy the profile picture to the output directory, if it exists:
if rendercv_data_model.cv.photo:
shutil.copyfile(
rendercv_data_model.cv.photo,
output_directory / rendercv_data_model.cv.photo.name,
)
return file_path
|
render_a_pdf_from_typst(file_path)
Run TinyTeX with the given Typst file to render the PDF.
Parameters:
-
file_path
(Path
)
–
The path to the Typst file.
Returns:
-
Path
–
The path to the rendered PDF file.
Source code in rendercv/renderer/renderer.py
| def render_a_pdf_from_typst(file_path: pathlib.Path) -> pathlib.Path:
"""Run TinyTeX with the given Typst file to render the PDF.
Args:
file_path: The path to the Typst file.
Returns:
The path to the rendered PDF file.
"""
typst_compiler = TypstCompiler(file_path)
# Before running Typst, make sure the PDF file is not open in another program,
# that wouldn't allow Typst to write to it. Remove the PDF file if it exists,
# if it's not removable, then raise an error:
pdf_output_path = file_path.with_suffix(".pdf")
if sys.platform == "win32":
if pdf_output_path.is_file():
try:
pdf_output_path.unlink()
except PermissionError as e:
message = (
f"The PDF file {pdf_output_path} is open in another program and"
" doesn't allow RenderCV to rewrite it. Please close the PDF file."
)
raise RuntimeError(message) from e
typst_compiler.run(output=pdf_output_path, format="pdf")
return pdf_output_path
|
render_pngs_from_typst(file_path, ppi=150)
Run Typst with the given Typst file to render the PNG files.
Parameters:
-
file_path
(Path
)
–
The path to the Typst file.
-
ppi
(float
, default:
150
)
–
Pixels per inch for PNG output, defaults to 150.
Returns:
-
list[Path]
–
Paths to the rendered PNG files.
Source code in rendercv/renderer/renderer.py
| def render_pngs_from_typst(
file_path: pathlib.Path, ppi: float = 150
) -> list[pathlib.Path]:
"""Run Typst with the given Typst file to render the PNG files.
Args:
file_path: The path to the Typst file.
ppi: Pixels per inch for PNG output, defaults to 150.
Returns:
Paths to the rendered PNG files.
"""
typst_compiler = TypstCompiler(file_path)
output_path = file_path.parent / (file_path.stem + "_{p}.png")
typst_compiler.run(format="png", ppi=ppi, output=output_path)
# Look at the outtput folder and find the PNG files:
png_files = list(output_path.parent.glob(f"{file_path.stem}_*.png"))
return sorted(png_files, key=lambda x: int(x.stem.split("_")[-1]))
|
render_an_html_from_markdown(markdown_file_path)
Render an HTML file from a Markdown file with the same name and in the same
directory. It uses rendercv/themes/main.j2.html
as the Jinja2 template.
Parameters:
-
markdown_file_path
(Path
)
–
The path to the Markdown file.
Returns:
-
Path
–
The path to the rendered HTML file.
Source code in rendercv/renderer/renderer.py
| def render_an_html_from_markdown(markdown_file_path: pathlib.Path) -> pathlib.Path:
"""Render an HTML file from a Markdown file with the same name and in the same
directory. It uses `rendercv/themes/main.j2.html` as the Jinja2 template.
Args:
markdown_file_path: The path to the Markdown file.
Returns:
The path to the rendered HTML file.
"""
try:
import markdown
except Exception as e:
from .. import _parial_install_error_message
raise ImportError(_parial_install_error_message) from e
# check if the file exists:
if not markdown_file_path.is_file():
message = f"The file {markdown_file_path} doesn't exist!"
raise FileNotFoundError(message)
# Convert the markdown file to HTML:
markdown_text = markdown_file_path.read_text(encoding="utf-8")
html_body = markdown.markdown(markdown_text)
# Get the title of the markdown content:
title = re.search(r"# (.*)\n", markdown_text)
title = title.group(1) if title else None
jinja2_environment = templater.Jinja2Environment().environment
html_template = jinja2_environment.get_template("main.j2.html")
html = html_template.render(html_body=html_body, title=title)
# Write html into a file:
html_file_path = markdown_file_path.parent / f"{markdown_file_path.stem}.html"
html_file_path.write_text(html, encoding="utf-8")
return html_file_path
|