mirror of https://github.com/eyhc1/rendercv.git
create LaTeXFile class
This commit is contained in:
parent
49a769ea80
commit
cd898274b7
|
@ -18,6 +18,98 @@ import jinja2
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class LaTeXFile:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
cv: dm.CurriculumVitae,
|
||||||
|
design: dm.Design,
|
||||||
|
environment: jinja2.Environment,
|
||||||
|
file_path,
|
||||||
|
):
|
||||||
|
self.file_path = file_path
|
||||||
|
self.cv = cv
|
||||||
|
self.design = design
|
||||||
|
self.environment = environment
|
||||||
|
|
||||||
|
self.preamble = self.template("Preamble")
|
||||||
|
self.header = self.template("Header")
|
||||||
|
self.sections = []
|
||||||
|
for section in cv.sections:
|
||||||
|
title = self.template("SectionTitle", section_title=section.title)
|
||||||
|
entries = []
|
||||||
|
for entry in section.entries:
|
||||||
|
entries.append(self.template(section.entry_type, entry=entry))
|
||||||
|
self.sections.append((title, entries))
|
||||||
|
|
||||||
|
def template(
|
||||||
|
self,
|
||||||
|
template_name: Literal[
|
||||||
|
"EducationEntry",
|
||||||
|
"ExperienceEntry",
|
||||||
|
"NormalEntry",
|
||||||
|
"PublicationEntry",
|
||||||
|
"OneLineEntry",
|
||||||
|
"TextEntry",
|
||||||
|
"Header",
|
||||||
|
"Preamble",
|
||||||
|
"SectionTitle",
|
||||||
|
],
|
||||||
|
entry: Optional[
|
||||||
|
dm.EducationEntry
|
||||||
|
| dm.ExperienceEntry
|
||||||
|
| dm.NormalEntry
|
||||||
|
| dm.PublicationEntry
|
||||||
|
| dm.OneLineEntry
|
||||||
|
| str # TextEntry
|
||||||
|
] = None,
|
||||||
|
section_title: Optional[str] = None,
|
||||||
|
) -> str:
|
||||||
|
"""Template one of the files in the `templates` directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cv (dm.CurriculumVitae): The CV.
|
||||||
|
design (dm.Design): The design.
|
||||||
|
entry (dm.EducationEntry): The education entry.
|
||||||
|
enty_type (Literal["EducationEntry", "ExperienceEntry", "NormalEntry", "PublicationEntry", "OneLineEntry", "TextEntry"]): The type of the entry.
|
||||||
|
environment (jinja2.Environment): The Jinja2 environment.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The rendered education entry.
|
||||||
|
"""
|
||||||
|
education_entry_template = self.environment.get_template(
|
||||||
|
f"{self.design.theme}/{template_name}.j2.tex"
|
||||||
|
)
|
||||||
|
|
||||||
|
# loop through the entry attributes and make them "" if they are None:
|
||||||
|
if entry is not None and not isinstance(entry, str):
|
||||||
|
for key, value in entry.model_dump().items():
|
||||||
|
if value is None:
|
||||||
|
try:
|
||||||
|
entry.__setattr__(key, "")
|
||||||
|
except ValueError:
|
||||||
|
# then it means it's a computed property, can be ignored
|
||||||
|
pass
|
||||||
|
|
||||||
|
latex_code = education_entry_template.render(
|
||||||
|
cv=self.cv,
|
||||||
|
design=self.design,
|
||||||
|
entry=entry,
|
||||||
|
section_title=section_title,
|
||||||
|
today=Date.today().strftime("%B %Y"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return latex_code
|
||||||
|
|
||||||
|
def get_latex_code(self):
|
||||||
|
main_template = self.environment.get_template("main.j2.tex")
|
||||||
|
latex_code = main_template.render(
|
||||||
|
header=self.header,
|
||||||
|
preamble=self.preamble,
|
||||||
|
sections=self.sections,
|
||||||
|
)
|
||||||
|
return latex_code
|
||||||
|
|
||||||
|
|
||||||
def markdown_to_latex(markdown_string: str) -> str:
|
def markdown_to_latex(markdown_string: str) -> str:
|
||||||
"""Convert a markdown string to LaTeX.
|
"""Convert a markdown string to LaTeX.
|
||||||
|
|
||||||
|
@ -264,7 +356,7 @@ def setup_theme_environment(theme_name: str) -> jinja2.Environment:
|
||||||
"""
|
"""
|
||||||
# create a Jinja2 environment:
|
# create a Jinja2 environment:
|
||||||
environment = jinja2.Environment(
|
environment = jinja2.Environment(
|
||||||
loader=jinja2.PackageLoader("rendercv", os.path.join("themes", theme_name)),
|
loader=jinja2.PackageLoader("rendercv", os.path.join("themes")),
|
||||||
trim_blocks=True,
|
trim_blocks=True,
|
||||||
lstrip_blocks=True,
|
lstrip_blocks=True,
|
||||||
)
|
)
|
||||||
|
@ -293,112 +385,22 @@ def setup_theme_environment(theme_name: str) -> jinja2.Environment:
|
||||||
return environment
|
return environment
|
||||||
|
|
||||||
|
|
||||||
def template(
|
|
||||||
cv: dm.CurriculumVitae,
|
|
||||||
design: dm.Design,
|
|
||||||
template_name: Literal[
|
|
||||||
"EducationEntry",
|
|
||||||
"ExperienceEntry",
|
|
||||||
"NormalEntry",
|
|
||||||
"PublicationEntry",
|
|
||||||
"OneLineEntry",
|
|
||||||
"TextEntry",
|
|
||||||
"Header",
|
|
||||||
"Preamble",
|
|
||||||
"SectionTitle",
|
|
||||||
],
|
|
||||||
environment: jinja2.Environment,
|
|
||||||
entry: Optional[
|
|
||||||
dm.EducationEntry
|
|
||||||
| dm.ExperienceEntry
|
|
||||||
| dm.NormalEntry
|
|
||||||
| dm.PublicationEntry
|
|
||||||
| dm.OneLineEntry
|
|
||||||
| str # TextEntry
|
|
||||||
] = None,
|
|
||||||
section_title: Optional[str] = None,
|
|
||||||
) -> str:
|
|
||||||
"""Template one of the files in the `templates` directory.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cv (dm.CurriculumVitae): The CV.
|
|
||||||
design (dm.Design): The design.
|
|
||||||
entry (dm.EducationEntry): The education entry.
|
|
||||||
enty_type (Literal["EducationEntry", "ExperienceEntry", "NormalEntry", "PublicationEntry", "OneLineEntry", "TextEntry"]): The type of the entry.
|
|
||||||
environment (jinja2.Environment): The Jinja2 environment.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: The rendered education entry.
|
|
||||||
"""
|
|
||||||
education_entry_template = environment.get_template(f"{template_name}.j2.tex")
|
|
||||||
|
|
||||||
latex_code = education_entry_template.render(
|
|
||||||
cv=cv,
|
|
||||||
design=design,
|
|
||||||
entry=entry,
|
|
||||||
section_title=section_title,
|
|
||||||
today=Date.today().strftime("%B %Y"),
|
|
||||||
)
|
|
||||||
|
|
||||||
return latex_code
|
|
||||||
|
|
||||||
|
|
||||||
def generate_the_latex_file(
|
def generate_the_latex_file(
|
||||||
rendercv_data_model: dm.RenderCVDataModel, output_file_path: str
|
rendercv_data_model: dm.RenderCVDataModel, output_file_path: str
|
||||||
) -> str:
|
) -> str:
|
||||||
""" """
|
""" """
|
||||||
environment = setup_theme_environment(rendercv_data_model.design.theme)
|
environment = setup_theme_environment(rendercv_data_model.design.theme)
|
||||||
|
latex_file_object = LaTeXFile(
|
||||||
# render the preamble:
|
rendercv_data_model.cv,
|
||||||
preamble = template(
|
rendercv_data_model.design,
|
||||||
cv=rendercv_data_model.cv,
|
environment,
|
||||||
design=rendercv_data_model.design,
|
output_file_path,
|
||||||
entry=None,
|
|
||||||
template_name="Preamble",
|
|
||||||
environment=environment,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
latex_file = preamble + "\n\\begin{document}\n"
|
with open(output_file_path, "w") as latex_file:
|
||||||
|
latex_file.write(latex_file_object.get_latex_code())
|
||||||
|
|
||||||
# render the header:
|
return latex_file_object.get_latex_code()
|
||||||
header = template(
|
|
||||||
cv=rendercv_data_model.cv,
|
|
||||||
design=rendercv_data_model.design,
|
|
||||||
template_name="Header",
|
|
||||||
environment=environment,
|
|
||||||
)
|
|
||||||
|
|
||||||
latex_file = latex_file + header + "\n"
|
|
||||||
|
|
||||||
# render the sections:
|
|
||||||
for section in rendercv_data_model.cv.sections:
|
|
||||||
title = template(
|
|
||||||
cv=rendercv_data_model.cv,
|
|
||||||
design=rendercv_data_model.design,
|
|
||||||
template_name="SectionTitle",
|
|
||||||
environment=environment,
|
|
||||||
section_title=section.title,
|
|
||||||
)
|
|
||||||
|
|
||||||
latex_file = latex_file + title + "\n"
|
|
||||||
|
|
||||||
for entry in section.entries:
|
|
||||||
entry = template(
|
|
||||||
cv=rendercv_data_model.cv,
|
|
||||||
design=rendercv_data_model.design,
|
|
||||||
template_name=section.entry_type,
|
|
||||||
environment=environment,
|
|
||||||
entry=entry,
|
|
||||||
)
|
|
||||||
latex_file = latex_file + entry + "\n"
|
|
||||||
|
|
||||||
latex_file = latex_file + "\\end{document}\n"
|
|
||||||
|
|
||||||
# write the LaTeX file:
|
|
||||||
with open(output_file_path, "w") as file:
|
|
||||||
file.write(latex_file)
|
|
||||||
|
|
||||||
return latex_file
|
|
||||||
|
|
||||||
|
|
||||||
def render_the_latex_file(latex_file_path: str) -> str:
|
def render_the_latex_file(latex_file_path: str) -> str:
|
||||||
|
@ -420,28 +422,17 @@ def render_the_latex_file(latex_file_path: str) -> str:
|
||||||
output_file_name = latex_file_name.replace(".tex", ".pdf")
|
output_file_name = latex_file_name.replace(".tex", ".pdf")
|
||||||
output_file_path = os.path.join(os.path.dirname(latex_file_path), output_file_name)
|
output_file_path = os.path.join(os.path.dirname(latex_file_path), output_file_name)
|
||||||
|
|
||||||
|
tinytex_binaries = files("rendercv").joinpath("tinytex-release", "TinyTeX", "bin")
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
# Windows
|
# Windows
|
||||||
executable = str(
|
executable = str(tinytex_binaries.joinpath("windows", "lualatex.exe"))
|
||||||
files("rendercv").joinpath(
|
|
||||||
"vendor", "TinyTeX", "bin", "windows", "lualatex.exe"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif sys.platform == "linux" or sys.platform == "linux2":
|
elif sys.platform == "linux" or sys.platform == "linux2":
|
||||||
# Linux
|
# Linux
|
||||||
executable = str(
|
executable = str(tinytex_binaries.joinpath("x86_64-linux", "lualatex"))
|
||||||
files("rendercv").joinpath(
|
|
||||||
"vendor", "TinyTeX", "bin", "x86_64-linux", "lualatex"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
# MacOS
|
# MacOS
|
||||||
executable = str(
|
executable = str(tinytex_binaries.joinpath("universal-darwin", "lualatex"))
|
||||||
files("rendercv").joinpath(
|
|
||||||
"vendor", "TinyTeX", "bin", "universal-darwin", "lualatex"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
raise OSError(f"Unknown OS {os.name}!")
|
raise OSError(f"Unknown OS {os.name}!")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue