rendercv/docs/update_entry_figures.py

255 lines
8.5 KiB
Python
Raw Permalink Normal View History

2024-06-19 11:34:05 +00:00
"""This script generates the example entry figures and creates an environment for
documentation templates using `mkdocs-macros-plugin`. For example, the content of the
example entries found in
"[Structure of the YAML Input File](https://docs.rendercv.com/user_guide/structure_of_the_yaml_input_file/)"
are coming from this script.
"""
2024-02-23 17:58:53 +00:00
import io
2024-06-24 13:08:07 +00:00
import pathlib
2024-02-24 21:23:07 +00:00
import shutil
2024-06-24 13:08:07 +00:00
import tempfile
2024-02-23 17:58:53 +00:00
from typing import Any
2024-06-19 11:34:05 +00:00
import pdfCropMargins
2024-06-24 13:08:07 +00:00
import ruamel.yaml
2024-02-23 17:58:53 +00:00
2024-06-17 18:57:50 +00:00
import rendercv.data_models as dm
import rendercv.renderer as r
repository_root = pathlib.Path(__file__).parent.parent
rendercv_path = repository_root / "rendercv"
2024-03-17 19:31:12 +00:00
image_assets_directory = pathlib.Path(__file__).parent / "assets" / "images"
2024-02-23 17:58:53 +00:00
# The entries below will be pasted into the documentation as YAML, and their
# corresponding figures will be generated with this script.
education_entry = {
"institution": "Boğaziçi University",
"location": "Istanbul, Turkey",
"degree": "BS",
"area": "Mechanical Engineering",
"start_date": "2015-09",
"end_date": "2020-06",
"highlights": [
"GPA: 3.24/4.00 ([Transcript](https://example.com))",
"Awards: Dean's Honor List, Sportsperson of the Year",
],
}
experience_entry = {
"company": "Some Company",
"location": "TX, USA",
"position": "Software Engineer",
"start_date": "2020-07",
"end_date": "2021-08-12",
"highlights": [
(
2024-02-27 18:46:53 +00:00
"Developed an [IOS application](https://example.com) that has received"
2024-02-23 17:58:53 +00:00
" more than **100,000 downloads**."
),
"Managed a team of **5** engineers.",
],
}
normal_entry = {
"name": "Some Project",
"date": "2021-09",
"highlights": [
"Developed a web application with **React** and **Django**.",
"Implemented a **RESTful API**",
],
}
publication_entry = {
"title": (
"Magneto-Thermal Thin Shell Approximation for 3D Finite Element Analysis of"
" No-Insulation Coils"
),
2024-03-09 16:59:14 +00:00
"authors": ["J. Doe", "***H. Tom***", "S. Doe", "A. Andsurname"],
2024-02-27 18:46:53 +00:00
"date": "2021-12-08",
2024-02-23 17:58:53 +00:00
"journal": "IEEE Transactions on Applied Superconductivity",
"doi": "10.1109/TASC.2023.3340648",
}
one_line_entry = {
2024-03-10 17:14:06 +00:00
"label": "Programming",
2024-02-23 17:58:53 +00:00
"details": "Python, C++, JavaScript, MATLAB",
}
2024-03-10 18:11:06 +00:00
bullet_entry = {
"bullet": "This is a bullet entry.",
}
2024-02-23 17:58:53 +00:00
text_entry = (
"This is a *TextEntry*. It is only a text and can be useful for sections like"
" **Summary**. To showcase the TextEntry completely, this sentence is added, but it"
" doesn't contain any information."
)
def dictionary_to_yaml(dictionary: dict[str, Any]):
"""Converts a dictionary to a YAML string.
Args:
dictionary (dict[str, Any]): The dictionary to be converted to YAML.
Returns:
str: The YAML string.
"""
yaml_object = ruamel.yaml.YAML()
2024-02-24 15:38:58 +00:00
yaml_object.width = 60
yaml_object.indent(mapping=2, sequence=4, offset=2)
2024-02-23 17:58:53 +00:00
with io.StringIO() as string_stream:
yaml_object.dump(dictionary, string_stream)
yaml_string = string_stream.getvalue()
return yaml_string
def define_env(env):
# see https://mkdocs-macros-plugin.readthedocs.io/en/latest/macros/
entries = [
"education_entry",
"experience_entry",
"normal_entry",
"publication_entry",
"one_line_entry",
2024-03-10 18:11:06 +00:00
"bullet_entry",
2024-02-23 17:58:53 +00:00
"text_entry",
]
entries_showcase = dict()
for entry in entries:
proper_entry_name = entry.replace("_", " ").title()
entries_showcase[proper_entry_name] = {
"yaml": dictionary_to_yaml(eval(entry)),
"figures": [
{
2024-05-18 21:02:14 +00:00
"path": f"../assets/images/{theme}/{entry}.png",
2024-02-23 17:58:53 +00:00
"alt_text": f"{proper_entry_name} in {theme}",
"theme": theme,
}
for theme in dm.available_themes
],
}
env.variables["showcase_entries"] = entries_showcase
# for theme templates reference docs:
themes_path = rendercv_path / "themes"
theme_templates = dict()
for theme in dm.available_themes:
theme_templates[theme] = dict()
for theme_file in themes_path.glob(f"{theme}/*.tex"):
theme_templates[theme][
theme_file.stem.replace(".j2", "")
] = theme_file.read_text()
env.variables["theme_templates"] = theme_templates
2024-05-18 21:02:14 +00:00
# available themes strings (put available themes between ``)
themes = [f"`{theme}`" for theme in dm.available_themes]
env.variables["available_themes"] = ", ".join(themes)
# available social networks strings (put available social networks between ``)
social_networks = [
f"`{social_network}`" for social_network in dm.available_social_networks
]
env.variables["available_social_networks"] = ", ".join(social_networks)
2024-02-23 17:58:53 +00:00
2024-02-24 21:23:07 +00:00
def generate_entry_figures():
"""Generate an image for each entry type and theme."""
2024-02-23 17:58:53 +00:00
# Generate PDF figures for each entry type and theme
entries = {
2024-04-07 17:44:07 +00:00
"education_entry": dm.EducationEntry(**education_entry),
"experience_entry": dm.ExperienceEntry(**experience_entry),
"normal_entry": dm.NormalEntry(**normal_entry),
"publication_entry": dm.PublicationEntry(**publication_entry),
"one_line_entry": dm.OneLineEntry(**one_line_entry),
"text_entry": f"{text_entry}",
2024-03-10 18:11:06 +00:00
"bullet_entry": dm.BulletEntry(**bullet_entry),
2024-02-23 17:58:53 +00:00
}
themes = dm.available_themes
with tempfile.TemporaryDirectory() as temporary_directory:
# create a temporary directory:
temporary_directory_path = pathlib.Path(temporary_directory)
for theme in themes:
design_dictionary = {
"theme": theme,
"disable_page_numbering": True,
"disable_last_updated_date": True,
}
if theme == "moderncv":
# moderncv theme does not support these options:
del design_dictionary["disable_page_numbering"]
del design_dictionary["disable_last_updated_date"]
2024-02-23 17:58:53 +00:00
for entry_type, entry in entries.items():
# Create the data model with only one section and one entry
data_model = dm.RenderCVDataModel(
**{
"cv": dm.CurriculumVitae(sections={entry_type: [entry]}),
"design": design_dictionary,
}
)
# Render:
latex_file_path = r.generate_latex_file_and_copy_theme_files(
data_model, temporary_directory_path
)
pdf_file_path = r.latex_to_pdf(latex_file_path)
# Prepare the output directory and file path:
2024-03-17 19:31:12 +00:00
output_directory = image_assets_directory / theme
2024-02-23 17:58:53 +00:00
output_directory.mkdir(parents=True, exist_ok=True)
output_pdf_file_path = output_directory / f"{entry_type}.pdf"
# Remove the file if it exists:
if output_pdf_file_path.exists():
output_pdf_file_path.unlink()
# Crop the margins
pdfCropMargins.crop(
argv_list=[
"-p4",
"100",
"0",
"100",
"0",
"-a4",
"0",
"-30",
"0",
"-30",
"-o",
str(output_pdf_file_path.absolute()),
str(pdf_file_path.absolute()),
]
)
# Convert pdf to an image
png_file_path = r.pdf_to_pngs(output_pdf_file_path)[0]
desired_png_file_path = output_pdf_file_path.with_suffix(".png")
2024-02-23 17:58:53 +00:00
# If the image exists, remove it
if desired_png_file_path.exists():
desired_png_file_path.unlink()
2024-02-23 17:58:53 +00:00
# Move the image to the desired location
png_file_path.rename(desired_png_file_path)
2024-02-23 17:58:53 +00:00
# Remove the pdf file
output_pdf_file_path.unlink()
2024-02-24 21:23:07 +00:00
2024-03-17 19:31:12 +00:00
def update_index():
"""Update the index.md file by copying the README.md file."""
index_file_path = repository_root / "docs" / "index.md"
readme_file_path = repository_root / "README.md"
shutil.copy(readme_file_path, index_file_path)
2024-02-24 21:23:07 +00:00
if __name__ == "__main__":
generate_entry_figures()
2024-06-19 11:34:05 +00:00
print("Entry figures generated successfully.")