Massive Refactor: Architecture Redesign and Technical Debt Cleanup (#528)

* Rename `data` folder with schema

* Start refactoring data models

* Work on entry models

* Keep working on entries

* Keep working on data models

* Push old data files

* Keep working on data models

* First draft of schema.cv

* Keep working on schema

* Keep working on schema

* Improve schema.models

* Keep working on rendercv.schema

* Work on schema.design

* Keep working on rendercv.schema

* Complete variant_class_generator

* Keep working rendercv.schema

* Keep working on rendercv.schema

* Final touches to rendercv.schema

* Improve json schema descriptions in rendercv.schema

* Start working on rendercv.schema tests

* Keep implementing rendercv.schema tests

* Add more tests for rendercv.schema

* Improve rendercv.schema

* Improve docstrings and comments in rendercv.schema

* Implement better pydantic error handling in `rendercv.schema`

* Improve variant class system

* Fix rendercv.schema tests

* Start working on rendercv.templater

* Update template names

* Switching to new rendercv typst template soon

* Work on new templater

* Rename renderer with renderer_old

* Don't use utils in rendercv.schema

* Complete connections

* Update renderer folder structure

* Work on new renderer

* Work on new renderer

* Date processing on new renderer

* Improve date processing, support multiple emails, phones, and websites

* Improve markdown to Typst

* Complete entry template processing

* Time span computation in new renderer

* Better entry templates

* Setup new templates

* Improve rendercv.schema

* Start adding tests for rendercv.renderer

* New markdown parser!

* Improve markdown to typst conversion

* Finalize markdown parser

* Add new test files for rendercv.renderer

* Fix cv and connections

* Add connections test

* Improve connection tests

* Improve entry templates

* Add model processor tests

* Improve templater

* Rename old folders

* Improve schema

* Add file generation logic to renderer

* Fix naming issues

* Fix schema tests

* Add path type tests

* Add font family and typst dimension type tests

* Rename old tests

* Fix design tests

* Start integration testing of renderer

* Improve entry tempates

* Handle nested highlights properly

* Finalize Typst preamble template

* Start working on new CLI

* Remove old test files

* Implement override dictionary in new schema

* Start working on new CLI

* Better prints on render command

* New structure

* New render printer

* Add all the commands to new CLI

* Work on new command in new cli

* Improve new command

* Add error handler to new cli

* Work on create theme command

* Complete create theme command

* Remove old source files

* Improve exceptions

* Create new docs

* Add writing tests guide

* Fix cli printer and write tests

* Test copy templates

* Add app tests

* Bring back accidentally removed files

* Imporve cli and tests

* Fix path issues

* Improve

* Improve

* Add reference file comparison tests

* Fix path resolver

* Start working on test_pdf_png

* Implement comparison of multiple files (png)

* Start testing typst

* Fix templating issues

* Fix header and entry templates issues

* Implement short second rows

* Fix date issues

* Fix nested bullets and add summary

* Update testdata

* Implement footer

* Update testdata

* Reimagined design and locale schema, first iteration

* Reimagined design and locale second iteration

* Update design and locale schemas

* Adapt templater to the new design and locale

* Fix tests

* Update lib.typ and testdata for the new locale and design

* Implement proper tests with all combinations of entries

* Remove some docstrings

* fix connections logic

* Improve

* Start working on examples

* Update testdata

* Fix long second row issue

* fix templating issues

* Fix lib.typ issues

* Update testdata

* Fix clean_trailing_parts

* Update test cv

* update test cv

* Update theme defaults

* update schema and fix moderncv

* Fix moderncv issues

* Update testdata

* Update testdata and examples

* Fix issues about photo

* Fix typst photo path issues

* improve entry templates from yaml

* add new locale

* Rename writing tests doc

* Update writing tests

* Improve tests

* Add more cli tests

* Increase test coverage

* Rename variant pydantic model generator

* Improve tests

* Update testdata and improve tests

* Format, fix pre-commit errors

* Fix scripts and update entry figures

* Improve tests

* Write docstrings of schema

* Write schema docstrings

* Setup api reference

* Start working on new docs

* Work on docs

* Improve progress panel of render command

* Finalize new docs index

* Complete CLI docs

* Work on YAML input structure page

* Finalize user guide

* Start working on developer guide

* Improve api reference

* Improve developer guide

* Improve developer guide

* Improve developer gide

* Improve developer guide

* Improve developer guide

* Update developer guide

* Improve developer guide

* Improve developer guide

* Improve developer guide

* Developer guide first draft

* update developer guide

* Update examples

* Update testdata

* Handle wrong installation (rendercv instead of rendercv[full])

* Remove unnecessary files

* Write set up vs code page

* Update README.md

* Change docs description

* Compress design options gif

* minor updates

* Polish all the json schema descriptions

* Update testdata and examples

* Remove some emdashed from docs

* Add whatsapp support

* Add TestEscapeTypstCharacters to tests

* Implement custom connections

* Add page break before sections feature

* Revert page break before sections feature

* Rebase to main

* Fix social network tests, update schema
This commit is contained in:
Sina Atalay
2025-12-09 17:03:56 +03:00
committed by GitHub
parent a45537deb4
commit 5cc5fbdf9e
613 changed files with 479343 additions and 120866 deletions

View File

@@ -19,7 +19,7 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -28,7 +28,7 @@ jobs:
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
run: just install
- name: Create executable
run: just create-executable

View File

@@ -26,7 +26,7 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -35,7 +35,7 @@ jobs:
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
run: just install
- name: Build docs
run: just build-docs

View File

@@ -22,7 +22,7 @@ jobs:
- update_files
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -96,8 +96,8 @@ jobs:
- name: Upload package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
publish_to_dockerhub_and_ghcr:
name: Push Docker image to Docker Hub and GitHub Container Registry
publish_docker_to_ghcr:
name: Push Docker image to GitHub Container Registry
runs-on: ubuntu-latest
needs:
- publish_to_pypi
@@ -108,7 +108,7 @@ jobs:
id-token: write
steps:
- name: Check out the repo
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3

View File

@@ -20,25 +20,23 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu, windows, macos]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.12", "3.13", "3.14"]
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "${{ matrix.python-version}}"
- name: Install just
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
run: just install
- name: Test
run: just test-with-coverage
run: just test-coverage
- name: Rename the coverage file
run: mv .coverage .coverage.${{ matrix.python-version }}.${{ matrix.os }}
@@ -51,14 +49,12 @@ jobs:
path: .coverage.${{ matrix.python-version }}.${{ matrix.os }}
report-coverage:
# Run only if the workflow was triggered by a push event
if: github.event_name == 'push'
name: Generate the coverage report
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Download coverage files
uses: actions/download-artifact@v6
@@ -71,7 +67,7 @@ jobs:
uses: astral-sh/setup-uv@v7
- name: Install the project
run: uv sync --locked --all-extras --all-groups
run: just install
- name: Install just
uses: taiki-e/install-action@just
@@ -86,6 +82,6 @@ jobs:
run: uv tool run smokeshow==0.4.0 upload ./htmlcov
env:
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 20
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 90
SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}

View File

@@ -14,7 +14,7 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -23,7 +23,7 @@ jobs:
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
run: just install
- name: Set Git credentials
run: |

8
.gitignore vendored
View File

@@ -165,10 +165,7 @@ cython_debug/
# VSCode
.vscode/
# Personal CVs
*_CV.yaml
*_cv.py
*_CV.typ
# RenderCV output
rendercv_output/
# Include reference files
@@ -190,3 +187,6 @@ render_command.prof
# Executables:
bin/
# Coverage:
coverage.md

View File

@@ -1,13 +1,16 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.2
rev: v0.14.8
hooks:
- id: ruff
- repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.407
hooks:
- id: pyright
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
- repo: https://github.com/adrienverge/yamllint
rev: v1.37.1
hooks:
- id: yamllint
args:
- --skip=src/rendercv/schema/models/locale/other_locales/*
- --exclude-file=schema.json

View File

@@ -1,3 +0,0 @@
extends: default
rules:
line-length: disable

View File

@@ -1,31 +1,49 @@
# syntax=docker/dockerfile:1.7
# Use a Python image with uv pre-installed
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
ARG UID=1000
ARG GID=1000
# Install the project into `/app`
WORKDIR /app
FROM python:3.13-slim AS builder
# Enable bytecode compilation
ENV UV_COMPILE_BYTECODE=1
WORKDIR /build
# Copy from the cache instead of linking since it's a mounted volume
ENV UV_LINK_MODE=copy
RUN python -m venv /opt/rendercv-venv \
&& /opt/rendercv-venv/bin/pip install --no-cache-dir --upgrade pip \
&& /opt/rendercv-venv/bin/pip install --no-cache-dir "rendercv[full]"
# Install the project's dependencies using the lockfile and settings
# This layer is cached separately from the project code for faster rebuilds
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-install-project --no-editable --extra full
FROM python:3.13-slim
# Then, add the rest of the project source code and install it
# Installing separately from its dependencies allows optimal layer caching
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-editable --extra full
ARG UID
ARG GID
# Final stage
FROM python:3.12-slim-bookworm
RUN groupadd --gid ${GID} rendercv \
&& useradd --uid ${UID} --gid ${GID} --create-home rendercv
# Setup a non-root user
RUN groupadd --system --gid 999 rendercv \
&& useradd --system --gid 999 --uid 999 --create-home rendercv
COPY --from=builder /opt/rendercv-venv /opt/rendercv-venv
# Set working directory
WORKDIR /app
ENV PATH="/opt/rendercv-venv/bin:${PATH}"
# Copy the virtual environment from the builder stage
COPY --from=builder --chown=rendercv:rendercv /app/.venv /app/.venv
WORKDIR /rendercv
# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"
USER rendercv:rendercv
# Use the non-root user to run our application
USER rendercv
ENTRYPOINT ["/bin/bash"]
# Set the entrypoint to the rendercv CLI (installed via pyproject.toml entry point)
ENTRYPOINT ["rendercv"]
# Default command shows help
CMD ["--help"]

157
README.md
View File

@@ -1,7 +1,7 @@
<div align="center">
<h1>RenderCV</h1>
_The engine of the [RenderCV App](https://rendercv.com)_
_CV/resume generator for academics and engineers_
[![test](https://github.com/rendercv/rendercv/actions/workflows/test.yaml/badge.svg?branch=main)](https://github.com/rendercv/rendercv/actions/workflows/test.yaml)
[![coverage](https://coverage-badge.samuelcolvin.workers.dev/rendercv/rendercv.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/rendercv/rendercv)
@@ -11,68 +11,149 @@ _The engine of the [RenderCV App](https://rendercv.com)_
</div>
RenderCV engine is a Typst-based Python package with a command-line interface (CLI) that allows you to version-control your CV/resume as source code. It reads a CV written in a YAML file with Markdown syntax, converts it into a [Typst](https://typst.app) code, and generates a PDF.
Write your CV or resume as YAML, then run RenderCV,
RenderCV engine's focus is to provide these three features:
```bash
rendercv render John_Doe_CV.yaml
```
- **Content-first approach:** Users should be able to focus on the content instead of worrying about the formatting.
- **A mechanism to version-control a CV's content and design separately:** The content and design of a CV are separate issues and they should be treated separately.
- **Robustness:** A PDF should be delivered if there aren't any errors. If errors exist, they should be clearly explained along with solutions.
and get a PDF with perfect typography. No template wrestling. No broken layouts. Consistent spacing, every time.
With RenderCV, you can:
It takes a YAML file that looks like this:
- Version-control your CV — it's just text.
- Focus on content — don't wory about the formatting.
- Get perfect typography — kerning, spacing, hierarchy, all handled. No design skills required.
A YAML file like this:
```yaml
cv:
name: John Doe
location: Location
email: john.doe@example.com
phone: tel:+1-609-999-9995
location: San Francisco, CA
email: john.doe@email.com
website: https://rendercv.com/
social_networks:
- network: LinkedIn
username: john.doe
username: rendercv
- network: GitHub
username: john.doe
username: rendercv
sections:
welcome_to_RenderCV!:
- '[RenderCV](https://rendercv.com) is a Typst-based CV
framework designed for academics and engineers, with Markdown
syntax support.'
- Each section title is arbitrary. Each section contains
a list of entries, and there are 7 different entry types
to choose from.
Welcome to RenderCV:
- RenderCV reads a CV written in a YAML file, and generates a PDF with professional typography.
- See the [documentation](https://docs.rendercv.com) for more details.
education:
- institution: Stanford University
- institution: Princeton University
area: Computer Science
degree: PhD
location: Stanford, CA, USA
start_date: 2023-09
end_date: present
date:
start_date: 2018-09
end_date: 2023-05
location: Princeton, NJ
summary:
highlights:
- Working on the optimization of autonomous vehicles
in urban environments
- "Thesis: Efficient Neural Architecture Search for Resource-Constrained Deployment"
- "Advisor: Prof. Sanjeev Arora"
- NSF Graduate Research Fellowship, Siebel Scholar (Class of 2022)
...
```
Then, it produces one of these PDFs with its corresponding Typst file, Markdown file, HTML file, and images as PNGs. Click on the images below to preview PDF files.
becomes one of these PDFs. Click on the images to preview.
| [![Classic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/classic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ClassicTheme_CV.pdf) | [![Sb2nov Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/sb2nov.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_Sb2novTheme_CV.pdf) |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [![Moderncv Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/moderncv.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ModerncvTheme_CV.pdf) | [![Engineeringresumes Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringresumes.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringresumesTheme_CV.pdf) |
| [![Engineeringclassic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringclassic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringclassicTheme_CV.pdf) | ![Custom themes can be added.](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/customtheme.png) |
| [![Classic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/classic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ClassicTheme_CV.pdf) | [![Engineeringresumes Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringresumes.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringresumesTheme_CV.pdf) | [![Sb2nov Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/sb2nov.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_Sb2novTheme_CV.pdf) |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [![Moderncv Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/moderncv.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ModerncvTheme_CV.pdf) | [![Engineeringclassic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringclassic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringclassicTheme_CV.pdf) | ![Custom themes can be added.](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/customtheme.png) |
RenderCV comes with a JSON Schema so that the YAML input file can be filled out interactively.
![JSON Schema of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/schema.gif)
## JSON Schema
## Getting Started
RenderCV's JSON Schema lets you fill out the YAML interactively, with autocompletion and inline documentation.
RenderCV engine is very easy to install (`pip install "rendercv[full]"`) and easy to use (`rendercv new "John Doe"`). Follow the [user guide](https://docs.rendercv.com/user_guide) to get started.
![JSON Schema of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/json_schema.gif)
## Motivation
We are developing a [purpose-built app](https://rendercv.com) for writing CVs and resumes that will be available on mobile and web. This Python project is the foundation of that app. Check out [our blog post](https://rendercv.com/introducing-rendercv/) to learn more about why one would use such an app.
## Extensive Design Options
## Contributing
You have full control over every detail.
All contributions to RenderCV are welcome! To get started, please read [the developer guide](https://docs.rendercv.com/developer_guide).
```yaml
design:
theme: classic
page:
size: us-letter
top_margin: 0.7in
bottom_margin: 0.7in
left_margin: 0.7in
right_margin: 0.7in
show_footer: true
show_top_note: true
colors:
body: rgb(0, 0, 0)
name: rgb(0, 79, 144)
headline: rgb(0, 79, 144)
connections: rgb(0, 79, 144)
section_titles: rgb(0, 79, 144)
links: rgb(0, 79, 144)
footer: rgb(128, 128, 128)
top_note: rgb(128, 128, 128)
typography:
line_spacing: 0.6em
alignment: justified
date_and_location_column_alignment: right
font_family: Source Sans 3
# ...and more
```
![Design Options of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/design_options.gif)
> [!TIP]
> Want to set up a live preview environment like the one shown above? See [how to set up VS Code for RenderCV](https://docs.rendercv.com/user_guide/how_to/set_up_vs_code_for_rendercv.md).
## Strict Validation
No surprises. If something's wrong, you'll know exactly what and where. If it's valid, you get a perfect PDF.
![Strict Validation Feature of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/validation.gif)
## Any Language
Fill out the locale field for your language.
```yaml
locale:
language: english
last_updated: Last updated in
month: month
months: months
year: year
years: years
present: present
month_abbreviations:
- Jan
- Feb
- Mar
...
```
## Get Started
Install RenderCV (Requires Python 3.12+):
```
pip install "rendercv[full]"
```
Create a new CV yaml file:
```
rendercv new "John Doe"
```
Edit the YAML, then render:
```
rendercv render "John_Doe_CV.yaml"
```
For more details, see the [user guide](https://docs.rendercv.com/user_guide/index.md).

View File

@@ -0,0 +1,37 @@
from pathlib import Path
import mkdocs_gen_files
nav = mkdocs_gen_files.Nav()
repository_root = Path(__file__).parent.parent.parent
api_reference = repository_root / "docs" / "api_reference"
src_rendercv = repository_root / "src" / "rendercv"
nav[("src", "rendercv")] = "index.md"
# Process each Python file in the objects directory
for path in sorted(src_rendercv.rglob("*.py")):
# Skip __init__.py files and __main__.py files
if path.name in ("__init__.py", "__main__.py"):
continue
# Get the relative path from the objects directory
module_path = path.relative_to(src_rendercv).with_suffix("")
doc_path = module_path.with_suffix(".md")
parts = (f"rendercv.{module_path.parts[0]}", *module_path.parts[1:])
# Add to navigation
nav[("src", *parts)] = doc_path.as_posix()
# Generate the documentation page
with mkdocs_gen_files.open(f"api_reference/{doc_path}", "w") as fd:
module_ident = "rendercv." + ".".join(module_path.parts)
fd.write(f"::: {module_ident}\n")
# Set the edit path to the actual source file
# mkdocs_gen_files.set_edit_path(full_doc_path, full_doc_path.relative_to(docs_path))
# Write the navigation file
with mkdocs_gen_files.open("api_reference/SUMMARY.md", "w") as nav_file:
nav_file.writelines(nav.build_literate_nav())

View File

@@ -0,0 +1,7 @@
# API Reference
RenderCV is a CLI application, not a library. Its internal API is not guaranteed to be stable and may change without notice. However, for those who wish to use RenderCV programmatically in Python scripts, the complete API reference is provided here.
::: rendercv
options:
heading_level: 2

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 KiB

After

Width:  |  Height:  |  Size: 731 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 MiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 KiB

After

Width:  |  Height:  |  Size: 759 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 KiB

After

Width:  |  Height:  |  Size: 752 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 MiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 698 KiB

After

Width:  |  Height:  |  Size: 681 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 KiB

After

Width:  |  Height:  |  Size: 710 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 MiB

View File

@@ -1,5 +1,7 @@
---
toc_depth: 1
hide:
- navigation
---
# Changelog
@@ -92,8 +94,8 @@ RenderCV has transitioned from using $\LaTeX$ to Typst. RenderCV is now much fas
### Changed
- $\LaTeX$ has been replaced with Typst.
- The `design` field has been changed completely. See the [documentation](https://docs.rendercv.com/user_guide/structure_of_the_yaml_input_file/#design-field) for details.
- The `locale_catalog` field has been renamed to `locale`, and some fields have been moved from `design` to `locale`. See the [documentation](https://docs.rendercv.com/user_guide/structure_of_the_yaml_input_file/#locale-field) for details.
- The `design` field has been changed completely.
- The `locale_catalog` field has been renamed to `locale`, and some fields have been moved from `design` to `locale`.
- The `moderncv` theme's header has been changed.
@@ -167,7 +169,7 @@ RenderCV has transitioned from using $\LaTeX$ to Typst. RenderCV is now much fas
### Added
- `rendercv_settings` field has been added to the YAML input file. For details, see [here](../user_guide/structure_of_the_yaml_input_file.md#rendercv_settings-field). It will be extended in the future.
- `rendercv_settings` field has been added to the YAML input file. It will be extended in the future.
## [1.13] - July 23, 2024
@@ -176,8 +178,8 @@ RenderCV has transitioned from using $\LaTeX$ to Typst. RenderCV is now much fas
### Added
- Arbitrary keys are now allowed in the `cv` field. For details, see [here](../user_guide/structure_of_the_yaml_input_file.md#using-arbitrary-keys).
- Two new fields have been added to the `locale` field: `phone_number_format` and `date_style` ([#130](https://github.com/rendercv/rendercv/issues/130)). For details, see [here](../user_guide/structure_of_the_yaml_input_file.md#locale-field).
- Arbitrary keys are now allowed in the `cv` field.
- Two new fields have been added to the `locale` field: `phone_number_format` and `date_style` ([#130](https://github.com/rendercv/rendercv/issues/130)).
### Changed
@@ -195,7 +197,7 @@ RenderCV has transitioned from using $\LaTeX$ to Typst. RenderCV is now much fas
### Added
- Arbitrary keys are now allowed in entry types. Users can use these keys in their templates. For details, see the [documentation](../user_guide/structure_of_the_yaml_input_file.md#using-arbitrary-keys).
- Arbitrary keys are now allowed in entry types. Users can use these keys in their templates.
- The `locale.full_names_of_months` field has been added to the data model ([#111](https://github.com/rendercv/rendercv/issues/111)).
- The `TODAY` placeholder can be used in the `design.page_numbering_style` field now.
@@ -214,7 +216,7 @@ RenderCV has transitioned from using $\LaTeX$ to Typst. RenderCV is now much fas
### Added
- CLI options now have short versions. See the [CLI documentation](https://docs.rendercv.com/user_guide/cli/) for more information.
- CLI options now have short versions.
- CLI now notifies the user when a new version is available ([#89](https://github.com/rendercv/rendercv/issues/89)).
- `Google Scholar` has been added as a social network type ([#85](https://github.com/rendercv/rendercv/issues/85)).
- Two new design options have been added to the `classic`, `sb2nov`, and `engineeringresumes` themes: `separator_between_connections` and `use_icons_for_connections`.
@@ -259,7 +261,7 @@ RenderCV has transitioned from using $\LaTeX$ to Typst. RenderCV is now much fas
### Added
- RenderCV is now a multilingual tool. English strings can be overridden with `locale` section in the YAML input file ([#26](https://github.com/rendercv/rendercv/issues/26), [#20](https://github.com/rendercv/rendercv/pull/20)). See the [documentation](../user_guide/structure_of_the_yaml_input_file.md#locale-field) for more information.
- RenderCV is now a multilingual tool. English strings can be overridden with `locale` section in the YAML input file ([#26](https://github.com/rendercv/rendercv/issues/26), [#20](https://github.com/rendercv/rendercv/pull/20)).
- PNG files for each page can be generated now ([#57](https://github.com/rendercv/rendercv/issues/57)).
- `rendercv new` command now generates Markdown and $\LaTeX$ source files in addition to the YAML input file so that the default templates can be modified easily.
- A new CLI command has been added, `rendercv create-theme`, to allow users to create their own themes easily.

View File

@@ -0,0 +1,57 @@
# Guidelines for Writing Source Code
## Type Annotations
**Every function, variable, and class attribute must be strictly typed. No exceptions.**
Use modern Python 3.12+ syntax:
- Type aliases with `type` statement
- PEP 695 type parameters (`[T]`, `[**P]`)
- Pipe unions (`str | int`, not `Union[str, int]`)
- Proper optional types (`str | None`, not `Optional[str]`)
## Linting and Type Checking
Always run `just check` and `just format` before committing. `just check` must show **zero errors**:
```bash
just format
just check
```
If there's absolutely no alternative, use `# pyright: ignore[errorCode]` or `#NOQA: errorCode` to ignore typing or linting errors.
## Docstrings
Use [Google-style docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings). Include a **"Why" section** and **"Example" section** when it adds value:
```python
def resolve_relative_path(
path: pathlib.Path, info: pydantic.ValidationInfo, must_exist: bool = True
) -> pathlib.Path:
"""Convert relative path to absolute path based on input file location.
Why:
Users reference files like `photo: profile.jpg` relative to their CV
YAML. This validator resolves such paths to absolute form and validates
existence, enabling file access during rendering.
Args:
path: Path to resolve (may be relative or absolute).
info: Validation context containing input file path.
must_exist: Whether to raise error if path doesn't exist.
Returns:
Absolute path.
"""
```
Docstring order:
1. Brief description (one line)
2. Why section (when it adds value)
3. Example section (when it adds value)
4. Args section (mandatory)
5. Returns section (mandatory)
6. Raises section (mandatory if function raises exceptions)

View File

@@ -0,0 +1,145 @@
# Guidelines for Writing Tests
## File Structure
Each test file tests all classes and functions in its corresponding source file. The structure mirrors `src/rendercv/`:
```
src/rendercv/renderer/templater/date.py
→ tests/renderer/templater/test_date.py
(tests all functions and classes in date.py)
src/rendercv/schema/models/cv/section.py
→ tests/schema/models/cv/test_section.py
(tests all functions and classes in section.py)
```
## Naming Conventions
Test names must include the name of the function or class being tested.
**When you need only one test**, use `test_` + the name:
- Testing `clean_url()``test_clean_url`
- Testing `Cv``test_cv`
**When you need multiple tests**, wrap them in a class using `Test` + PascalCase name:
- Testing `clean_url()``TestCleanUrl`
- Testing `Cv``TestCv`
Example with one test:
```python
@pytest.mark.parametrize(
("url", "expected_clean_url"),
[
("https://example.com", "example.com"),
("https://example.com/", "example.com"),
("https://example.com/test", "example.com/test"),
],
)
def test_clean_url(url, expected_clean_url):
assert clean_url(url) == expected_clean_url
```
Example with multiple tests:
```python
class TestComputeDateString:
@pytest.mark.parametrize(...)
def test_date_parameter_takes_precedence(self, ...):
...
@pytest.mark.parametrize(...)
def test_date_ranges(self, ...):
...
@pytest.mark.parametrize(...)
def test_returns_none_for_incomplete_data(self, ...):
...
```
## Use Parametrize for Variations
Instead of writing multiple similar tests, use `@pytest.mark.parametrize`:
```python
@pytest.mark.parametrize(
("input_a", "input_b", "expected"),
[
("2020-01-01", "2021-01-01", "Jan 2020 Jan 2021"),
("2020-01", "2021-02-01", "Jan 2020 Feb 2021"),
(2020, 2021, "2020 2021"),
],
)
def test_date_ranges(self, input_a, input_b, expected):
result = compute_date_string(None, input_a, input_b, EnglishLocale())
assert result == expected
```
## Shared Fixtures with conftest.py
Place shared fixtures in `conftest.py`. Use the closest one possible:
- Fixtures for one folder → that folder's `conftest.py`
- Fixtures for multiple folders → their closest common parent's `conftest.py`
```
tests/
├── conftest.py # Used across all tests
├── schema/
│ ├── conftest.py # Used by schema tests only
│ └── models/
│ └── cv/
│ ├── conftest.py # Used by CV model tests only
│ ├── test_section.py
│ └── test_cv.py
└── renderer/
└── ...
```
## Testing Principles
**Keep tests focused.** Test functions in isolation: input → output.
**Don't create unnecessary fixtures.** If setup is one clear line, inline it:
```python
# Don't:
@pytest.fixture
def locale(self):
return EnglishLocale()
def test_something(self, locale):
result = format_date(Date(2020, 1, 1), locale)
# Do:
def test_something(self):
result = format_date(Date(2020, 1, 1), EnglishLocale())
```
**Prefer real behavior over mocking.** Only mock when there's no practical alternative (external APIs, file system, etc.).
**Name tests by expected behavior, not by input:**
- Good: `test_returns_none_for_incomplete_data` - describes what should happen
- Bad: `test_function_with_none_input` - describes input but not behavior
**Keep tests simple:**
```python
def test_something(self, input, expected):
result = function_under_test(input)
assert result == expected
```
**What to test:**
- Input → expected output
- Input → expected error
**What to avoid:**
- Testing implementation details instead of behavior
- Complex test setup when simple values work

View File

@@ -0,0 +1,40 @@
---
toc_depth: 3
---
# Dockerfile
## What is Docker?
Docker lets software carry **its entire working environment** with it: the right language runtime, libraries, and configuration, all bundled into a single file called an *image*. Think of an image as a **frozen filesystem where everything is already installed and configured correctly**.
When you run an image, Docker creates a **container**: a live, isolated instance of that environment running on your machine. When you're done, you can delete it without a trace. Your actual system stays untouched.
## Why Docker Is Useful for RenderCV
## Why Docker for RenderCV?
RenderCV installs easily with `pip install rendercv` if you have Python. Most users don't need Docker.
But Docker makes sense if you want:
- **No installation at all** — no Python, no packages, nothing added to your system
- **A reproducible environment** — the exact same setup on every machine, every time
- **To bypass restrictions** — some systems block software installation but allow containers
The RenderCV Docker image is a ready-made environment with Python and RenderCV pre-installed. Just run:
```bash
docker run -v "$PWD":/work -w /work ghcr.io/rendercv/rendercv render Your_CV.yaml
```
## How the Image Gets Published
Docker images are stored in **registries**, which are servers that host images so anyone can download and run them. Docker Hub is the most popular, but GitHub has its own called GitHub Container Registry (GHCR).
When you publish a GitHub release, the [`release.yaml` workflow](https://github.com/rendercv/rendercv/blob/main/.github/workflows/release.yaml) automatically builds and publishes the RenderCV image to GHCR at `ghcr.io/rendercv/rendercv`.
When users run `docker run ghcr.io/rendercv/rendercv`, Docker automatically pulls the image from the registry if it's not already on their machine.
## Learn More
To learn more about writing `Dockerfile`, see the `uv`'s guide on [Docker](https://docs.astral.sh/uv/guides/integration/docker/).

View File

@@ -0,0 +1,91 @@
---
toc_depth: 3
---
# Documentation
## The Goal
We want documentation at `docs.rendercv.com`, a proper website with navigation, search, theming, and interactive features.
**What is a website?** A collection of HTML, CSS, and JavaScript files. Browsers download these files and render them as the pages you see. To have a website, you need:
1. HTML/CSS/JavaScript files
2. A server hosting those files
3. A domain pointing to that server
**The problem:** Writing HTML/CSS/JavaScript manually for documentation is impractical. You want to write content in Markdown and have it become a professional website automatically.
**The solution:** [`mkdocs`](https://github.com/mkdocs/mkdocs) with [Material theme](https://github.com/squidfunk/mkdocs-material). You write Markdown in `docs/`, `mkdocs` generates HTML/CSS/JavaScript, and GitHub Pages hosts it at `docs.rendercv.com`.
```mermaid
flowchart LR
A[Markdown in docs/] --> B[MkDocs + Material]
B --> C[HTML/CSS/JS files]
C --> D[GitHub Pages hosting]
D --> E[docs.rendercv.com]
```
**This means:** Editing Markdown files in `docs/` updates the website at `docs.rendercv.com`.
## Configuration: [`mkdocs.yaml`](https://github.com/rendercv/rendercv/blob/main/mkdocs.yaml)
`mkdocs.yaml` controls how `mkdocs` builds the website:
- **Site metadata:** name, description, repository
- **Theme:** Material theme with colors and features
- **Navigation:** sidebar structure
- **Plugins:** see below
## Plugins
`mkdocs` plugins extend functionality beyond Markdown → HTML conversion.
### [`mkdocstrings`](https://github.com/mkdocstrings/mkdocstrings): API Reference
Generates API reference from Python docstrings. The entire [API Reference](../api_reference/index.md) section is auto-generated from `src/rendercv/`.
### [`mkdocs-macros-plugin`](https://mkdocs-macros-plugin.readthedocs.io/): Dynamic Content
Lets you inject code-generated values into Markdown. [`docs/docs_templating.py`](https://github.com/rendercv/rendercv/blob/main/docs/docs_templating.py) runs during build. It imports values directly from RenderCV's code and exposes them as variables. It's heavily used in [YAML Input Structure](../user_guide/yaml_input_structure.md) page.
## Entry Type Figures
The [YAML Input Structure](../user_guide/yaml_input_structure.md) page shows visual examples of each entry type rendered in each theme.
These are auto-generated PNG images. Run `just update-entry-figures` to regenerate them from [`docs/user_guide/sample_entries.yaml`](https://github.com/rendercv/rendercv/blob/main/docs/user_guide/sample_entries.yaml).
## Local Preview
```bash
just serve-docs
```
Starts a local server at `http://127.0.0.1:8000` with live reload. Edit Markdown files and see changes instantly.
```bash
just build-docs
```
Generates the final website in `site/` directory. Mainly used by GitHub workflows for final deployment (see [GitHub Workflows](github_workflows.md)).
## Deployment
Every push to `main` triggers automatic deployment.
**The workflow** ([`.github/workflows/deploy-docs.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/deploy-docs.yaml)):
1. **Trigger:** Runs on every push to `main`
2. **Build step:**
- Installs dependencies (`uv`, `just`)
- Runs `just build-docs` to generate the website
- Uploads the `site/` directory as an artifact
3. **Deploy step:**
- Takes the uploaded artifact
- Deploys it to GitHub Pages (a free static website hosting service)
- Makes it available at `docs.rendercv.com`
## Learn More
See the [MkDocs Material documentation](https://squidfunk.github.io/mkdocs-material/) for more information.

View File

@@ -1,29 +0,0 @@
# Frequently Asked Questions (FAQ)
## How can I add a new social network to RenderCV?
To add a new social network to RenderCV, go to the `rendercv/data/models/curriculum_vitae.py` file and follow these steps:
1. Append the social network name (for example, "Facebook") to the `SocialNetworkName` type.
2. If necessary, implement its username validation in the `SocialNetwork.check_username` method.
3. Implement its URL generation using the `SocialNetwork.url` method. If the URL can be generated by appending the username to a hostname, only update `url_dictionary`.
4. Finally, include the Typst icon of the social network to the `icon_dictionary` in the `CurriculumVitae.connections` method. RenderCV uses the [`fontawesome`](https://typst.app/universe/package/fontawesome/) package.
Then, the tests should be implemented for the new social network with the following steps:
1. Go to `tests/test_data.py` and update `test_social_network_url` accordingly, i.e., add a new `(network, username, expected_url)` tuple to the `pytest.mark.parametrize` decorator.
2. Go to `tests/conftest.py` and add the new social network to `rendercv_filled_curriculum_vitae_data_model`.
3. Set `update_testdata` to `True` in `conftest.py` and run the tests to update the `testdata` folder.
4. Review the updated `testdata` folder manually to ensure everything works as expected. Then, set `update_testdata` to `False` and push the changes.
## When should we consider adding a new entry type to RenderCV?
We should add a new entry type if and only if the proposed design of the entry type cannot be achieved using any of the existing entry types. This is because RenderCV's entry types are not designed to function as data models. Their purpose is not to store specific data but rather to determine how a given set of strings will appear in the PDF.
For example, JSON Resume follows a data-oriented approach. In JSON Resume, each entry type acts as a data model specifically designed to store structured information. RenderCV takes a design-oriented approach for two reasons:
- There would be too many different data models that would ultimately look more or less the same in the PDF.
- It would be impossible to provide all the different data models people might need.
Therefore, we decided to create entry types solely for their design output.

View File

@@ -0,0 +1,123 @@
---
toc_depth: 3
---
# GitHub Actions
## The Problem
Every software project has repetitive tasks that must run consistently:
- **On every update:** Run tests, redeploy documentation
- **On every release:** Run tests, update `schema.json` and examples, build executables for 4 platforms, build package, upload to PyPI, push Docker image
You could do these manually. But manual means:
- Forgetting steps ("Did I update `schema.json`? Did I build the Windows executable?")
- Wasted time ("Why am I doing the same 15 steps every release?")
**What if you could write down these tasks once, and have them run automatically every time?**
That's what **CI/CD (Continuous Integration/Continuous Deployment)** is. And **GitHub Actions** is GitHub's system for it.
## What are GitHub Actions?
GitHub actions are **automation scripts that run on GitHub's servers when certain events happen**.
You define them in `.github/workflows/*.yaml` files. Each file describes:
1. **When to run:** push to main? Pull request? New release?
2. **What to do:** Run tests? Build docs? Publish package?
3. **Where to run:** Linux? Windows? macOS? Multiple versions?
GitHub reads these files and executes them automatically when the triggering events occur.
**Why GitHub's servers?** Because you don't want to worry about it. Push your code, turn off your computer, you're done. GitHub handles the rest (running tests, deploying docs, building packages) without you having to keep your machine on or manually run anything.
## RenderCV's Workflows
RenderCV has 5 workflows. Each handles a specific automation task.
**How workflows start:** Every workflow begins the same way: clone the repository, install `uv`, install `just`, then run some `just` commands. This recreates the same environment you'd have locally (see [Setup](index.md)).
### 1. [`test.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/test.yaml): Run Tests
**When it runs:**
- Every push to `main` branch
- Every pull request
- Manually (via GitHub UI)
- When called by other workflows
**What it does:**
1. Runs `just test-coverage` across **9 different environments** (3 operating systems × 3 Python versions: 3.12, 3.13, 3.14)
2. Combines all coverage reports and uploads them to show the coverage report
### 2. [`deploy-docs.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/deploy-docs.yaml): Deploy Documentation
**When it runs:**
- Every push to `main` branch
- Manually (via GitHub UI)
**What it does:**
1. Builds the documentation website using `just build-docs`
2. Uploads it to GitHub Pages
3. Documentation is now live at https://docs.rendercv.com
### 3. [`update-files.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/update-files.yaml): Update Generated Files
**When it runs:**
- Manually (via GitHub UI)
- When called by the release workflow
**What it does:**
1. Regenerates files derived from code:
- `schema.json` using `just update-schema`
- Example YAML files and PDFs in `examples/` folder using `just update-examples`
- Entry figures using `just update-entry-figures`
2. Commits and pushes these changes to the repository
### 4. [`create-executables.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/create-executables.yaml): Create Executables
**When it runs:**
- Manually (via GitHub UI)
- When called by the release workflow
**What it does:**
1. Builds standalone executables using `just create-executable` for 4 platforms:
- Linux (x86_64 and ARM64)
- macOS (ARM64)
- Windows (x86_64)
2. Uploads executables as artifacts
These are single-file executables that users can download and run without installing Python.
### 5. [`release.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/release.yaml): Publish a Release
**When it runs:**
- When a new GitHub release is published
**What it does:**
This is the complete release pipeline. It orchestrates everything:
1. **Run tests:** Calls `test.yaml` to ensure everything works
2. **Update files:** Calls `update-files.yaml` to regenerate schema/examples
3. **Build package:** Installs `uv`, builds Python wheel and source distribution using `uv build`
4. **Create executables:** Calls `create-executables.yaml` for all platforms
5. **Create GitHub release:** Downloads and uploads executables and wheel to the release
6. **Publish to PyPI:** Downloads and uploads package so users can `pip install rendercv`
7. **Publish Docker image:** Builds and pushes Docker image to GitHub Container Registry
## Learn More
- [GitHub Actions Documentation](https://docs.github.com/en/actions): Official docs
- [`.github/workflows/`](https://github.com/rendercv/rendercv/tree/main/.github/workflows): RenderCV's workflow files

View File

@@ -0,0 +1,65 @@
# Add a New Locale
1. Create a YAML file in `src/rendercv/schema/models/locale/other_locales/`
```bash
touch src/rendercv/schema/models/locale/other_locales/mylanguage.yaml
```
2. Add the schema reference and provide translations
```yaml
# yaml-language-server: $schema=../../../../../../schema.json
locale:
language: mylanguage
last_updated: "Your translation"
month: "Your translation"
months: "Your translation"
year: "Your translation"
years: "Your translation"
present: "Your translation"
month_abbreviations:
- Jan
- Feb
- Mar
- Apr
- May
- Jun
- Jul
- Aug
- Sep
- Oct
- Nov
- Dec
month_names:
- January
- February
- March
- April
- May
- June
- July
- August
- September
- October
- November
- December
```
3. Add ISO 639-1 language code to `english_locale.py`
Edit `src/rendercv/schema/models/locale/english_locale.py` line 95-108:
```python
return {
"english": "en",
# ... existing languages
"mylanguage": "xx", # Add your two-letter ISO 639-1 code
}[self.language]
```
4. Done. Use it:
```bash
rendercv new "John Doe" --locale mylanguage
```

View File

@@ -0,0 +1,114 @@
# Add a New Social Network
1. Add network name to `SocialNetworkName` type
Edit `src/rendercv/schema/models/cv/social_network.py`:
```python
type SocialNetworkName = Literal[
"LinkedIn",
"GitHub",
# ... existing networks
"MyNetwork", # Add your network here
]
```
2. Add URL pattern to `url_dictionary`
Edit `src/rendercv/schema/models/cv/social_network.py`:
```python
url_dictionary: dict[SocialNetworkName, str] = {
"LinkedIn": "https://linkedin.com/in/",
# ... existing networks
"MyNetwork": "https://mynetwork.com/profile/", # Add URL base here
}
```
3. (Optional) Add username validation
If your network has special username format requirements, edit `src/rendercv/schema/models/cv/social_network.py`:
```python
match network:
case "Mastodon":
# ... existing validations
case "MyNetwork":
# ... your custom validation logic
```
4. (Optional) Add custom URL generation
If URL generation requires special logic (not just base + username), edit `src/rendercv/schema/models/cv/social_network.py`:
```python
@functools.cached_property
def url(self) -> str:
if self.network == "Mastodon":
# ... existing custom logic
elif self.network == "MyNetwork":
# ... your custom URL generation logic
else:
url = url_dictionary[self.network] + self.username
return url
```
5. Add Font Awesome icon
Edit `src/rendercv/renderer/templater/connections.py`:
```python
typst_fa_icons = {
"LinkedIn": "linkedin",
# ... existing icons
"MyNetwork": "my-icon-name", # Add your icon name here
}
```
See available icons at: [fontawesome.com/search](https://fontawesome.com/search)
6. Add test for URL generation
Edit `tests/schema/models/cv/test_social_network.py`:
```python
@pytest.mark.parametrize(
("network", "username", "expected_url"),
[
# ... existing tests
(
"MyNetwork",
"myusername",
"https://mynetwork.com/profile/myusername",
),
],
)
def test_url(self, network, username, expected_url):
# test implementation
```
7. Add network to test fixtures
Edit `tests/renderer/conftest.py`, add your network to the `social_networks` list:
```python
social_networks=[
SocialNetwork(network="LinkedIn", username="johndoe"),
# ... existing networks
SocialNetwork(network="MyNetwork", username="johndoe"),
]
```
8. Update test data and verify visual output
```bash
just update-testdata
```
Check the generated PDFs in `tests/renderer/testdata/test_pdf_png/` to ensure your network appears correctly with the icon.
9. Run tests to verify everything passes
```bash
just test
```

View File

@@ -0,0 +1,27 @@
# Add a New Theme
1. Create a YAML file in `src/rendercv/schema/models/design/other_themes/`
```bash
touch src/rendercv/schema/models/design/other_themes/mytheme.yaml
```
2. Add the schema reference and override Classic theme defaults
```yaml
# yaml-language-server: $schema=../../../../../../schema.json
design:
theme: mytheme
# Override any defaults from classic_theme.py here
colors:
name: rgb(0,0,0)
typography:
font_family: New Computer Modern
# ... add any other overrides
```
3. Done. Use it:
```bash
rendercv new "John Doe" --theme mytheme
```

View File

@@ -1,114 +1,78 @@
# Developer Guide
---
toc_depth: 1
---
All contributions to RenderCV are welcome!
# Setup
The source code is thoroughly documented and well-commented, making it an enjoyable read and easy to understand. A detailed documentation of the source code is available in the [API reference](../reference/index.md).
## Prerequisites
You need two tools to develop RenderCV:
## Getting Started
- **[`uv`](https://docs.astral.sh/uv/)**: Package and project manager. RenderCV uses `uv` to manage dependencies. It also handles Python installations, so you don't need to install Python separately.
- **[`just`](https://github.com/casey/just)**: Command runner. Development commands are defined in the [`justfile`](https://github.com/rendercv/rendercv/blob/main/justfile), and you need `just` to run them.
There are two ways of developing RenderCV: [locally](#develop-locally) or [with GitHub Codespaces](#develop-with-github-codespaces).
Install them by following their official installation guides:
### Develop Locally
- [Install `uv`](https://docs.astral.sh/uv/getting-started/installation/)
- [Install `just`](https://github.com/casey/just#installation)
1. Install [Hatch](https://hatch.pypa.io/latest/). The installation guide for Hatch can be found [here](https://hatch.pypa.io/latest/install/#installation).
## Setting Up the Development Environment
Hatch is a Python project manager. It mainly allows you to define the virtual environments you need in [`pyproject.toml`](https://github.com/rendercv/rendercv/blob/main/pyproject.toml). Then, it takes care of the rest. Also, you don't need to install Python. Hatch will install it when you follow the steps below.
1. Clone the repository:
2. Clone the repository.
```
```bash
git clone https://github.com/rendercv/rendercv.git
```
3. Go to the `rendercv` directory.
```
and change to the repository directory:
```bash
cd rendercv
```
4. Start using one of the virtual environments by activating it in the terminal.
Default development environment with Python 3.13:
2. Set up the development environment (creates a virtual environment in `./.venv` with all dependencies):
```bash
hatch shell default
just sync
```
The same environment, but with Python 3.10 (or 3.11, 3.12, 3.13):
```bash
hatch shell test.py3.10
```
3. Run `just test` to verify all tests pass and everything is set up correctly.
5. Finally, activate the virtual environment in your integrated development environment (IDE). In Visual Studio Code:
4. Finally, activate the virtual environment in your integrated development environment (IDE). In Visual Studio Code:
- Press `Ctrl+Shift+P`.
- Type `Python: Select Interpreter`.
- Select one of the virtual environments created by Hatch.
- Select the one in `./.venv`.
### Develop with GitHub Codespaces
1. [Fork](https://github.com/rendercv/rendercv/fork) the repository.
2. Navigate to the forked repository.
3. Click the <> **Code** button, then click the **Codespaces** tab, and then click **Create codespace on main**.
Then, [Visual Studio Code for the Web](https://code.visualstudio.com/docs/editor/vscode-web) will be opened with a ready-to-use development environment.
This is done with [Development containers](https://containers.dev/), and the environment is defined in the [`.devcontainer/devcontainer.json`](https://github.com/rendercv/rendercv/blob/main/.devcontainer/devcontainer.json) file. Dev containers can also be run locally using various [supporting tools and editors](https://containers.dev/supporting).
That's it! You're now ready to start developing RenderCV.
## Available Commands
These commands are defined in the [`pyproject.toml`](https://github.com/rendercv/rendercv/blob/main/pyproject.toml) file.
### Development
- Build the package
```bash
hatch run build
```
- Format the code with [Black](https://github.com/psf/black) and [Ruff](https://github.com/astral-sh/ruff)
```bash
hatch run format
```
- Lint the code with [Ruff](https://github.com/astral-sh/ruff)
```bash
hatch run lint
```
- Run [pre-commit](https://pre-commit.com/)
```bash
hatch run precommit
```
- Check the types with [Pyright](https://github.com/RobertCraigie/pyright-python)
```bash
hatch run check-types
```
- Run the tests with Python 3.13
```bash
hatch run test
```
- Run the tests with Python 3.13 and generate the coverage report
```bash
hatch run test-and-report
```
- Update [schema.json](https://github.com/rendercv/rendercv/blob/main/schema.json)
```bash
hatch run update-schema
```
- Update [`examples`](https://github.com/rendercv/rendercv/tree/main/examples) folder
```bash
hatch run update-examples
```
- Create an executable version of RenderCV with [PyInstaller](https://www.pyinstaller.org/)
```bash
hatch run exe:create
```
- Preview the documentation as you write it
```bash
hatch run docs:serve
```
- Build the documentation
```bash
hatch run docs:build
```
- Update figures of the entry types in the "[Structure of the YAML Input File](../user_guide/structure_of_the_yaml_input_file.md)"
```bash
hatch run docs:update-entry-figures
```
- `just sync`: Sync all dependencies (including extras and dev groups)
- `just format`: Format code with black and ruff
- `just check`: Run all checks (ruff, pyright, pre-commit)
## About [`pyproject.toml`](https://github.com/rendercv/rendercv/blob/main/pyproject.toml)
### Testing
[`pyproject.toml`](https://github.com/rendercv/rendercv/blob/main/pyproject.toml) contains the metadata, dependencies, and tools required for the project. Please read through the file to understand the project's technical details.
- `just test`: Run tests with pytest
- `just test-coverage`: Run tests with coverage report
- `just update-testdata`: Update test data files (see [Testing](testing.md) for more details)
### Documentation
- `just build-docs`: Build documentation
- `just serve-docs`: Serve documentation locally with live reload
### Scripts
- `just update-schema`: Update JSON schema
- `just update-entry-figures`: Update entry figures for documentation
- `just update-examples`: Update example files
- `just create-executable`: Create standalone executable
### Utilities
- `just count-lines`: Count lines of Python code in the `src/` directory

View File

@@ -0,0 +1,149 @@
---
toc_depth: 3
---
# JSON Schema
## The Problem
You've encountered this everywhere, even if you didn't realize it was the same problem:
**VS Code settings** (`settings.json`):
```json
{
"editor.fontSize": 14,
"editor.tabSiz": 4 // ← Typo! VS Code highlights it red immediately
}
```
**GitHub Actions workflows** (`.github/workflows/test.yaml`):
```yaml
on:
push:
branchs: # ← Typo! Your editor underlines it, suggests "branches"
- main
```
**These files are completely different (VS Code settings, GitHub workflows). But you get autocomplete and validation in both.** How?
VS Code doesn't just "know" what's valid in `settings.json`. GitHub Actions workflows don't magically get autocomplete.
**Someone had to tell your editor:** "Here are all the valid fields, their types, and what they mean."
That "someone" is **JSON Schema**.
## What is JSON Schema?
JSON Schema is a **standard way to describe the structure of JSON/YAML documents**.
Think of it as a specification, a formal description of what's valid:
```json
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Your full name"
},
"age": {
"type": "integer",
"minimum": 0,
"description": "Your age in years"
},
"email": {
"type": "string",
"format": "email"
}
},
"required": ["name"]
}
```
This schema says:
- A valid document is an object
- It must have a `name` field (string, required)
- It can have an `age` field (non-negative integer, optional)
- It can have an `email` field (string matching email format, optional)
**Why does JSON Schema exist?**
Because JSON and YAML files are **everywhere**: configuration files, API requests/responses, CI/CD workflows, application settings, data files. They all share the same problem:
**How do you communicate what's valid?**
You could write documentation: "The `name` field is required and must be a string. The `age` field is optional and must be a non-negative integer." But **documentation is for humans to read, not machines**.
JSON Schema is the **same information in machine-readable format** so editors can understand it.
Once your editor has a schema, it can provide autocomplete, catch typos, and show inline documentation as you type.
This is why:
- **Microsoft publishes a JSON Schema for VS Code settings:** your editor fetches it and provides autocomplete
- **GitHub publishes a JSON Schema for Actions workflows:** that's how you get field suggestions
- **Thousands of tools do the same:** Kubernetes, Docker, Terraform, ESLint, package.json, tsconfig.json, the list goes on
JSON Schema is **infrastructure for editor tooling**.
## RenderCV's JSON Schema
RenderCV has the same problem. Users write their CVs in YAML, and we want them to have a smooth editor experience with autocomplete, typo detection, and inline documentation.
**Solution:** Publish a JSON Schema for RenderCV YAML files.
![JSON Schema of RenderCV](../assets/images/json_schema.gif)
That's why [`schema.json`](https://github.com/rendercv/rendercv/blob/main/schema.json) exists in the repository. Same universal problem, same universal solution.
## How the Schema is Generated
We don't write `schema.json` by hand. **It's automatically generated from Pydantic models.**
RenderCV's entire data structure is defined using Pydantic models (see [Understanding RenderCV](understanding_rendercv.md) for details). Pydantic has a built-in feature: `model_json_schema()`, which generates JSON Schema from your models.
That's what [`src/rendercv/schema/json_schema_generator.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/schema/json_schema_generator.py) does. It calls `model_json_schema()` on our top-level model and writes the result to `schema.json`.
## How Editors Know to Use RenderCV's Schema
There are two ways editors discover and use RenderCV's schema:
### 1. Manual Declaration
Add a special comment at the top of your YAML file:
```yaml
# yaml-language-server: $schema=https://raw.githubusercontent.com/rendercv/rendercv/refs/tags/v2.4/schema.json
cv:
name: John Doe
```
This tells the editor: "Use RenderCV's schema for this file." Note the version tag in the URL, which ensures you get the schema matching your RenderCV version.
**Requirements:** Your editor needs to support this. For VS Code, install the [YAML extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml).
### 2. Schema Store (Automatic)
RenderCV's schema is listed in [SchemaStore](https://github.com/SchemaStore/schemastore), a central registry of schemas that most IDEs use.
In SchemaStore, RenderCV's schema is configured to automatically activate for files ending with `_CV.yaml`. This means:
- If your file is named `John_Doe_CV.yaml`
- And your editor uses SchemaStore (VS Code with YAML extension does)
- You get autocomplete automatically, no comment needed
## When is the Schema Generated?
During development, whenever data models change, run:
```bash
just update-schema
```
This runs [`scripts/update_schema.py`](https://github.com/rendercv/rendercv/blob/main/scripts/update_schema.py), which regenerates `schema.json`.
## Learn More
- [Pydantic JSON Schema](https://docs.pydantic.dev/latest/concepts/json_schema/): How Pydantic generates schemas from models

View File

@@ -0,0 +1,138 @@
---
toc_depth: 3
---
# Project Management
## What is "Project Management"?
When you look at RenderCV's repository, you see:
```
.
├── src/ ← The actual RenderCV code
├── pyproject.toml ← Project configuration
├── justfile ← Command shortcuts
├── scripts/ ← Supplementary Python scripts
├── .pre-commit-config.yaml ← Pre-commit configuration
└── uv.lock ← Dependency lock file
```
**Project management is everything except `src/`.** It's all the infrastructure that lets us:
- Share RenderCV with users (`pip install rendercv`)
- Manage dependencies consistently
- Automate testing, building, and releases
- Ensure reproducibility across machines and time
## Why Can't We Just Write Python Code?
RenderCV is a Python project. The actual source code lives in `src/rendercv/`. Why do we need all these other files - `pyproject.toml`, `uv.lock`, `justfile`, `.github/workflows/`, etc.?
**Because code alone doesn't solve two critical problems: distribution and development environment.**
### Problem 1: Distribution
**How do users get your code?**
You could tell them "download these files, install dependencies with `pip install -r requirements.txt`, and run them with `python main.py`". But users want `pip install rendercv` and have it work instantly with `rendercv` command.
**This requires:** Packaging your code and uploading to [PyPI](https://pypi.org) (Python Package Index).
### Problem 2: Development Environment
You have the source code. Two developers want to contribute.
Developer A installs today with Python 3.11 and gets `pydantic==2.10`. Tests pass. Developer B installs one month later with Python 3.12 and gets `pydantic==2.11` which has breaking changes. Tests fail. "Works on A's machine" but not B's. B asks: "What formatter do you use? What settings? How do I run tests?"
**What needs to happen:** Everyone gets the same Python version, same package versions (locked, not "latest"), same development tools with same settings. All in one command.
**This requires:** Locking dependencies (Python version, every package, frozen in time), configuring all tools in one place, and automating setup so it's identical for everyone.
### The Solution
All those files you see in the repository (`pyproject.toml`, `uv.lock`, `justfile`, and more) work together to solve these problems. The result:
**For users:**
```bash
pip install rendercv
```
Works instantly. Every time. Anywhere. All dependencies installed automatically.
**For developers** ([Setup](index.md)):
```bash
just sync
```
One command. Identical environment for everyone: correct Python version, exact dependency versions, all dev tools ready. Works today, works in 2027. Bug from 6 months ago? Check out that commit, run `just sync`, exact environment recreated.
The rest of this guide explains what each file does.
## Files and Folders in the Root
### [`pyproject.toml`](https://github.com/rendercv/rendercv/blob/main/pyproject.toml)
The project definition file. This is the standard way to configure a Python project.
This file defines:
- Project metadata (name, version, description)
- Dependencies (what packages RenderCV needs)
- Entry points (makes `rendercv` a command)
- Build configuration (how to package RenderCV)
- Tool settings (ruff, pyright, pytest, etc.)
Open the file to see the full configuration with detailed comments.
### [`justfile`](https://github.com/rendercv/rendercv/blob/main/justfile)
[just](https://github.com/casey/just) is a command runner, a tool that lets you define terminal commands in a file and run them easily.
**Why do we need it?** During development, you constantly run commands like "run tests with coverage", "format all code", "build and serve docs". Without standardization:
- Everyone types different commands with different options
- You have to remember long command strings
The `justfile` solves this: define each command once, and everyone runs the same thing:
```bash
just test # Runs pytest with the right options
just format # Formats code with ruff
just serve-docs # Builds and serves documentation locally
just update-schema # Regenerates schema.json
```
This is why `just sync` works so elegantly. It's a standardized command that does exactly the same thing for everyone.
### [`scripts/`](https://github.com/rendercv/rendercv/tree/main/scripts)
Python scripts that automate some repetitive tasks.
**Why do we need it?** Some tasks need to be done repeatedly but are too complex for simple shell commands:
- `update_schema.py`: Generate `schema.json` from pydantic models
- `update_examples.py`: Regenerate all example YAML files and PDFs in `examples/` folder
- `create_executable.py`: Build standalone executable of RenderCV
These scripts are called by `just` commands (`just update-schema`, `just update-examples`, etc.).
### [`.pre-commit-config.yaml`](https://github.com/rendercv/rendercv/blob/main/.pre-commit-config.yaml)
Configuration file for [`pre-commit`](https://pre-commit.com/), a tool that runs code quality checks.
**Why do we need it?** Pre-commit's value is **fast CI/CD**. [pre-commit.ci](https://pre-commit.ci/) (free for open-source projects) automatically runs checks on every push and pull request. Forgot to format your code? The workflow fails, making it immediately obvious. Without pre-commit, we'd have to set up our own workflow to run these checks.
Run `just check` locally to check your code before committing. We don't use pre-commit as git hooks (that run before every commit). We prefer manual checks when ready.
### [`uv.lock`](https://github.com/rendercv/rendercv/blob/main/uv.lock)
A dependency lock file. This is a record of the exact version of every package RenderCV uses (including dependencies of dependencies).
**Why do we need it?** Remember development environment problem? This file solves it. When you run `just sync`, `uv` reads this file and installs the exact same versions everyone else has, not "the latest version", but "the exact version that's known to work". Without this file, developers would get different package versions and environments would drift apart.
**Never edit this manually.** `uv` generates and updates it automatically. **Always commit it to git.** That's how everyone gets identical environments.
## Learn More
See the [`uv` documentation](https://docs.astral.sh/uv/) for more information on project management.

View File

@@ -1,36 +1,79 @@
---
toc_depth: 2
---
# Testing
After implementing a new feature or fixing a bug, one can run all the tests to see if anything is broken.
Tests check if your code does what it's supposed to do. Every time you change something, you need to verify it still works. Instead of manually checking everything, you write test code once and rerun it automatically.
To run all the tests with each Python version (3.10, 3.11, 3.12, and 3.13), use the following command.
Here's a simple example:
```bash
hatch run test:test
```python
def sum(a, b):
return a + b
def test_sum():
assert sum(2, 3) == 5
assert sum(-1, 1) == 0
assert sum(0, 0) == 0
```
To run the tests with a specific Python version, use the following command.
If you change something in `sum`, you can run `test_sum` again to see if it's still working.
All of the tests of RenderCV are written in [`tests/`](https://github.com/rendercv/rendercv/tree/main/tests) directory.
## [`pytest`](https://github.com/pytest-dev/pytest): Testing Framework
`pytest` is a Python library that provides utilities to write and run tests.
**How does it work?** When you run `pytest`, it searches for files matching `test_*.py` in the `tests/` directory and executes all functions starting with `test_`.
**Configuration:** `pytest` reads settings from `pyproject.toml` under `[tool.pytest.ini_options]`.
## Running RenderCV Tests
Whenever you make changes to RenderCV's source code, run the tests to ensure everything still works. If all tests pass, your changes didn't break anything.
```bash
hatch run test.py3.10:test
just test
```
To run the tests with Python 3.13 and generate a coverage report, use the following command.
## Reference File Comparison
Some tests in [`tests/renderer/`](https://github.com/rendercv/rendercv/tree/main/tests/renderer) (specifically [`test_pdf_png.py`](https://github.com/rendercv/rendercv/blob/main/tests/renderer/test_pdf_png.py), [`test_typst.py`](https://github.com/rendercv/rendercv/blob/main/tests/renderer/test_typst.py), [`test_markdown.py`](https://github.com/rendercv/rendercv/blob/main/tests/renderer/test_markdown.py), and [`test_html.py`](https://github.com/rendercv/rendercv/blob/main/tests/renderer/test_html.py)) use reference file comparison:
1. Tests generate output files by running RenderCV
2. Generated files are compared against reference files in `tests/renderer/testdata/`
3. If they match exactly, the test passes. Any difference fails the test.
### Updating Reference Files
You fix a bug that changes RenderCV's output. Tests fail because the new output doesn't match old reference files.
**This is expected.** You intentionally changed the output. You need to update the reference files:
```bash
hatch run test-and-report
just update-testdata
```
Once new commits are pushed to the `main` branch, the [`test.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/test.yaml) workflow will be automatically triggered, and the tests will run.
## About [`testdata`](https://github.com/rendercv/rendercv/tree/main/tests/testdata) folder
In some of the tests:
- RenderCV generates an output with a sample input.
- Then, the output is compared with a reference output, which has been manually generated and stored in `testdata`. If the files differ, the tests fail.
When the `testdata` folder needs to be updated, it can be manually regenerated by setting `update_testdata` to `True` in `conftest.py` and running the tests.
!!! warning
- Whenever the `testdata` folder is generated, the files should be reviewed manually to ensure everything works as expected.
- `update_testdata` should be set to `False` before committing the changes.
**Manually verify new reference files before committing.** These become the source of truth. If you commit broken reference files, tests will pass even when RenderCV produces bad output. Always check generated PDFs and PNGs carefully.
## [`pytest-cov`](https://github.com/pytest-dev/pytest-cov): Coverage Plugin for `pytest`
Coverage is a measure of which code lines are executed when tests run. If tests execute a line, it's included in coverage. If tests execute all lines in `src/rendercv/`, coverage is 100%.
**Why does it matter?** Coverage reports show you which parts of your code aren't tested yet, so you know where to write more tests.
Run tests with coverage:
```bash
just test-coverage
```
This generates two outputs:
- **Terminal:** Overall coverage percentage
- **HTML report:** Open `htmlcov/index.html` to see exactly which lines are covered (green) and which aren't (red)
**Configuration:** Coverage settings are in `pyproject.toml` under `[tool.coverage.run]` and `[tool.coverage.report]`.

View File

@@ -0,0 +1,311 @@
---
toc_depth: 3
---
# Understanding RenderCV
This guide walks you through how RenderCV works, explaining each step and the tools we use.
## The Core Workflow
RenderCV does more than this (Markdown, HTML, PNG outputs, watching files, etc.), but at its core, what happens is:
```mermaid
flowchart LR
A[YAML file] --> B[Typst file]
B --> C[PDF]
```
Read a YAML file, generate a Typst file, compile it to PDF. Everything else is built on top of this foundation.
Let's understand each step.
## Step 1: Reading the YAML File
When a user gives us a YAML file like this:
```yaml
cv:
name: John Doe
location: San Francisco, CA
sections:
education:
- institution: MIT
degree: PhD
start_date: 2020-09
end_date: 2024-05
```
We need to:
1. Parse the YAML into Python dictionaries
2. Validate the data (Does `start_date` come before `end_date`? Is `name` actually provided and is it a string?)
### [`ruamel.yaml`](https://github.com/pycontribs/ruamel-yaml): YAML Parser
First problem: reading YAML files.
Python doesn't have a built-in YAML library. To read YAML files, you need a library. **We use `ruamel.yaml`**, one of the best YAML parsers available.
What does it do? Simple: **converts YAML text into Python dictionaries.**
**YAML file** (`cv.yaml`):
```yaml
cv:
name: John Doe
location: San Francisco, CA
sections:
education:
- institution: MIT
degree: PhD
start_date: 2020-09
```
**After parsing with `ruamel.yaml`:**
```python
from ruamel.yaml import YAML
yaml = YAML()
data = yaml.load(open("cv.yaml"))
# Now data is a Python dictionary:
{
"cv": {
"name": "John Doe",
"location": "San Francisco, CA",
"sections": {
"education": [
{
"institution": "MIT",
"degree": "PhD",
"start_date": "2020-09"
}
]
}
}
}
# You can access it like any Python dict:
data["cv"]["name"] # "John Doe"
data["cv"]["sections"]["education"][0]["institution"] # "MIT"
```
That's it. YAML text becomes a Python dictionary we can work with.
`ruamel.yaml` is being called in [`src/rendercv/schema/yaml_reader.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/schema/yaml_reader.py).
### [`pydantic`](https://github.com/pydantic/pydantic): Python Dictionary Validator
Now we have a dictionary. We need to validate it. Without a library, you'd write:
```python
if "name" not in data["cv"]:
raise ValueError("Missing 'name' field")
if not isinstance(data["cv"]["name"], str):
raise ValueError("name must be a string")
if "sections" in data["cv"]:
for section_name, entries in data["cv"]["sections"].items():
for entry in entries:
if "start_date" in entry and "end_date" in entry:
# Parse dates, compare them...
# This is already hundreds of lines and we're barely started
```
With `pydantic`, we can define the structure once:
```python
from pydantic import BaseModel
from datetime import date as Date
class Education(BaseModel):
institution: str
start_date: Date
end_date: Date
@pydantic.model_validator(mode="after")
def check_dates(self):
if self.start_date > self.end_date:
raise ValueError("start_date cannot be after end_date")
return self
class Cv(BaseModel):
name: str
location: str | None = None
education: list[Education]
```
Then validate:
```python
# This dictionary (from ruamel.yaml):
data = {
"name": "John Doe",
"location": "San Francisco",
"education": [
{
"institution": "MIT",
"start_date": "2020-09",
"end_date": "2024-05"
}
]
}
# Becomes this validated object:
cv = Cv.model_validate(data)
# Now you have clean, validated objects:
cv.name # "John Doe"
cv.education[0].institution # "MIT"
cv.education[0].start_date # "2020-09", guaranteed dates are valid
```
That's the power. Dictionary goes in, `pydantic` checks everything, clean Python object comes out.
![Strict Validation Feature of RenderCV](../assets/images/validation.gif)
**RenderCV's entire data model is `pydantic` models all the way down:**
```python
class RenderCVModel(BaseModel):
cv: Cv # ← pydantic model
design: Design # ← pydantic model
locale: Locale # ← pydantic model
settings: Settings # ← pydantic model
```
Each field is another `pydantic` model. `Cv` contains more `pydantic` models like `EducationEntry`, `ExperienceEntry`, etc. It's nested validation: when you validate `RenderCVModel`, `pydantic` automatically validates every nested model too. One `model_validate()` call checks the entire structure.
See [`src/rendercv/schema/models/rendercv_model.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/schema/models/rendercv_model.py) for the top-level model.
## Step 2: Generating the Typst File
Now we need to generate a Typst file:
```typst
= John Doe
San Francisco, CA
== Education
#strong[MIT] #h(1fr) 2020 2024
PhD in Computer Science
```
You could try string concatenation:
```python
typst = f"= {cv.name}\n"
if cv.location:
typst += f"{cv.location}\n"
typst += "\n"
for section_title, entries in cv.sections.items():
typst += f"== {section_title}\n"
for entry in entries:
typst += f"#strong[{entry.institution}]"
# What about optional fields? Spacing? Line breaks?
# Multiple themes with different layouts?
# This is impossible to maintain!
```
This doesn't work. You're building hundreds of lines of string concatenation logic, handling conditionals, managing whitespace. It's unworkable.
This is why **templating engines were invented**. When you need to programmatically generate complex text files, you need templates.
### [`jinja2`](https://github.com/pallets/jinja): Templating Engine
`jinja2` is the most famous templating engine for Python.
**Template file** (`Header.j2.typ`):
```jinja2
= {{ cv.name }}
{% if cv.location %}
{{ cv.location }}
{% endif %}
{% if cv.email %}
#link("mailto:{{ cv.email }}")
{% endif %}
```
**Python code:**
```python
template = jinja2_env.get_template("Header.j2.typ")
output = template.render(cv=cv)
```
**Result:**
```typst
= John Doe
San Francisco, CA
#link("mailto:john@example.com")
```
Clean separation: templates define layout, Python code provides data. Users can override templates to customize their CV without touching Python code.
Typst templates live in [`src/rendercv/renderer/templater/templates/typst/`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/renderer/templater/templates/typst/).
`jinja2` is being called in [`src/rendercv/renderer/templater/templater.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/renderer/templater/templater.py).
### [`markdown`](https://github.com/Python-Markdown/markdown): Markdown to Typst
Users want to write Markdown in their YAML:
```yaml
highlights:
- "**Published** [3 papers](https://example.com) on neural networks"
- "Collaborated with *Professor Smith*"
```
But Typst doesn't understand `**bold**` or `[links](url)`. We need Typst syntax: `#strong[bold]` and `#link("url")[text]`.
**We use the `markdown` library.** It parses Markdown into an XML tree. Then we walk the tree and convert each element to Typst:
```python
match element.tag:
case "strong":
return f"#strong[{content}]"
case "em":
return f"#emph[{content}]"
case "a":
href = element.get("href")
return f'#link("{href}")[{content}]'
```
Result: `#strong[Published] #link("https://example.com")[3 papers]`
See [`src/rendercv/renderer/templater/markdown_parser.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/renderer/templater/markdown_parser.py). The `markdown_to_typst()` function does this conversion.
## Step 3: Compiling to PDF
### [`typst`](https://github.com/messense/typst-py): Typst Compiler
`typst` library is the Python bindings for the Typst compiler.
```python
from typst import compile
compile("cv.typ", output="cv.pdf")
```
Done. Typst file has been compiled to PDF.
`typst` is being called in [`src/rendercv/renderer/pdf_png.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/renderer/pdf_png.py).
## The Complete Pipeline
When you run `rendercv render cv.yaml`:
1. **Parse** - `ruamel.yaml` reads YAML → Python dict
2. **Validate** - `pydantic` validates dict → `RenderCVModel` object
3. **Generate** - `jinja2` renders templates with data → Typst file
4. **Compile** - `typst` compiles Typst → PDF
Everything else (Markdown support, watch mode, PNG output, HTML export) builds on this core.
## Learn More
1. [`src/rendercv/cli/render_command/run_rendercv.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/cli/render_command/run_rendercv.py): The complete flow
2. [`src/rendercv/schema/models/rendercv_model.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/schema/models/rendercv_model.py): The top-level Pydantic model
3. [`src/rendercv/renderer/templater/templater.py`](https://github.com/rendercv/rendercv/blob/main/src/rendercv/renderer/templater/templater.py): Template rendering

View File

@@ -1,52 +0,0 @@
# Writing Documentation
The documentation's source files are located in the [`docs`](https://github.com/rendercv/rendercv/tree/main/docs) directory and it is built using the [MkDocs](https://github.com/mkdocs/mkdocs) package. To work on the documentation and see the changes in real-time, run the following command.
```bash
hatch run docs:serve
```
Once the changes are pushed to the `main` branch, the [`deploy-docs.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/deploy-docs.yaml) workflow will be automatically triggered, and [docs.rendercv.com](https://docs.rendercv.com/) will be updated to the most recent version.
## Updating the [`examples`](https://github.com/rendercv/rendercv/tree/main/examples) folder
The `examples` folder includes example YAML files for all the built-in themes, along with their corresponding PDF outputs. Also, there are PNG files of the first pages of each theme in [`docs/assets/images`](https://github.com/rendercv/rendercv/tree/main/docs/assets/images). These examples are shown in [`README.md`](https://github.com/rendercv/rendercv/blob/main/README.md).
These files are generated using [`scripts/update_examples.py`](https://github.com/rendercv/rendercv/blob/main/scripts/update_examples.py). The contents of the examples are taken from the [`create_a_sample_data_model`](https://docs.rendercv.com/reference/data/#rendercv.data.create_a_sample_data_model) function from [`rendercv.data`](https://docs.rendercv.com/reference/data/).
Run the following command to update the `examples` folder.
```bash
hatch run update-examples
```
Once a new release is created on GitHub, the [`publish-to-pypi.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/publish-to-pypi.yaml) workflow will be automatically triggered, and the `examples` folder will be updated to the most recent version.
## Updating figures of the entry types in the "[Structure of the YAML Input File](../user_guide/structure_of_the_yaml_input_file.md)"
There are example figures for each entry type for each theme in the "[Structure of the YAML Input File](../user_guide/structure_of_the_yaml_input_file.md)" page.
The figures are generated using [`scripts/update_entry_figures.py`](https://github.com/rendercv/rendercv/blob/main/scripts/update_entry_figures.py).
Run the following command to update the figures.
```bash
hatch run docs:update-entry-figures
```
Once a new release is created on GitHub, the [`publish-to-pypi.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/publish-to-pypi.yaml) workflow will be automatically triggered, and the figures will be updated to the most recent version.
## Updating the JSON Schema ([`schema.json`](https://github.com/rendercv/rendercv/blob/main/schema.json))
The schema of RenderCV's input file is defined using [Pydantic](https://docs.pydantic.dev/latest/). Pydantic allows automatic creation and customization of JSON schemas from Pydantic models.
The JSON Schema is also generated using [`scripts/update_schema.py`](https://github.com/rendercv/rendercv/blob/main/scripts/update_schema.py). It uses [`generate_json_schema`](https://docs.rendercv.com/reference/data/#rendercv.data.generate_json_schema) function from [`rendercv.data`](https://docs.rendercv.com/reference/data/).
Run the following command to update the JSON Schema.
```bash
hatch run update-schema
```
Once a new release is created on GitHub, the [`publish-to-pypi.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/publish-to-pypi.yaml) workflow will be automatically triggered, and `schema.json` will be updated to the most recent version.

142
docs/docs_templating.py Normal file
View File

@@ -0,0 +1,142 @@
"""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.
"""
import io
import pathlib
from typing import get_args
import pydantic
import ruamel.yaml
from rendercv.schema.models.cv.section import (
BulletEntry,
EducationEntry,
ExperienceEntry,
NormalEntry,
NumberedEntry,
OneLineEntry,
PublicationEntry,
ReversedNumberedEntry,
)
from rendercv.schema.models.cv.social_network import available_social_networks
from rendercv.schema.models.design.built_in_design import available_themes
from rendercv.schema.models.design.classic_theme import (
Alignment,
BodyAlignment,
Bullet,
PageSize,
PhoneNumberFormatType,
SectionTitleType,
)
from rendercv.schema.models.design.font_family import available_font_families
from rendercv.schema.models.locale.locale import available_locales
from rendercv.schema.yaml_reader import read_yaml
repository_root = pathlib.Path(__file__).parent.parent
rendercv_path = repository_root / "src" / "rendercv"
image_assets_directory = pathlib.Path(__file__).parent / "assets" / "images"
class SampleEntries(pydantic.BaseModel):
education_entry: EducationEntry
experience_entry: ExperienceEntry
normal_entry: NormalEntry
publication_entry: PublicationEntry
one_line_entry: OneLineEntry
bullet_entry: BulletEntry
numbered_entry: NumberedEntry
reversed_numbered_entry: ReversedNumberedEntry
text_entry: str
def dictionary_to_yaml(dictionary: dict):
"""Converts a dictionary to a YAML string.
Args:
dictionary: The dictionary to be converted to YAML.
Returns:
The YAML string.
"""
yaml_object = ruamel.yaml.YAML()
yaml_object.width = 60
yaml_object.indent(mapping=2, sequence=4, offset=2)
with io.StringIO() as string_stream:
yaml_object.dump(dictionary, string_stream)
return string_stream.getvalue()
def define_env(env):
# See https://mkdocs-macros-plugin.readthedocs.io/en/latest/macros/
sample_entries = read_yaml(
repository_root / "docs" / "user_guide" / "sample_entries.yaml"
)
# validate the parsed dictionary by creating an instance of SampleEntries:
sample_entries = SampleEntries(**sample_entries).model_dump()
entries_showcase = {}
for entry_name, entry in sample_entries.items():
proper_entry_name = entry_name.replace("_", " ").title().replace(" ", "")
entries_showcase[proper_entry_name] = {
"yaml": dictionary_to_yaml(entry),
"figures": [
{
"path": f"../assets/images/{theme}/{entry_name}.png",
"alt_text": f"{proper_entry_name} in {theme}",
"theme": theme,
}
for theme in available_themes
],
}
env.variables["sample_entries"] = entries_showcase
env.variables["entry_count"] = len(sample_entries)
env.variables["entry_names"] = [
f"[{entry_name}](#{entry_name.lower()})" for entry_name in entries_showcase
]
# Available themes strings (put available themes between ``)
themes = [f"`{theme}`" for theme in available_themes]
env.variables["available_themes"] = ", ".join(themes)
# Available locales string
locales = [f"`{locale}`" for locale in available_locales]
env.variables["available_locales"] = ", ".join(locales)
# Available social networks strings (put available social networks between ``)
social_networks = [
f"`{social_network}`" for social_network in available_social_networks
]
env.variables["available_social_networks"] = ", ".join(social_networks)
# Others:
env.variables["available_page_sizes"] = ", ".join(
[f"`{page_size}`" for page_size in get_args(PageSize.__value__)]
)
env.variables["available_font_families"] = ", ".join(
[f"`{font_family}`" for font_family in available_font_families]
)
env.variables["available_body_alignments"] = ", ".join(
[f"`{text_alignment}`" for text_alignment in get_args(BodyAlignment.__value__)]
)
env.variables["available_phone_number_formats"] = ", ".join(
[
f"`{phone_number_format}`"
for phone_number_format in get_args(PhoneNumberFormatType.__value__)
]
)
env.variables["available_alignments"] = ", ".join(
[f"`{alignment}`" for alignment in get_args(Alignment.__value__)]
)
env.variables["available_section_title_types"] = ", ".join(
[
f"`{section_title_type}`"
for section_title_type in get_args(SectionTitleType.__value__)
]
)
env.variables["available_bullets"] = ", ".join(
[f"`{bullet}`" for bullet in get_args(Bullet.__value__)]
)

View File

@@ -1,162 +0,0 @@
"""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.
"""
import io
import pathlib
from typing import get_args
import pydantic
import ruamel.yaml
import rendercv.data as data
import rendercv.themes.options as theme_options
repository_root = pathlib.Path(__file__).parent.parent
rendercv_path = repository_root / "src" / "rendercv"
image_assets_directory = pathlib.Path(__file__).parent / "assets" / "images"
class SampleEntries(pydantic.BaseModel):
education_entry: data.EducationEntry
experience_entry: data.ExperienceEntry
normal_entry: data.NormalEntry
publication_entry: data.PublicationEntry
one_line_entry: data.OneLineEntry
bullet_entry: data.BulletEntry
numbered_entry: data.NumberedEntry
reversed_numbered_entry: data.ReversedNumberedEntry
text_entry: str
def dictionary_to_yaml(dictionary: dict):
"""Converts a dictionary to a YAML string.
Args:
dictionary: The dictionary to be converted to YAML.
Returns:
The YAML string.
"""
yaml_object = ruamel.yaml.YAML()
yaml_object.width = 60
yaml_object.indent(mapping=2, sequence=4, offset=2)
with io.StringIO() as string_stream:
yaml_object.dump(dictionary, string_stream)
return string_stream.getvalue()
def define_env(env):
# See https://mkdocs-macros-plugin.readthedocs.io/en/latest/macros/
sample_entries = data.read_a_yaml_file(
repository_root / "docs" / "user_guide" / "sample_entries.yaml"
)
# validate the parsed dictionary by creating an instance of SampleEntries:
SampleEntries(**sample_entries)
entries_showcase = {}
for entry_name, entry in sample_entries.items():
proper_entry_name = entry_name.replace("_", " ").title().replace(" ", "")
entries_showcase[proper_entry_name] = {
"yaml": dictionary_to_yaml(entry),
"figures": [
{
"path": f"../assets/images/{theme}/{entry_name}.png",
"alt_text": f"{proper_entry_name} in {theme}",
"theme": theme,
}
for theme in data.available_themes
],
}
env.variables["sample_entries"] = entries_showcase
# For theme templates reference docs
themes_path = rendercv_path / "themes"
theme_templates = {}
for theme in data.available_themes:
theme_templates[theme] = {}
for theme_file in themes_path.glob(f"{theme}/*.typ"):
theme_templates[theme][theme_file.stem] = theme_file.read_text()
# Update ordering of theme templates, if there are more files, add them to the
# end
order = [
"Preamble.j2",
"Header.j2",
"SectionBeginning.j2",
"SectionEnding.j2",
"TextEntry.j2",
"BulletEntry.j2",
"NumberedEntry.j2",
"ReversedNumberedEntry.j2",
"OneLineEntry.j2",
"EducationEntry.j2",
"ExperienceEntry.j2",
"NormalEntry.j2",
"PublicationEntry.j2",
]
remaining_files = set(theme_templates[theme].keys()) - set(order)
order += list(remaining_files)
theme_templates[theme] = {key: theme_templates[theme][key] for key in order}
if theme != "markdown":
theme_templates[theme] = {
f"{key}.typ": value for key, value in theme_templates[theme].items()
}
else:
theme_templates[theme] = {
f"{key}.md": value for key, value in theme_templates[theme].items()
}
env.variables["theme_templates"] = theme_templates
theme_components = {}
for theme_file in themes_path.glob("components/*.typ"):
theme_components[theme_file.stem] = theme_file.read_text()
theme_components = {f"{key}.typ": value for key, value in theme_components.items()}
env.variables["theme_components"] = theme_components
# Available themes strings (put available themes between ``)
themes = [f"`{theme}`" for theme in data.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 data.available_social_networks
]
env.variables["available_social_networks"] = ", ".join(social_networks)
# Others:
env.variables["available_page_sizes"] = ", ".join(
[f"`{page_size}`" for page_size in get_args(theme_options.PageSize)]
)
env.variables["available_font_families"] = ", ".join(
[f"`{font_family}`" for font_family in get_args(theme_options.FontFamily)]
)
env.variables["available_text_alignments"] = ", ".join(
[
f"`{text_alignment}`"
for text_alignment in get_args(theme_options.TextAlignment)
]
)
env.variables["available_header_alignments"] = ", ".join(
[
f"`{header_alignment}`"
for header_alignment in get_args(theme_options.Alignment)
]
)
env.variables["available_section_title_types"] = ", ".join(
[
f"`{section_title_type}`"
for section_title_type in get_args(
get_args(theme_options.SectionTitleType)[0]
)
]
)
env.variables["available_bullets"] = ", ".join(
[f"`{bullet}`" for bullet in get_args(theme_options.BulletPoint)]
)

View File

@@ -1,73 +1,158 @@
# The engine of the [RenderCV App](https://rendercv.com)
# RenderCV
<div align="center" markdown>
*CV/resume generator for academics and engineers*
[![test](https://github.com/rendercv/rendercv/actions/workflows/test.yaml/badge.svg?branch=main)](https://github.com/rendercv/rendercv/actions/workflows/test.yaml)
[![coverage](https://coverage-badge.samuelcolvin.workers.dev/rendercv/rendercv.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/rendercv/rendercv)
[![docs](https://img.shields.io/badge/docs-mkdocs-rgb(0%2C79%2C144))](https://docs.rendercv.com)
[![pypi-version](https://img.shields.io/pypi/v/rendercv?label=PyPI%20version&color=rgb(0%2C79%2C144))](https://pypi.python.org/pypi/rendercv)
[![pypi-downloads](https://img.shields.io/pepy/dt/rendercv?label=PyPI%20downloads&color=rgb(0%2C%2079%2C%20144))](https://pypistats.org/packages/rendercv)
</div>
RenderCV engine is a Typst-based Python package with a command-line interface (CLI) that allows you to version-control your CV/resume as source code. It reads a CV written in a YAML file with Markdown syntax, converts it into a [Typst](https://typst.app) code, and generates a PDF.
Write your CV or resume as YAML, then run RenderCV,
RenderCV engine's focus is to provide these three features:
```bash
rendercv render John_Doe_CV.yaml
```
- **Content-first approach:** Users should be able to focus on the content instead of worrying about the formatting.
- **A mechanism to version-control a CV's content and design separately:** The content and design of a CV are separate issues and they should be treated separately.
- **Robustness:** A PDF should be delivered if there aren't any errors. If errors exist, they should be clearly explained along with solutions.
and get a PDF with perfect typography. No template wrestling. No broken layouts. Consistent spacing, every time.
With RenderCV, you can:
It takes a YAML file that looks like this:
- Version-control your CV — it's just text.
- Focus on content — don't wory about the formatting.
- Get perfect typography — kerning, spacing, hierarchy, all handled. No design skills required.
A YAML file like this:
```yaml
cv:
name: John Doe
location: Location
email: john.doe@example.com
phone: tel:+1-609-999-9995
location: San Francisco, CA
email: john.doe@email.com
website: https://rendercv.com/
social_networks:
- network: LinkedIn
username: john.doe
username: rendercv
- network: GitHub
username: john.doe
username: rendercv
sections:
welcome_to_RenderCV!:
- '[RenderCV](https://rendercv.com) is a Typst-based CV
framework designed for academics and engineers, with Markdown
syntax support.'
- Each section title is arbitrary. Each section contains
a list of entries, and there are 7 different entry types
to choose from.
Welcome to RenderCV:
- RenderCV reads a CV written in a YAML file, and generates a PDF with professional typography.
- See the [documentation](https://docs.rendercv.com) for more details.
education:
- institution: Stanford University
- institution: Princeton University
area: Computer Science
degree: PhD
location: Stanford, CA, USA
start_date: 2023-09
end_date: present
date:
start_date: 2018-09
end_date: 2023-05
location: Princeton, NJ
summary:
highlights:
- Working on the optimization of autonomous vehicles
in urban environments
- "Thesis: Efficient Neural Architecture Search for Resource-Constrained Deployment"
- "Advisor: Prof. Sanjeev Arora"
- NSF Graduate Research Fellowship, Siebel Scholar (Class of 2022)
...
```
Then, it produces one of these PDFs with its corresponding Typst file, Markdown file, HTML file, and images as PNGs. Click on the images below to preview PDF files.
becomes one of these PDFs. Click on the images to preview.
| [![Classic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/classic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ClassicTheme_CV.pdf) | [![Sb2nov Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/sb2nov.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_Sb2novTheme_CV.pdf) |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [![Moderncv Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/moderncv.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ModerncvTheme_CV.pdf) | [![Engineeringresumes Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringresumes.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringresumesTheme_CV.pdf) |
| [![Engineeringclassic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringclassic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringclassicTheme_CV.pdf) | ![Custom themes can be added.](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/customtheme.png) |
| [![Classic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/classic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ClassicTheme_CV.pdf) | [![Engineeringresumes Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringresumes.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringresumesTheme_CV.pdf) | [![Sb2nov Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/sb2nov.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_Sb2novTheme_CV.pdf) |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [![Moderncv Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/moderncv.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_ModerncvTheme_CV.pdf) | [![Engineeringclassic Theme Example of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/engineeringclassic.png)](https://github.com/rendercv/rendercv/blob/main/examples/John_Doe_EngineeringclassicTheme_CV.pdf) | ![Custom themes can be added.](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/customtheme.png) |
RenderCV comes with a JSON Schema so that the YAML input file can be filled out interactively.
![JSON Schema of RenderCV](https://raw.githubusercontent.com/rendercv/rendercv/main/docs/assets/images/schema.gif)
## JSON Schema
## Getting Started
RenderCV's JSON Schema lets you fill out the YAML interactively, with autocompletion and inline documentation.
RenderCV engine is very easy to install (`pip install "rendercv[full]"`) and easy to use (`rendercv new "John Doe"`). Follow the [user guide](https://docs.rendercv.com/user_guide) to get started.
![JSON Schema of RenderCV](./assets/images/json_schema.gif)
## Motivation
We are developing a [purpose-built app](https://rendercv.com) for writing CVs and resumes that will be available on mobile and web. This Python project is the foundation of that app. Check out [our blog post](https://rendercv.com/introducing-rendercv/) to learn more about why one would use such an app.
## Extensive Design Options
## Contributing
You have full control over every detail.
All contributions to RenderCV are welcome! To get started, please read [the developer guide](https://docs.rendercv.com/developer_guide).
```yaml
design:
theme: classic
page:
size: us-letter
top_margin: 0.7in
bottom_margin: 0.7in
left_margin: 0.7in
right_margin: 0.7in
show_footer: true
show_top_note: true
colors:
body: rgb(0, 0, 0)
name: rgb(0, 79, 144)
headline: rgb(0, 79, 144)
connections: rgb(0, 79, 144)
section_titles: rgb(0, 79, 144)
links: rgb(0, 79, 144)
footer: rgb(128, 128, 128)
top_note: rgb(128, 128, 128)
typography:
line_spacing: 0.6em
alignment: justified
date_and_location_column_alignment: right
font_family: Source Sans 3
# ...and more
```
![Design Options of RenderCV](./assets/images/design_options.gif)
> [!TIP]
> Want to set up a live preview environment like the one shown above? See [how to set up VS Code for RenderCV](user_guide/how_to/set_up_vs_code_for_rendercv.md).
## Strict Validation
No surprises. If something's wrong, you'll know exactly what and where. If it's valid, you get a perfect PDF.
![Strict Validation Feature of RenderCV](./assets/images/validation.gif)
## Any Language
Fill out the locale field for your language.
```yaml
locale:
language: english
last_updated: Last updated in
month: month
months: months
year: year
years: years
present: present
month_abbreviations:
- Jan
- Feb
- Mar
...
```
## Get Started
Install RenderCV (Requires Python 3.12+):
```
pip install "rendercv[full]"
```
Create a new CV yaml file:
```
rendercv new "John Doe"
```
Edit the YAML, then render:
```
rendercv render "John_Doe_CV.yaml"
```
For more details, see the [user guide](user_guide/index.md).

View File

@@ -1,3 +0,0 @@
# `rendercv.api.functions`
::: rendercv.api.functions

View File

@@ -1,3 +0,0 @@
# `rendercv.api`
::: rendercv.api

View File

@@ -1,3 +0,0 @@
# `rendercv.cli.commands`
::: rendercv.cli.commands

View File

@@ -1,3 +0,0 @@
# `rendercv.cli`
::: rendercv.cli

View File

@@ -1,3 +0,0 @@
# `rendercv.cli.printer`
::: rendercv.cli.printer

View File

@@ -1,3 +0,0 @@
# `rendercv.cli.utilities`
::: rendercv.cli.utilities

View File

@@ -1,3 +0,0 @@
# `rendercv.data.generator`
::: rendercv.data.generator

View File

@@ -1,3 +0,0 @@
# `rendercv.data`
::: rendercv.data

View File

@@ -1,3 +0,0 @@
# `rendercv.data.models.base`
::: rendercv.data.models.base

View File

@@ -1,3 +0,0 @@
# `rendercv.data.models.computers`
::: rendercv.data.models.computers

Some files were not shown because too many files have changed in this diff Show More