Switch to uv (#515)

* Update pyproject.toml

* Create justfile

* Move `rendercv` to `src/rendercv`

* Polish pyproject.toml

* Update workflows

* Remove issue templates (no need)

* Fix mistakes in workflows

* Improve workflows

* Remove devcontainer

* Use uv

* Minor update

* Use .yaml instead of .yml

* Update test.yaml triggers

* Use --all-groups in uv sync

* Make theme options compatible with pydantic 3.12.*

* Fix coverage issue
This commit is contained in:
Sina Atalay
2025-10-28 17:32:57 +03:00
committed by GitHub
parent 8ad18fe9c0
commit 5156f7799e
146 changed files with 2880 additions and 1942 deletions

View File

@@ -1,15 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Python 3",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers-contrib/features/hatch:2": {}
},
// Use 'initializeCommand' to run commands before anything else:
"initializeCommand": "git submodule update --init",
// Use 'onCreateCommand' to run commands after the container is created inside the container:
"onCreateCommand": "hatch env create default && hatch env create docs",
}

View File

@@ -1,16 +0,0 @@
---
name: Bug report
about: Create a report to help us improve RenderCV
title: ''
labels: bug
assignees: sinaatalay
---
**Describe the bug**
A clear and concise description of what the bug is and what you expected to happen.
**To Reproduce**
Please provide a minimal YAML input as a code block for us to produce the same error.
**Screenshots**
If applicable, add screenshots to help explain your problem.

View File

@@ -1,9 +0,0 @@
---
name: Enhancement
about: Suggest an idea for RenderCV
title: ''
labels: enhancement
assignees: sinaatalay
---
A clear and concise description of what you want to happen.

View File

@@ -1,9 +0,0 @@
---
name: Improvement to the documentation
about: Create a report to help us improve the documentation of RenderCV
title: ''
labels: documentation
assignees: sinaatalay
---
A clear and concise description of what you want to add, improve, or fix in the documentation.

View File

View File

@@ -1,8 +1,8 @@
name: Create executables
# GitHub events that triggers the workflow:
# GitHub events that trigger the workflow:
on:
workflow_call: # to make the workflow triggerable from other workflows (publish-a-release.yaml)
workflow_call: # to make the workflow triggerable from other workflows
workflow_dispatch: # to make the workflow triggerable manually
jobs:
@@ -21,12 +21,17 @@ jobs:
steps:
- uses: actions/checkout@v5
- name: Install Hatch
uses: pypa/hatch@install
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Install just
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
- name: Create executable
run: |
hatch run exe:create
run: just create-executable
- name: Upload executable as an artifact
uses: actions/upload-artifact@v4

View File

@@ -22,26 +22,29 @@ concurrency:
cancel-in-progress: false
jobs:
# Build job
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Hatch
uses: pypa/hatch@install
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Build the website
run: |
hatch run docs:build
- name: Install just
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
- name: Build docs
run: just build-docs
- name: Upload the website as an artifact
uses: actions/upload-pages-artifact@v4
with:
path: site
# Deployment job
deploy:
name: Deploy
environment:

View File

@@ -4,46 +4,72 @@ name: Publish a release
on:
push:
tags:
- "v*.*.*"
- "v*.*.*-*"
workflow_dispatch:
- "v*.*"
jobs:
call_test_workflow:
test:
name: Run Tests
if: ${{ github.ref_type == 'tag' && github.ref_name matches '^v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$' }}
uses: ./.github/workflows/test.yaml
call_create_executables_workflow:
update_files:
name: Update schema.json, examples, and entry figures
uses: ./.github/workflows/update-files.yaml
needs:
- test
build:
name: Build Package
needs:
- update_files
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Check if the release tag matches the version
uses: samuelcolvin/check-python-version@v5
with:
version_file_path: src/rendercv/__init__.py
- name: Build
run: uv build
- name: Upload the wheel and source distribution as artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist
create_executables:
name: Create Executables
needs:
- call_test_workflow
- update_files
uses: ./.github/workflows/create-executables.yaml
upload_release_files:
name: Create release files
create_github_release:
name: Create GitHub Release
needs:
- call_create_executables_workflow
- build
- create_executables
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download the executables
uses: actions/download-artifact@v5
with:
pattern: rendercv-*
merge-multiple: false
- name: Checkout the repository
uses: actions/checkout@v5
- name: Download the build artifacts
uses: actions/download-artifact@v5
with:
name: dist
path: dist
- uses: actions/checkout@v5
- name: Install Hatch
uses: pypa/hatch@install
- name: Build
run: |
hatch build
- name: Upload the executables as release assets
- name: Create GitHub release with assets
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
@@ -59,34 +85,21 @@ jobs:
publish_to_pypi:
name: Publish to PyPI
needs:
- upload_release_files
- create_github_release
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write
steps:
- uses: actions/checkout@v5
- name: Install Hatch
uses: pypa/hatch@install
- name: Check if the release tag matches the version
uses: samuelcolvin/check-python-version@v5
- name: Download the build artifacts
uses: actions/download-artifact@v5
with:
version_file_path: rendercv/__init__.py
- name: Build
run: |
hatch build
name: dist
path: dist
- name: Upload package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- name: Upload the wheel and source distribution as artifacts
uses: actions/upload-artifact@v4
with:
path: dist
publish_to_dockerhub_and_ghcr:
name: Push Docker image to Docker Hub and GitHub Container Registry
runs-on: ubuntu-latest
@@ -134,13 +147,6 @@ jobs:
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v3
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-name: ghcr.io/${{ github.repository }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
call_update_files_workflow:
name: Update files
uses: ./.github/workflows/update-files.yaml
needs:
- publish_to_dockerhub_and_ghcr
- publish_to_pypi

View File

@@ -1,14 +1,14 @@
name: Test
# GitHub events that triggers the workflow:
# GitHub events that trigger the workflow:
on:
push:
branches:
- "*"
- main
pull_request:
branches:
- "*"
workflow_call: # to make the workflow triggerable from other workflows (publish-to-pypi.yaml)
workflow_call: # to make the workflow triggerable from other workflows
workflow_dispatch: # to make the workflow triggerable manually
# The workflow:
@@ -20,17 +20,23 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu, windows, macos]
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v5
- name: Install Hatch
uses: pypa/hatch@install
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Install just
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
- name: Test
run: hatch run test.py${{ matrix.python-version }}:test-and-report
run: just test-with-coverage
- name: Rename the coverage file
run: mv .coverage .coverage.${{ matrix.python-version }}.${{ matrix.os }}
@@ -59,19 +65,23 @@ jobs:
path: coverage
merge-multiple: true # download them in the same folder
- name: Install Hatch
uses: pypa/hatch@install
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Install the project
run: uv sync --locked --all-extras --all-groups
- name: Install just
uses: taiki-e/install-action@just
- name: Combine coverage files
run: |
hatch run coverage combine coverage
hatch run coverage report
hatch run coverage html --show-contexts --title "RenderCV coverage for ${{ github.sha }}"
uv run coverage combine coverage
uv run coverage report
uv run coverage html --show-contexts --title "RenderCV coverage for ${{ github.sha }}"
- name: Upload the coverage report to smokeshow
run: |
pip install smokeshow==0.4.0
smokeshow upload ./htmlcov
run: uv tool run smokeshow==0.4.0 upload ./htmlcov
env:
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 90

View File

@@ -1,6 +1,6 @@
name: Update files
# GitHub events that triggers the workflow:
# GitHub events that trigger the workflow:
on:
workflow_call: # to make the workflow triggerable from other workflows (publish-a-release.yaml)
workflow_dispatch: # to make the workflow triggerable manually
@@ -16,8 +16,14 @@ jobs:
steps:
- uses: actions/checkout@v5
- name: Install Hatch
uses: pypa/hatch@install
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Install just
uses: taiki-e/install-action@just
- name: Install the project
run: uv sync --locked --all-extras --all-groups
- name: Set Git credentials
run: |
@@ -25,26 +31,20 @@ jobs:
git config --local user.name "GitHub Actions [Bot]"
- name: Update schema.json
continue-on-error: true
run: |
hatch run update-schema
git add schema.json
run: just update-schema
- name: Update `examples` folder
continue-on-error: true
run: |
hatch run update-examples
git add examples/*
git add docs/assets/images/*.png
- name: Update examples folder
run: just update-examples
- name: Update entry figures
continue-on-error: true
run: |
hatch run docs:update-entry-figures
git add docs/assets/images/**/*.png
run: just update-entry-figures
- name: Push changes
continue-on-error: true
- name: Commit and push changes
run: |
git commit -m "Update schema.json, examples, and entry figures"
git push origin HEAD:main
git add -A
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "Update schema.json, examples, and entry figures"
git push origin HEAD:main
fi

59
justfile Normal file
View File

@@ -0,0 +1,59 @@
format:
uv run black src tests ; uv run ruff check --fix src tests ; uv run ruff format src tests
format-file target:
uv run -- black {{target}}; uv run -- ruff check --fix {{target}}; uv run -- ruff format {{target}}
lint:
uv run -- ruff check src tests
check-types:
uv run -- pyright src tests
pre-commit:
uv run -- pre-commit run --all-files
count-lines:
wc -l `find src -name '*.py'`
update-schema:
uv run scripts/update_schema.py
update-entry-figures:
uv run scripts/update_entry_figures.py
update-examples:
uv run scripts/update_examples.py
create-executable:
uv run scripts/create_executable.py
profile-render-command:
uv run -- python -m cProfile -o render_command.prof -m rendercv render examples/John_Doe_ClassicTheme_CV.yaml && snakeviz render_command.prof
src-tree:
tree src/rendercv --gitignore
build-docs:
uv run mkdocs build --clean --strict
serve-docs:
uv run mkdocs serve
test:
uv run pytest
test-with-coverage:
uv run -- coverage run -m pytest; uv run -- coverage combine
report-coverage:
uv run -- coverage report && uv run -- coverage html --show-contexts
open video_path:
uv run scripts/open.py {{video_path}}
profile target:
sudo -E uv run py-spy record -o profile.svg python {{target}}
pull-data:
uv run scripts/pull_data.py

View File

@@ -1,15 +1,14 @@
# Every modern Python package today has a `pyproject.toml` file. It is a Python
# standard. `pyproject.toml` file contains all the metadata about the package. It also
# includes the dependencies and required information for building the package. For more
# details, see https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/.
# standard. The `pyproject.toml` file contains all the metadata about the package.
# It also includes the dependencies and required information for building the package.
# For more details, see https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/.
[build-system]
# If a code needs to be distributed, it might need to be compiled, or it might need to
# be bundled with other files. This process of making a code ready for distribution is
# called building.
# If code needs to be distributed, it might need to be compiled or bundled with other files.
# This process of making code ready for distribution is called building.
# Python packages need to be built too, even though they are not compiled (mostly). At
# the end of the building process, a source distribution package (sdist) and a built
# Python packages need to be built too, even though they are not compiled (mostly).
# At the end of the building process, a source distribution package (sdist) and a built
# distribution package (in Wheel format) are created.
# See https://packaging.python.org/en/latest/tutorials/packaging-projects/ for details.
# Built Distribution:
@@ -17,52 +16,45 @@
# Source Distribution:
# https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist
# To build RenderCV, we need to specify which build package we want to use. There are
# many build packages like `setuptools`, `flit`, `poetry`, `hatchling`, etc. We will use
# `hatchling`.
# To build RenderCV, we need to specify which build package to use. There are
# many build backends like `setuptools`, `flit`, `poetry`, `hatchling`, etc. We will use
# `uv_build`.
requires = [
"hatchling==1.27.0",
] # List of packages that are needed to build RenderCV
"uv_build>=0.9.5,<0.10.0",
] # Packages needed to build RenderCV
# Python has a standard object format called build-backend object. Python standard asks
# this object to have some specific methods that do a specific job. For example, it
# should have a method called `build_wheel` that builds a wheel file. We use hatchling
# to build RenderCV, and hatchling's build-backend object is `hatchling.build`.
# Python has a standard object format called a build-backend object. This object must
# implement specific methods that perform defined tasks. For example, it should have a
# method called `build_wheel` that builds a wheel file.
# See https://peps.python.org/pep-0517/
build-backend = "hatchling.build" # A build-backend object for building RenderCV
build-backend = "uv_build" # Build-backend object for building RenderCV
[tool.hatch.build.targets.sdist]
# In the sdist, what do we want to exclude? Gif files are huge.
# In the sdist, what do we want to exclude? GIF files are large.
exclude = ["*.gif"]
[tool.hatch.build.targets.wheel]
# In wheel, what do we want to include and exclude?
# In the wheel, what do we want to include and exclude?
packages = ["rendercv"]
[tool.hatch.version]
# We will use hatchling to generate the version number of RenderCV. It will go to the
# `path` below and get the version number from there.
# See https://hatch.pypa.io/latest/version/
path = "rendercv/__init__.py"
[project]
# Under the `project` section, we specify the metadata about RenderCV.
# Metadata about RenderCV.
name = 'rendercv'
version = '2.3'
description = 'Typst-based CV/resume generator'
authors = [{ name = 'Sina Atalay', email = 'dev@atalay.biz' }]
license = "MIT"
readme = "README.md"
requires-python = '>=3.10'
# RenderCV depends on these packages. They will be installed automatically when RenderCV
# is installed:
# RenderCV depends on these packages. They are installed automatically when RenderCV is installed:
dependencies = [
'Jinja2>=3.1.3', # to generate Typst and Markdown files
'phonenumbers==9.0.16', # to validate phone numbers
'email-validator==2.3.0', # to validate email addresses
'pydantic==2.11.9', # to validate and parse the input file
'pycountry==24.6.1', # for ISO 639-3 validation
'pydantic-extra-types==2.10.6', # to validate some extra types
'ruamel.yaml==0.18.6', # to parse YAML files
'Jinja2>=3.1.6', # Generate Typst and Markdown files
'phonenumbers>=9.0.16', # Validate phone numbers
'email-validator>=2.3.0', # Validate email addresses
'pydantic>=2.12.3', # Validate and parse input files
'pycountry>=24.6.1', # ISO 639-3 validation
'pydantic-extra-types>=2.10.6', # Validate extra types
'ruamel.yaml>=0.18.16', # Parse YAML files
]
classifiers = [
"Intended Audience :: Science/Research",
@@ -74,138 +66,67 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
] # go to https://pypi.org/classifiers/ to see all classifiers
dynamic = ["version"] # We will use hatchling to generate the version number
] # See all classifiers at https://pypi.org/classifiers/
[project.optional-dependencies]
full = [
'typer==0.16.0', # to create the command-line interface
"markdown==3.9", # to convert Markdown to HTML
"watchdog==6.0.0", # to poll files for updates
"typst==0.13.1", # to render PDF from Typst source files
"rendercv-fonts", # some font files for RenderCV
"packaging==25.0", # to validate the version number
'typer>=0.20.0', # Command-line interface
'markdown>=3.9', # Convert Markdown to HTML
'watchdog>=6.0.0', # Monitor files for updates
'typst>=0.13.7', # Render PDF from Typst source files
'packaging>=25.0', # Validate version numbers
'rendercv-fonts', # Font files for RenderCV
]
[project.urls]
# Here, we can specify the URLs related to RenderCV. They will be listed under the
# "Project links" section in PyPI. See https://pypi.org/project/rendercv/
# URLs related to RenderCV. Listed under the "Project links" section on PyPI.
"Web App" = 'https://rendercv.com'
Source = 'https://github.com/rendercv/rendercv'
Documentation = 'https://docs.rendercv.com'
Changelog = 'https://docs.rendercv.com/changelog'
[project.scripts]
# Here, we specify the entry points of RenderCV.
# Entry points for RenderCV.
# See https://packaging.python.org/en/latest/specifications/entry-points/#entry-points
# See https://hatch.pypa.io/latest/config/metadata/#cli
# The key and value below mean this: If someone installs RenderCV, then running
# `rendercv` in the terminal will run the function `app` in the module `cli` in the
# package `rendercv`.
# The key and value below mean: when someone installs RenderCV,
# running `rendercv` in the terminal executes the function `app` in the module `cli`
# inside the package `rendercv`.
rendercv = 'rendercv.cli:app'
# ======================================================================================
# Virtual Environments Below ===========================================================
# ======================================================================================
# RenderCV depends on other packages, which are listed under the `project` section as
# `dependencies`. However, for the development of RenderCV, we need some other packages
# too (like `black`, `ruff`, `mkdocs`, etc.). We need these packages in our virtual
# environments and we handle the environments with `hatchling`.
# There will be three virtual environments for RenderCV: `default`, `docs`, and `test`.
# `default` is the default virtual environment needed to develop RenderCV.
# `docs` is the virtual environment needed to build the documentation of RenderCV.
# `test` is the virtual environment needed to run the tests of RenderCV.
[tool.hatch.envs.default]
installer = "uv"
python = "3.13"
dependencies = [
"ruff", # to lint and format the code
"black", # to format the code
"ipython", # for ipython shell
"pyright", # to check the types
"pre-commit", # to run the checks before committing
"pytest==8.3.4", # to run the tests
"coverage==7.6.10", # to generate coverage reports
"pypdf==5.1.0", # to read PDF files
"snakeviz==2.2.2", # for profiling
"pyinstaller==6.11.1", # to build the executable
# Virtual Environment Dependencies:
[dependency-groups]
dev = [
'ruff>=0.14.1', # Lint and format the code
'black>=25.9.0', # Format the code
'pyright>=1.1.406', # Type checking
'pre-commit>=4.3.0', # Run checks before committing
'pytest>=8.4.2', # Run tests
'coverage>=7.11.0', # Generate coverage reports
'pypdf>=6.1.3', # Read PDF files
'snakeviz>=2.2.2', # Profiling
'pyinstaller>=6.16.0', # Build executables
]
features = ["full"] # to install full optional dependencies
[tool.hatch.envs.default.scripts]
# Hatch allows us to define scripts that can be run in the activated virtual environment
# with `hatch run ENV_NAME:SCRIPT_NAME`.
# Format all the code in the `rendercv` package with `black`:
format = "black rendercv docs tests && ruff check --fix && ruff format" # hatch run format
# Lint the code in the `rendercv` package with `ruff`:
lint = "ruff check" # hatch run lint
# Check types in the `rendercv` package with `pyright`:
check-types = "pyright rendercv tests" # hatch run check-types
# Run pre-commit checks:
precommit = "pre-commit run --all-files" # hatch run pre-commit
# Run the tests:
test = "pytest" # hatch run test
# Run the tests and generate the coverage report as HTML:
test-and-report = "coverage run -m pytest && coverage combine && coverage report && coverage html --show-contexts" # hatch run test-and-report
# Profile render command
profile-render-command = "python -m cProfile -o render_command.prof -m rendercv render examples/John_Doe_ClassicTheme_CV.yaml && snakeviz render_command.prof"
# Update schema.json:
update-schema = "python scripts/update_schema.py" # hatch run update-schema
# Update `examples` folder:
update-examples = "python scripts/update_examples.py" # hatch run update-examples
[tool.hatch.envs.test]
template = "default"
[[tool.hatch.envs.test.matrix]]
python = ["3.10", "3.11", "3.12", "3.13"]
[tool.hatch.envs.docs]
installer = "uv"
python = "3.13"
# Dependencies to be installed in the `docs` virtual environment.
dependencies = [
"mkdocs-material==9.6.12", # to build docs
"mkdocstrings-python==1.16.10", # to build reference documentation from docstrings
"pdfCropMargins==2.1.3", # to generate entry figures for the documentation
"pillow==10.4.0", # lock the dependency of pdfCropMargins
"mkdocs-macros-plugin==1.3.7", # to be able to have dynamic content in the documentation
"PyMuPDF==1.24.14", # to convert PDF files to images
docs = [
'mkdocs-material>=9.6.20',
'mkdocstrings[python]>=0.30.1', # Build reference docs from docstrings
'pdfCropMargins>=2.2.1', # Generate entry figures for documentation
'pillow>=10.4.0', # Lock dependency of pdfCropMargins
'mkdocs-macros-plugin>=1.4.0', # Enable dynamic content in docs
'PyMuPDF>=1.26.5', # Convert PDF files to images
]
features = ["full"] # to install full optional dependencies
[tool.hatch.envs.docs.scripts]
# Build the documentation with `mkdocs`:
build = "mkdocs build --clean --strict" # hatch run docs:build
# Start the development server for the documentation with `mkdocs`:
serve = "mkdocs serve" # hatch run docs:serve
# Update entry figures in "Structure of the YAML File" page:
update-entry-figures = "python scripts/update_entry_figures.py" # hatch run docs:update-entry-figures
[tool.hatch.envs.exe]
installer = "uv"
python = "3.13"
dependencies = [
"pyinstaller==6.11.1", # to build the executable
exe = [
'pyinstaller>=6.16.0', # Build executables
]
features = ["full"]
[tool.hatch.envs.exe.scripts]
create = "python scripts/create_executable.py" # hatch run exe:create
# ======================================================================================
# Virtual Environments Above ===========================================================
# ======================================================================================
# RenderCV uses different tools to check the code quality, format the code, build the
# documentation, build the package, etc. We can specify the settings for these tools in
# `pyproject.toml` file under `[tool.name_of_the_tool]` so that new contributors can use
# these tools easily. Generally, popular IDEs grab these settings from `pyproject.toml`
# file automatically.
# Tools Settings:
# RenderCV uses various tools to check code quality, format code, build docs, and package the project.
# Their configurations are specified below so contributors and IDEs can pick them up automatically.
[tool.ruff]
line-length = 88
@@ -215,69 +136,54 @@ docstring-code-format = true
[tool.ruff.lint]
extend-select = [
"B", # flake8-bugbear
"I", # isort
"ARG", # flake8-unused-arguments
"C4", # flake8-comprehensions
"EM", # flake8-errmsg
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"G", # flake8-logging-format
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"RET", # flake8-return
"RUF", # Ruff-specific
"SIM", # flake8-simplify
"T20", # flake8-print
"UP", # pyupgrade
"YTT", # flake8-2020
"EXE", # flake8-executable
"NPY", # NumPy specific rules
"PD", # pandas-vet
'B', 'I', 'ARG', 'C4', 'EM', 'ICN', 'ISC', 'G', 'PGH', 'PIE', 'PL', 'PT', 'PTH', 'RET', 'RUF', 'SIM', 'T20', 'UP', 'YTT', 'EXE', 'NPY', 'PD',
]
ignore = [
"PLR", # Design related pylint codes
"ISC001", # Conflicts with formatter
"UP007", # I like Optional type
"PGH003", # It would be nice to not ignore this
'PLR', # Design-related pylint codes
'ISC001', # Conflicts with formatter
'UP007', # Allow Optional type
'PGH003', # Prefer not to ignore this
]
flake8-unused-arguments.ignore-variadic-names = true
[tool.black]
line-length = 88 # maximum line length
preview = true # to allow enable-unstable-feature
line-length = 88 # Maximum line length
preview = true # Enable preview features
enable-unstable-feature = [
"string_processing",
] # to break strings into multiple lines
'string_processing',
] # Break strings into multiple lines
[tool.pyright]
reportIncompatibleVariableOverride = false # disable this error type
reportIncompatibleMethodOverride = false # disable this error type
exclude = ["rendercv/themes/*"]
typeCheckingMode = 'standard'
enableTypeIgnoreComments = false
reportUnnecessaryTypeIgnoreComment = true
reportIncompatibleVariableOverride = false
reportIncompatibleMethodOverride = false
reportMissingTypeStubs = false
reportPrivateUsage = false
exclude = ['rendercv/themes/*']
[tool.coverage.run]
source = ['rendercv'] # The source to measure during execution
source = ['rendercv'] # Measure coverage in this source
concurrency = ['multiprocessing'] # For watcher tests
# Use relative paths instead of absolute paths, this is useful for combining coverage
# reports from different OSes:
# Use relative paths for cross-platform coverage merging:
relative_files = true
[tool.coverage.report]
# Don't include jinja templates in the coverage report:
omit = ["*.j2.*", "rendercv/__main__.py"]
# Exclude templates from coverage reports:
omit = ['*.j2.*', 'rendercv/__main__.py']
# Don't include these lines in the coverage report:
exclude_lines = ["if __name__ == .__main__.:"]
# Exclude specific lines from coverage:
exclude_lines = ['if __name__ == .__main__.:']
[tool.pytest.ini_options]
log_cli_level = 'INFO'
xfail_strict = true
addopts = [
"-ra", # Show extra test summary info for all tests
"-v", # Increase verbosity
"--strict-markers", # Don't allow unknown markers
"--strict-config", # Always fail if there are unknown configuration options
'-ra', # Show extra test summary info
'-v', # Increase verbosity
'--strict-markers', # Disallow unknown markers
'--strict-config', # Fail on unknown config options
]
testpaths = ["tests"]
testpaths = ['tests']

View File

@@ -1,9 +0,0 @@
from typing import Literal
from rendercv.themes.options import ThemeOptions, theme_options_theme_field_info
theme_options_theme_field_info.default = "classic"
class ClassicThemeOptions(ThemeOptions):
theme: Literal["classic"] = theme_options_theme_field_info

View File

@@ -1,127 +0,0 @@
from typing import Literal
import rendercv.themes.options as o
o.page_show_page_numbering_field_info.default = False
class Page(o.Page):
show_page_numbering: bool = o.page_show_page_numbering_field_info
o.header_name_font_family_field_info.default = "Raleway"
o.header_connections_font_family_field_info.default = "Raleway"
o.header_name_bold_field_info.default = False
o.header_alignment_field_info.default = "left"
class Header(o.Header):
name_font_family: o.FontFamily = o.header_name_font_family_field_info
name_bold: bool = o.header_name_bold_field_info
alignment: o.Alignment = o.header_alignment_field_info
connections_font_family: o.FontFamily = o.header_connections_font_family_field_info
o.links_use_external_link_icon_field_info.default = False
class Links(o.Links):
use_external_link_icon: bool = o.links_use_external_link_icon_field_info
o.text_font_family_field_info.default = "Raleway"
class Text(o.Text):
font_family: o.FontFamily = o.text_font_family_field_info
o.section_titles_font_family_field_info.default = "Raleway"
o.section_titles_bold_field_info.default = False
class SectionTitles(o.SectionTitles):
font_family: o.FontFamily = o.section_titles_font_family_field_info
bold: bool = o.section_titles_bold_field_info
o.highlights_left_margin_field_info.default = "0cm"
class Highlights(o.Highlights):
left_margin: o.TypstDimension = o.highlights_left_margin_field_info
o.education_entry_main_column_first_row_template_field_info.default = (
"**INSTITUTION**, AREA -- LOCATION"
)
o.entry_base_with_date_date_and_location_column_template_field_info.default = "DATE"
class EducationEntryOptions(o.EducationEntryOptions):
main_column_first_row_template: str = (
o.education_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.normal_entry_main_column_first_row_template_field_info.default = (
"**NAME** -- **LOCATION**"
)
class NormalEntryOptions(o.NormalEntryOptions):
main_column_first_row_template: str = (
o.normal_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.experience_entry_main_column_first_row_template_field_info.default = (
"**POSITION**, COMPANY -- LOCATION"
)
class ExperienceEntryOptions(o.ExperienceEntryOptions):
main_column_first_row_template: str = (
o.experience_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.entry_types_education_entry_field_info.default = EducationEntryOptions()
o.entry_types_normal_entry_field_info.default = NormalEntryOptions()
o.entry_types_experience_entry_field_info.default = ExperienceEntryOptions()
class EntryOptionsTypes(o.EntryTypes):
education_entry: EducationEntryOptions = o.entry_types_education_entry_field_info
normal_entry: NormalEntryOptions = o.entry_types_normal_entry_field_info
experience_entry: ExperienceEntryOptions = o.entry_types_experience_entry_field_info
o.theme_options_theme_field_info.default = "engineeringresumes"
o.theme_options_page_field_info.default = Page()
o.theme_options_header_field_info.default = Header()
o.theme_options_text_field_info.default = Text()
o.theme_options_entry_types_field_info.default = EntryOptionsTypes()
o.theme_options_highlights_field_info.default = Highlights()
o.theme_options_links_field_info.default = Links()
o.theme_options_section_titles_field_info.default = SectionTitles()
class EngineeringclassicThemeOptions(o.ThemeOptions):
theme: Literal["engineeringclassic"] = o.theme_options_theme_field_info
page: Page = o.theme_options_page_field_info
header: Header = o.theme_options_header_field_info
highlights: Highlights = o.theme_options_highlights_field_info
text: Text = o.theme_options_text_field_info
links: Links = o.theme_options_links_field_info
entry_types: EntryOptionsTypes = o.theme_options_entry_types_field_info
section_titles: SectionTitles = o.theme_options_section_titles_field_info

View File

@@ -1,195 +0,0 @@
from typing import Literal
import pydantic_extra_types.color as pydantic_color
import rendercv.themes.options as o
o.page_show_page_numbering_field_info.default = False
class Page(o.Page):
show_page_numbering: bool = o.page_show_page_numbering_field_info
o.header_name_font_family_field_info.default = "XCharter"
o.header_separator_between_connections_field_info.default = "|"
o.header_use_icons_for_connections_field_info.default = False
o.header_name_bold_field_info.default = False
o.header_name_font_size_field_info = "25pt"
o.header_connections_font_family_field_info.default = "XCharter"
o.header_use_urls_as_placeholders_for_connections_field_info.default = True
class Header(o.Header):
name_font_family: o.FontFamily = o.header_name_font_family_field_info
name_font_size: o.TypstDimension = o.header_name_font_size_field_info
name_bold: bool = o.header_name_bold_field_info
separator_between_connections: str = (
o.header_separator_between_connections_field_info
)
use_icons_for_connections: bool = o.header_use_icons_for_connections_field_info
use_urls_as_placeholders_for_connections: bool = (
o.header_use_urls_as_placeholders_for_connections_field_info
)
connections_font_family: o.FontFamily = o.header_connections_font_family_field_info
o.colors_name_field_info.default = "rgb(0,0,0)"
o.colors_connections_field_info.default = "rgb(0,0,0)"
o.colors_section_titles_field_info.default = "rgb(0,0,0)"
o.colors_links_field_info.default = "rgb(0,0,0)"
class Colors(o.Colors):
name: pydantic_color.Color = o.colors_name_field_info
connections: pydantic_color.Color = o.colors_connections_field_info
section_titles: pydantic_color.Color = o.colors_section_titles_field_info
links: pydantic_color.Color = o.colors_links_field_info
o.links_underline_field_info.default = True
o.links_use_external_link_icon_field_info.default = False
class Links(o.Links):
underline: bool = o.links_underline_field_info
use_external_link_icon: bool = o.links_use_external_link_icon_field_info
o.text_font_family_field_info.default = "XCharter"
o.text_leading_field_info.default = "0.6em"
class Text(o.Text):
font_family: o.FontFamily = o.text_font_family_field_info
leading: o.TypstDimension = o.text_leading_field_info
o.section_titles_type_field_info.default = "with-full-line"
o.section_titles_vertical_space_above_field_info.default = "0.55cm"
o.section_titles_vertical_space_below_field_info.default = "0.3cm"
o.section_titles_font_size_field_info.default = "1.2em"
o.section_titles_font_family_field_info.default = "XCharter"
class SectionTitles(o.SectionTitles):
font_family: o.FontFamily = o.section_titles_font_family_field_info
type: o.SectionTitleType = o.section_titles_type_field_info
vertical_space_above: o.TypstDimension = (
o.section_titles_vertical_space_above_field_info
)
vertical_space_below: o.TypstDimension = (
o.section_titles_vertical_space_below_field_info
)
font_size: o.TypstDimension = o.section_titles_font_size_field_info
o.entries_vertical_space_between_entries_field_info.default = "0.4cm"
o.entries_left_and_right_margin_field_info.default = "0cm"
class Entries(o.Entries):
vertical_space_between_entries: o.TypstDimension = (
o.entries_vertical_space_between_entries_field_info
)
left_and_right_margin: o.TypstDimension = o.entries_left_and_right_margin_field_info
o.highlights_left_margin_field_info.default = "0cm"
o.highlights_top_margin_field_info.default = "0.25cm"
o.highlights_vertical_space_between_highlights_field_info.default = "0.19cm"
o.highlights_horizontal_space_between_bullet_and_highlight_field_info.default = "0.3em"
class Highlights(o.Highlights):
left_margin: o.TypstDimension = o.highlights_left_margin_field_info
top_margin: o.TypstDimension = o.highlights_top_margin_field_info
horizontal_space_between_bullet_and_highlight: o.TypstDimension = (
o.highlights_horizontal_space_between_bullet_and_highlight_field_info
)
vertical_space_between_highlights: o.TypstDimension = (
o.highlights_vertical_space_between_highlights_field_info
)
o.education_entry_main_column_first_row_template_field_info.default = (
"**INSTITUTION**, DEGREE in AREA -- LOCATION"
)
o.education_entry_degree_column_template_field_info.default = None
o.entry_base_with_date_date_and_location_column_template_field_info.default = "DATE"
class EducationEntryOptions(o.EducationEntryOptions):
main_column_first_row_template: str = (
o.education_entry_main_column_first_row_template_field_info
)
degree_column_template: str | None = (
o.education_entry_degree_column_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.normal_entry_main_column_first_row_template_field_info.default = (
"**NAME** -- **LOCATION**"
)
class NormalEntryOptions(o.NormalEntryOptions):
main_column_first_row_template: str = (
o.normal_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.experience_entry_main_column_first_row_template_field_info.default = (
"**POSITION**, COMPANY -- LOCATION"
)
class ExperienceEntryOptions(o.ExperienceEntryOptions):
main_column_first_row_template: str = (
o.experience_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.entry_types_education_entry_field_info.default = EducationEntryOptions()
o.entry_types_normal_entry_field_info.default = NormalEntryOptions()
o.entry_types_experience_entry_field_info.default = ExperienceEntryOptions()
class EntryOptionsTypes(o.EntryTypes):
education_entry: EducationEntryOptions = o.entry_types_education_entry_field_info
normal_entry: NormalEntryOptions = o.entry_types_normal_entry_field_info
experience_entry: ExperienceEntryOptions = o.entry_types_experience_entry_field_info
o.theme_options_theme_field_info.default = "engineeringresumes"
o.theme_options_page_field_info.default = Page()
o.theme_options_header_field_info.default = Header()
o.theme_options_text_field_info.default = Text()
o.theme_options_colors_field_info.default = Colors()
o.theme_options_entry_types_field_info.default = EntryOptionsTypes()
o.theme_options_section_titles_field_info.default = SectionTitles()
o.theme_options_highlights_field_info.default = Highlights()
o.theme_options_links_field_info.default = Links()
o.theme_options_entries_field_info.default = Entries()
class EngineeringresumesThemeOptions(o.ThemeOptions):
theme: Literal["engineeringresumes"] = o.theme_options_theme_field_info
page: Page = o.theme_options_page_field_info
header: Header = o.theme_options_header_field_info
highlights: Highlights = o.theme_options_highlights_field_info
text: Text = o.theme_options_text_field_info
colors: Colors = o.theme_options_colors_field_info
links: Links = o.theme_options_links_field_info
entries: Entries = o.theme_options_entries_field_info
entry_types: EntryOptionsTypes = o.theme_options_entry_types_field_info
section_titles: SectionTitles = o.theme_options_section_titles_field_info

View File

@@ -1,169 +0,0 @@
from typing import Literal
import rendercv.themes.options as o
o.header_name_font_family_field_info.default = "Fontin"
o.header_name_bold_field_info.default = False
o.header_name_font_size_field_info = "25pt"
o.header_alignment_field_info.default = "left"
o.header_connections_font_family_field_info.default = "Fontin"
class Header(o.Header):
name_font_family: o.FontFamily = o.header_name_font_family_field_info
name_font_size: o.TypstDimension = o.header_name_font_size_field_info
name_bold: bool = o.header_name_bold_field_info
alignment: o.Alignment = o.header_alignment_field_info
connections_font_family: o.FontFamily = o.header_connections_font_family_field_info
o.links_underline_field_info.default = True
o.links_use_external_link_icon_field_info.default = False
class Links(o.Links):
underline: bool = o.links_underline_field_info
use_external_link_icon: bool = o.links_use_external_link_icon_field_info
o.text_font_family_field_info.default = "Fontin"
o.text_leading_field_info.default = "0.6em"
class Text(o.Text):
font_family: o.FontFamily = o.text_font_family_field_info
leading: o.TypstDimension = o.text_leading_field_info
o.section_titles_type_field_info.default = "moderncv"
o.section_titles_bold_field_info.default = False
o.section_titles_vertical_space_above_field_info.default = "0.55cm"
o.section_titles_vertical_space_below_field_info.default = "0.3cm"
o.section_titles_font_size_field_info.default = "1.4em"
o.section_titles_line_thickness_field_info.default = "0.15cm"
o.section_titles_font_family_field_info.default = "Fontin"
class SectionTitles(o.SectionTitles):
font_family: o.FontFamily = o.section_titles_font_family_field_info
type: o.SectionTitleType = o.section_titles_type_field_info
vertical_space_above: o.TypstDimension = (
o.section_titles_vertical_space_above_field_info
)
vertical_space_below: o.TypstDimension = (
o.section_titles_vertical_space_below_field_info
)
font_size: o.TypstDimension = o.section_titles_font_size_field_info
bold: bool = o.section_titles_bold_field_info
line_thickness: o.TypstDimension = o.section_titles_line_thickness_field_info
o.entries_vertical_space_between_entries_field_info.default = "0.4cm"
o.entries_left_and_right_margin_field_info.default = "0cm"
o.entries_horizontal_space_between_columns_field_info.default = "0.4cm"
class Entries(o.Entries):
vertical_space_between_entries: o.TypstDimension = (
o.entries_vertical_space_between_entries_field_info
)
left_and_right_margin: o.TypstDimension = o.entries_left_and_right_margin_field_info
horizontal_space_between_columns: o.TypstDimension = (
o.entries_horizontal_space_between_columns_field_info
)
o.highlights_left_margin_field_info.default = "0cm"
o.highlights_top_margin_field_info.default = "0.25cm"
o.highlights_vertical_space_between_highlights_field_info.default = "0.19cm"
o.highlights_horizontal_space_between_bullet_and_highlight_field_info.default = "0.3em"
class Highlights(o.Highlights):
left_margin: o.TypstDimension = o.highlights_left_margin_field_info
top_margin: o.TypstDimension = o.highlights_top_margin_field_info
horizontal_space_between_bullet_and_highlight: o.TypstDimension = (
o.highlights_horizontal_space_between_bullet_and_highlight_field_info
)
vertical_space_between_highlights: o.TypstDimension = (
o.highlights_vertical_space_between_highlights_field_info
)
o.education_entry_main_column_first_row_template_field_info.default = (
"**INSTITUTION**, DEGREE in AREA -- LOCATION"
)
o.education_entry_degree_column_template_field_info.default = None
o.entry_base_with_date_date_and_location_column_template_field_info.default = "DATE"
class EducationEntryOptions(o.EducationEntryOptions):
main_column_first_row_template: str = (
o.education_entry_main_column_first_row_template_field_info
)
degree_column_template: str | None = (
o.education_entry_degree_column_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.normal_entry_main_column_first_row_template_field_info.default = (
"**NAME** -- **LOCATION**"
)
class NormalEntryOptions(o.NormalEntryOptions):
main_column_first_row_template: str = (
o.normal_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.experience_entry_main_column_first_row_template_field_info.default = (
"**POSITION**, COMPANY -- LOCATION"
)
class ExperienceEntryOptions(o.ExperienceEntryOptions):
main_column_first_row_template: str = (
o.experience_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.entry_types_education_entry_field_info.default = EducationEntryOptions()
o.entry_types_normal_entry_field_info.default = NormalEntryOptions()
o.entry_types_experience_entry_field_info.default = ExperienceEntryOptions()
class EntryOptionsTypes(o.EntryTypes):
education_entry: EducationEntryOptions = o.entry_types_education_entry_field_info
normal_entry: NormalEntryOptions = o.entry_types_normal_entry_field_info
experience_entry: ExperienceEntryOptions = o.entry_types_experience_entry_field_info
o.theme_options_theme_field_info.default = "moderncv"
o.theme_options_header_field_info.default = Header()
o.theme_options_text_field_info.default = Text()
o.theme_options_entry_types_field_info.default = EntryOptionsTypes()
o.theme_options_section_titles_field_info.default = SectionTitles()
o.theme_options_highlights_field_info.default = Highlights()
o.theme_options_links_field_info.default = Links()
o.theme_options_entries_field_info.default = Entries()
class ModerncvThemeOptions(o.ThemeOptions):
theme: Literal["moderncv"] = o.theme_options_theme_field_info
header: Header = o.theme_options_header_field_info
highlights: Highlights = o.theme_options_highlights_field_info
text: Text = o.theme_options_text_field_info
links: Links = o.theme_options_links_field_info
entries: Entries = o.theme_options_entries_field_info
entry_types: EntryOptionsTypes = o.theme_options_entry_types_field_info
section_titles: SectionTitles = o.theme_options_section_titles_field_info

View File

@@ -1,978 +0,0 @@
"""
The `rendercv.themes.options` module contains the standard data models for the Typst
themes' design options. To avoid code duplication, the themes are encouraged to inherit
from these data models.
"""
import pathlib
import re
from typing import Annotated, Literal
import pydantic
import pydantic_extra_types.color as pydantic_color
from ..data.models.base import RenderCVBaseModelWithoutExtraKeys
# Custom field types:
def validate_typst_dimension(dimension: str) -> str:
"""Check if the input string is a valid dimension for the Typst theme.
Args:
dimension: The input string to be validated.
Returns:
The input string itself if it is a valid dimension.
"""
if not re.fullmatch(r"\d+\.?\d*(cm|in|pt|mm|ex|em)", dimension):
message = (
"The value must be a number followed by a unit (cm, in, pt, mm, ex, em)."
" For example, 0.1cm."
)
raise ValueError(message)
return dimension
TypstDimension = Annotated[
str,
pydantic.AfterValidator(validate_typst_dimension),
]
try:
import rendercv_fonts
available_font_families = [
"Libertinus Serif",
"New Computer Modern",
"DejaVu Sans Mono",
*rendercv_fonts.available_font_families,
# Common system fonts
"Arial",
"Helvetica",
"Tahoma",
"Times New Roman",
"Verdana",
"Calibri",
"Georgia",
"Aptos",
"Cambria",
"Inter",
"Garamond",
"Montserrat",
"Candara",
"Gill Sans",
"Didot",
"Playfair Display",
]
if "Font Awesome 6" in available_font_families:
available_font_families.remove("Font Awesome 6")
available_font_families = sorted(set(available_font_families))
except ImportError:
available_font_families = [
"Libertinus Serif",
"New Computer Modern",
"DejaVu Sans Mono",
"Mukta",
"Open Sans",
"Gentium Book Plus",
"Noto Sans",
"Lato",
"Source Sans 3",
"EB Garamond",
"Open Sauce Sans",
"Fontin",
"Roboto",
"Ubuntu",
"Poppins",
"Raleway",
"XCharter",
# Common system fonts
"Arial",
"Helvetica",
"Tahoma",
"Times New Roman",
"Verdana",
"Calibri",
"Georgia",
"Aptos",
"Cambria",
"Inter",
"Garamond",
"Montserrat",
"Candara",
"Gill Sans",
"Didot",
"Playfair Display",
]
available_font_families = sorted(set(available_font_families))
font_family_validator = pydantic.TypeAdapter(Literal[tuple(available_font_families)])
def validate_font_family(font_family: str) -> str:
"""Check if the input string is a valid font family.
Args:
font_family: The input string to be validated.
Returns:
The input string itself if it is a valid font family.
"""
if (pathlib.Path("fonts")).exists():
# Then allow custom font families.
return font_family
try:
font_family_validator.validate_strings(font_family)
except pydantic.ValidationError as e:
message = (
"The font family must be one of the following:"
f" {', '.join(available_font_families)}."
)
raise ValueError(message) from e
return font_family_validator.validate_strings(font_family)
FontFamily = Annotated[
str,
pydantic.PlainValidator(
validate_font_family,
json_schema_input_type=Literal[tuple(available_font_families)],
),
]
BulletPoint = Literal["", "", "-", "", "", "", "", ""]
PageSize = Literal[
"a0",
"a1",
"a2",
"a3",
"a4",
"a5",
"a6",
"a7",
"a8",
"us-letter",
"us-legal",
"us-executive",
"us-gov-letter",
"us-gov-legal",
"us-business-card",
"presentation-16-9",
"presentation-4-3",
]
Alignment = Literal["left", "center", "right"]
TextAlignment = Literal["left", "justified", "justified-with-no-hyphenation"]
SectionTitleType = Literal[
"with-partial-line", "with-full-line", "without-line", "moderncv"
]
page_size_field_info: PageSize = pydantic.Field(
default="us-letter",
title="Page Size",
description="The page size of the CV.",
)
page_top_margin_field_info = pydantic.Field(
default="2cm",
title="Top Margin",
description="The top margin of the page with units (cm, in, pt, mm, ex, em)",
)
page_bottom_margin_field_info = pydantic.Field(
default="2cm",
title="Bottom Margin",
description="The bottom margin of the page with units (cm, in, pt, mm, ex, em)",
)
page_left_margin_field_info = pydantic.Field(
default="2cm",
title="Left Margin",
description="The left margin of the page with units (cm, in, pt, mm, ex, em)",
)
page_right_margin_field_info = pydantic.Field(
default="2cm",
title="Right Margin",
description="The right margin of the page with units (cm, in, pt, mm, ex, em)",
)
page_show_page_numbering_field_info = pydantic.Field(
default=True,
title="Show Page Numbering",
description=(
'If this option is "true", the page numbering will be shown in the footer.'
),
)
page_show_last_updated_date_field_info = pydantic.Field(
default=True,
title="Show Last Updated Date",
description=(
'If this option is "true", the last updated date will be shown in the footer.'
),
)
class Page(RenderCVBaseModelWithoutExtraKeys):
"""Options related to the page."""
model_config = pydantic.ConfigDict(title="Page")
size: PageSize = page_size_field_info
top_margin: TypstDimension = page_top_margin_field_info
bottom_margin: TypstDimension = page_bottom_margin_field_info
left_margin: TypstDimension = page_left_margin_field_info
right_margin: TypstDimension = page_right_margin_field_info
show_page_numbering: bool = page_show_page_numbering_field_info
show_last_updated_date: bool = page_show_last_updated_date_field_info
color_common_description = (
"\nThe color can be specified either with their name"
" (https://www.w3.org/TR/SVG11/types.html#ColorKeywords), hexadecimal value, RGB"
" value, or HSL value."
)
color_common_examples = ["Black", "7fffd4", "rgb(0,79,144)", "hsl(270, 60%, 70%)"]
colors_text_field_info = pydantic.Field(
default=pydantic_color.Color("rgb(0,0,0)"),
title="Color of Text",
description="The color of the text." + color_common_description,
examples=color_common_examples,
)
colors_name_field_info = pydantic.Field(
default=pydantic_color.Color("rgb(0,79,144)"),
title="Color of Name",
description=("The color of the name in the header." + color_common_description),
examples=color_common_examples,
)
colors_connections_field_info = pydantic.Field(
default=pydantic_color.Color("rgb(0,79,144)"),
title="Color of Connections",
description=(
"The color of the connections in the header." + color_common_description
),
examples=color_common_examples,
)
colors_section_titles_field_info = pydantic.Field(
default=pydantic_color.Color("rgb(0,79,144)"),
title="Color of Section Titles",
description=("The color of the section titles." + color_common_description),
examples=color_common_examples,
)
colors_links_field_info = pydantic.Field(
default=pydantic_color.Color("rgb(0,79,144)"),
title="Color of Links",
description="The color of the links." + color_common_description,
examples=color_common_examples,
)
colors_last_updated_date_and_page_numbering_field_info = pydantic.Field(
default=pydantic_color.Color("rgb(128,128,128)"),
title="Color of Last Updated Date and Page Numbering",
description=(
"The color of the last updated date and page numbering."
+ color_common_description
),
examples=color_common_examples,
)
class Colors(RenderCVBaseModelWithoutExtraKeys):
"""Color used throughout the CV."""
model_config = pydantic.ConfigDict(title="Colors")
text: pydantic_color.Color = colors_text_field_info
name: pydantic_color.Color = colors_name_field_info
connections: pydantic_color.Color = colors_connections_field_info
section_titles: pydantic_color.Color = colors_section_titles_field_info
links: pydantic_color.Color = colors_links_field_info
last_updated_date_and_page_numbering: pydantic_color.Color = (
colors_last_updated_date_and_page_numbering_field_info
)
@pydantic.field_serializer(
"text",
"name",
"connections",
"section_titles",
"links",
"last_updated_date_and_page_numbering",
)
def serialize_color(self, value: pydantic_color.Color) -> str:
return value.as_rgb()
text_font_family_field_info = pydantic.Field(
default="Source Sans 3",
title="Font Family",
description="The font family.",
)
text_font_size_field_info = pydantic.Field(
default="10pt",
title="Font Size",
description="The font size of the text.",
)
text_leading_field_info = pydantic.Field(
default="0.6em",
title="Leading",
description="The vertical space between adjacent lines of text.",
)
text_alignment_field_info: TextAlignment = pydantic.Field(
default="justified",
title="Alignment of Text",
description="The alignment of the text.",
)
text_date_and_location_column_alignment_field_info: Alignment = pydantic.Field(
default="right",
title="Alignment of Date and Location Column",
description="The alignment of the date column in the entries.",
)
class Text(RenderCVBaseModelWithoutExtraKeys):
"""Options related to text."""
model_config = pydantic.ConfigDict(title="Text")
font_family: FontFamily = text_font_family_field_info
font_size: TypstDimension = text_font_size_field_info
leading: TypstDimension = text_leading_field_info
alignment: TextAlignment = text_alignment_field_info
date_and_location_column_alignment: Alignment = (
text_date_and_location_column_alignment_field_info
)
links_underline_field_info = pydantic.Field(
default=False,
title="Underline Links",
description='If this option is "true", links will be underlined.',
)
links_use_external_link_icon_field_info = pydantic.Field(
default=True,
title="Use External Link Icon",
description=(
'If this option is "true", an external link icon will be shown next to the'
" links."
),
)
class Links(RenderCVBaseModelWithoutExtraKeys):
"""Options related to links."""
model_config = pydantic.ConfigDict(title="Links")
underline: bool = links_underline_field_info
use_external_link_icon: bool = links_use_external_link_icon_field_info
header_name_font_family_field_info = pydantic.Field(
default="Source Sans 3",
title="Name Font Family",
description="The font family of the name in the header.",
)
header_name_font_size_field_info = pydantic.Field(
default="30pt",
title="Name Font Size",
description="The font size of the name in the header.",
)
header_name_bold_field_info = pydantic.Field(
default=True,
title="Bold Name",
description='If this option is "true", the name in the header will be bold.',
)
header_small_caps_for_name_field_info = pydantic.Field(
default=False,
title="Small Caps for Name",
description=(
'If this option is "true", the name in the header will be in small caps.'
),
)
header_photo_width_field_info = pydantic.Field(
default="3.5cm",
title="Width of the Photo",
description="The width of the photo in the header.",
)
header_vertical_space_name_connections_field_info = pydantic.Field(
default="0.7cm",
title="Vertical Margin Between the Name and Connections",
description=(
"The vertical margin between the name of the person and the connections."
),
)
header_vertical_space_connections_first_section_field_info = pydantic.Field(
default="0.7cm",
title="Vertical Margin Between Connections and First Section",
description=(
"The vertical margin between the connections and the first section title."
),
)
header_horizontal_space_connections_field_info = pydantic.Field(
default="0.5cm",
title="Space Between Connections",
description="The space between the connections (like phone, email, and website).",
)
header_separator_between_connections_field_info = pydantic.Field(
default=None,
title="Separator Between Connections",
description="The separator between the connections in the header.",
)
header_connections_font_family_field_info = pydantic.Field(
default="Source Sans 3",
title="Connections Font Family",
description="The font family of the connections in the header.",
)
header_use_icons_for_connections_field_info = pydantic.Field(
default=True,
title="Use Icons for Connections",
description=(
'If this option is "true", icons will be used for the connections'
" (phone number, email, social networks, etc.) in the header."
),
)
header_use_urls_as_placeholders_for_connections_field_info = pydantic.Field(
default=False,
title="Use URLs as Placeholders for Connections",
description=(
'If this option is "true", the URLs will be used as placeholders for the'
" connections."
),
)
make_connections_links_field_info = pydantic.Field(
default=True,
title="Make Connections Links",
description='If this option is "true", the connections will be clickable links.',
)
header_alignment_field_info: Alignment = pydantic.Field(
default="center",
title="Alignment of the Header",
description="The alignment of the header.",
)
class Header(RenderCVBaseModelWithoutExtraKeys):
"""Options related to headers."""
model_config = pydantic.ConfigDict(title="Header")
name_font_family: FontFamily = header_name_font_family_field_info
name_font_size: TypstDimension = header_name_font_size_field_info
name_bold: bool = header_name_bold_field_info
small_caps_for_name: bool = header_small_caps_for_name_field_info
photo_width: TypstDimension = header_photo_width_field_info
vertical_space_between_name_and_connections: TypstDimension = (
header_vertical_space_name_connections_field_info
)
vertical_space_between_connections_and_first_section: TypstDimension = (
header_vertical_space_connections_first_section_field_info
)
horizontal_space_between_connections: TypstDimension = (
header_horizontal_space_connections_field_info
)
connections_font_family: FontFamily = header_connections_font_family_field_info
separator_between_connections: str | None = (
header_separator_between_connections_field_info
)
use_icons_for_connections: bool = header_use_icons_for_connections_field_info
use_urls_as_placeholders_for_connections: bool = (
header_use_urls_as_placeholders_for_connections_field_info
)
make_connections_links: bool = make_connections_links_field_info
alignment: Alignment = header_alignment_field_info
@pydantic.field_validator("separator_between_connections")
def validate_separator_between_connections(cls, value: str | None) -> str:
if value is None:
return ""
return value
section_titles_font_family_field_info = pydantic.Field(
default="Source Sans 3",
title="Font Family",
description="The font family of the section titles.",
)
section_titles_font_size_field_info = pydantic.Field(
default="1.4em",
title="Font Size",
description="The font size of the section titles.",
)
section_titles_bold_field_info = pydantic.Field(
default=True,
title="Bold Section Titles",
description='If this option is "true", the section titles will be bold.',
)
section_titles_type_field_info: SectionTitleType = pydantic.Field(
default="with-partial-line",
title="Type",
description="The type of the section titles.",
)
section_titles_line_thickness_field_info = pydantic.Field(
default="0.5pt",
title="Line Thickness",
description="The thickness of the line under the section titles.",
)
section_titles_vertical_space_above_field_info = pydantic.Field(
default="0.5cm",
title="Vertical Space Above Section Titles",
description="The vertical space above the section titles.",
)
section_titles_vertical_space_below_field_info = pydantic.Field(
default="0.3cm",
title="Vertical Space Below Section Titles",
description="The vertical space below the section titles.",
)
section_titles_small_caps_field_info = pydantic.Field(
default=False,
title="Small Caps",
description='If this option is "true", the section titles will be in small caps.',
)
class SectionTitles(RenderCVBaseModelWithoutExtraKeys):
"""Options related to section titles."""
model_config = pydantic.ConfigDict(title="Section Titles")
type: SectionTitleType = section_titles_type_field_info
font_family: FontFamily = section_titles_font_family_field_info
font_size: TypstDimension = section_titles_font_size_field_info
bold: bool = section_titles_bold_field_info
small_caps: bool = section_titles_small_caps_field_info
line_thickness: TypstDimension = section_titles_line_thickness_field_info
vertical_space_above: TypstDimension = (
section_titles_vertical_space_above_field_info
)
vertical_space_below: TypstDimension = (
section_titles_vertical_space_below_field_info
)
entries_date_and_location_width_field_info = pydantic.Field(
default="4.15cm",
title="Width of Date and Location",
description="The width of the date and location in the entries.",
)
entries_left_and_right_margin_field_info = pydantic.Field(
default="0.2cm",
title="Left and Right Margin",
description="The left and right margin of the entries.",
)
entries_horizontal_space_between_columns_field_info = pydantic.Field(
default="0.1cm",
title="Horizontal Space Between Columns",
description="The horizontal space between the columns in the entries.",
)
entries_vertical_space_between_entries_field_info = pydantic.Field(
default="1.2em",
title="Vertical Space Between Entries",
description="The vertical space between the entries.",
)
entries_allow_page_break_in_sections_field_info = pydantic.Field(
default=True,
title="Allow Page Break in Sections",
description=(
'If this option is "true", a page break will be allowed in the sections.'
),
)
entries_allow_page_break_in_entries_field_info = pydantic.Field(
default=True,
title="Allow Page Break in Entries",
description=(
'If this option is "true", a page break will be allowed in the entries.'
),
)
entries_short_second_row_field_info = pydantic.Field(
default=False,
title="Short Second Row",
description=(
'If this option is "true", second row will be shortened to leave the bottom'
" of the date empty."
),
)
entries_show_time_spans_in_field_info = pydantic.Field(
default=[],
title="Show Time Spans in",
description=(
"The list of section titles where the time spans will be shown in the entries."
),
)
class Entries(RenderCVBaseModelWithoutExtraKeys):
"""Options related to entries."""
model_config = pydantic.ConfigDict(title="Entries")
date_and_location_width: TypstDimension = entries_date_and_location_width_field_info
left_and_right_margin: TypstDimension = entries_left_and_right_margin_field_info
horizontal_space_between_columns: TypstDimension = (
entries_horizontal_space_between_columns_field_info
)
vertical_space_between_entries: TypstDimension = (
entries_vertical_space_between_entries_field_info
)
allow_page_break_in_sections: bool = entries_allow_page_break_in_sections_field_info
allow_page_break_in_entries: bool = entries_allow_page_break_in_entries_field_info
short_second_row: bool = entries_short_second_row_field_info
show_time_spans_in: list[str] = entries_show_time_spans_in_field_info
highlights_bullet_field_info: BulletPoint = pydantic.Field(
default="",
title="Bullet",
description="The bullet used for the highlights and bullet entries.",
)
highlights_nested_bullet_field_info: BulletPoint = pydantic.Field(
default="-",
title="Nested Bullet",
description="The bullet used for the nested highlights.",
)
highlights_top_margin_field_info = pydantic.Field(
default="0.25cm",
title="Top Margin",
description="The top margin of the highlights.",
)
highlights_left_margin_field_info = pydantic.Field(
default="0.4cm",
title="Left Margin",
description="The left margin of the highlights.",
)
highlights_vertical_space_between_highlights_field_info = pydantic.Field(
default="0.25cm",
title="Vertical Space Between Highlights",
description="The vertical space between the highlights.",
)
highlights_horizontal_space_between_bullet_and_highlight_field_info = pydantic.Field(
default="0.5em",
title="Horizontal Space Between Bullet and Highlight",
description="The horizontal space between the bullet and the highlight.",
)
highlights_summary_left_margin_field_info = pydantic.Field(
default="0cm",
title="Left Margin of the Summary",
description="The left margin of the summary.",
)
class Highlights(RenderCVBaseModelWithoutExtraKeys):
"""Options related to highlights."""
model_config = pydantic.ConfigDict(title="Highlights")
bullet: BulletPoint = highlights_bullet_field_info
nested_bullet: BulletPoint = highlights_nested_bullet_field_info
top_margin: TypstDimension = highlights_top_margin_field_info
left_margin: TypstDimension = highlights_left_margin_field_info
vertical_space_between_highlights: TypstDimension = (
highlights_vertical_space_between_highlights_field_info
)
horizontal_space_between_bullet_and_highlight: TypstDimension = (
highlights_horizontal_space_between_bullet_and_highlight_field_info
)
summary_left_margin: TypstDimension = highlights_summary_left_margin_field_info
entry_base_with_date_main_column_second_row_template_field_info = pydantic.Field(
default="SUMMARY\nHIGHLIGHTS",
title="Main Column, Second Row",
description=(
"The content of the second row of the Main Column. The available placeholders"
" are all the keys used in the entries (in uppercase)."
),
)
entry_base_with_date_date_and_location_column_template_field_info = pydantic.Field(
default="LOCATION\nDATE",
title="Date and Location Column",
description=(
"The content of the Date and Location Column. The available placeholders are"
" all the keys used in the entries (in uppercase)."
),
)
class EntryBaseWithDate(RenderCVBaseModelWithoutExtraKeys):
"""Base options for entries with a date."""
main_column_second_row_template: str = (
entry_base_with_date_main_column_second_row_template_field_info
)
date_and_location_column_template: str = (
entry_base_with_date_date_and_location_column_template_field_info
)
publication_entry_main_column_first_row_template_field_info = pydantic.Field(
default="**TITLE**",
title="Main Column",
description=(
"The content of the Main Column. The available placeholders are all the keys"
" used in the entries (in uppercase)."
),
)
publication_entry_main_column_second_row_template_field_info = pydantic.Field(
default="AUTHORS\nURL (JOURNAL)",
title="Main Column, Second Row",
description=(
"The content of the second row of the Main Column. The available placeholders"
" are all the keys used in the entries (in uppercase)."
),
)
publication_entry_main_column_second_row_without_journal_template_field_info = pydantic.Field(
default="AUTHORS\nURL",
title="Main Column, Second Row Without Journal",
description=(
"The content of the Main Column in case the journal is not given. The"
" available placeholders are all the keys used in the entries (in uppercase)."
),
)
publication_entry_main_column_second_row_without_url_template_field_info = pydantic.Field(
default="AUTHORS\nJOURNAL",
title="Main Column, Second Row Without URL",
description=(
"The content of the Main Column in case the `doi` or `url is not given. The"
" available placeholders are all the keys used in the entries (in uppercase)."
),
)
publication_entry_date_and_location_column_template_field_info = pydantic.Field(
default="DATE",
title="Date and Location Column",
description=(
"The content of the Date and Location Column. The available placeholders are"
" all the keys used in the entries (in uppercase)."
),
)
class PublicationEntryOptions(RenderCVBaseModelWithoutExtraKeys):
"""Options related to publication entries."""
model_config = pydantic.ConfigDict(title="Publication Entry Options")
main_column_first_row_template: str = (
publication_entry_main_column_first_row_template_field_info
)
main_column_second_row_template: str = (
publication_entry_main_column_second_row_template_field_info
)
main_column_second_row_without_journal_template: str = (
publication_entry_main_column_second_row_without_journal_template_field_info
)
main_column_second_row_without_url_template: str = (
publication_entry_main_column_second_row_without_url_template_field_info
)
date_and_location_column_template: str = (
publication_entry_date_and_location_column_template_field_info
)
education_entry_main_column_first_row_template_field_info = pydantic.Field(
default="**INSTITUTION**, AREA",
title="Main Column, First Row",
description=(
"The content of the Main Column. The available placeholders are all the keys"
" used in the entries (in uppercase)."
),
)
education_entry_degree_column_template_field_info = pydantic.Field(
default="**DEGREE**",
title="Template of the Degree Column",
description=(
'If given, a degree column will be added to the education entry. If "null",'
" no degree column will be shown. The available placeholders are all the"
" keys used in the entries (in uppercase)."
),
)
education_entry_degree_column_width_field_info = pydantic.Field(
default="1cm",
title="Width of the Degree Column",
description=(
'The width of the degree column if the "degree_column_template" is given.'
),
)
class EducationEntryBase(RenderCVBaseModelWithoutExtraKeys):
"""Base options for education entries."""
main_column_first_row_template: str = (
education_entry_main_column_first_row_template_field_info
)
degree_column_template: str | None = (
education_entry_degree_column_template_field_info
)
degree_column_width: TypstDimension = education_entry_degree_column_width_field_info
class EducationEntryOptions(EntryBaseWithDate, EducationEntryBase):
"""Options related to education entries."""
model_config = pydantic.ConfigDict(title="Education Entry Options")
normal_entry_main_column_first_row_template_field_info = pydantic.Field(
default="**NAME**",
title="Main Column, First Row",
description=(
"The content of the Main Column. The available placeholders are all the"
" keys used in the entries (in uppercase)."
),
)
class NormalEntryBase(RenderCVBaseModelWithoutExtraKeys):
"""Base options for normal entries."""
main_column_first_row_template: str = (
normal_entry_main_column_first_row_template_field_info
)
class NormalEntryOptions(EntryBaseWithDate, NormalEntryBase):
"""Options related to normal entries."""
model_config = pydantic.ConfigDict(title="Normal Entry Options")
experience_entry_main_column_first_row_template_field_info = pydantic.Field(
default="**COMPANY**, POSITION",
title="Main Column, First Row",
description=(
"The content of the Main Column. The available placeholders are all the keys"
" used in the entries (in uppercase)."
),
)
class ExperienceEntryBase(RenderCVBaseModelWithoutExtraKeys):
"""Base options for experience entries."""
main_column_first_row_template: str = (
experience_entry_main_column_first_row_template_field_info
)
class ExperienceEntryOptions(EntryBaseWithDate, ExperienceEntryBase):
"""Options related to experience entries."""
model_config = pydantic.ConfigDict(title="Experience Entry Options")
one_line_entry_template_field_info = pydantic.Field(
default="**LABEL:** DETAILS",
title="Template",
description=(
"The template of the one-line entry. The available placeholders are all the"
" keys used in the entries (in uppercase)."
),
)
class OneLineEntryOptions(RenderCVBaseModelWithoutExtraKeys):
"""Options related to one-line entries."""
model_config = pydantic.ConfigDict(title="One Line Entry Options")
template: str = one_line_entry_template_field_info
entry_types_one_line_entry_field_info = pydantic.Field(
default=OneLineEntryOptions(),
title="One-Line Entry",
description="Options related to one-line entries.",
)
entry_types_education_entry_field_info = pydantic.Field(
default=EducationEntryOptions(),
title="Education Entry",
description="Options related to education entries.",
)
entry_types_normal_entry_field_info = pydantic.Field(
default=NormalEntryOptions(),
title="Normal Entry",
description="Options related to normal entries.",
)
entry_types_experience_entry_field_info = pydantic.Field(
default=ExperienceEntryOptions(),
title="Experience Entry",
description="Options related to experience entries.",
)
entry_types_publication_entry_field_info = pydantic.Field(
default=PublicationEntryOptions(),
title="Publication Entry",
description="Options related to publication entries.",
)
class EntryTypes(RenderCVBaseModelWithoutExtraKeys):
"""Options related to the templates."""
model_config = pydantic.ConfigDict(title="Entry Types")
one_line_entry: OneLineEntryOptions = entry_types_one_line_entry_field_info
education_entry: EducationEntryOptions = entry_types_education_entry_field_info
normal_entry: NormalEntryOptions = entry_types_normal_entry_field_info
experience_entry: ExperienceEntryOptions = entry_types_experience_entry_field_info
publication_entry: PublicationEntryOptions = (
entry_types_publication_entry_field_info
)
theme_options_theme_field_info = pydantic.Field(
default="tobeoverwritten",
title="Theme",
description="The theme of the CV. It just changes the default values.",
)
theme_options_page_field_info = pydantic.Field(
default=Page(),
title="Page",
description="Options related to the page.",
)
theme_options_colors_field_info = pydantic.Field(
default=Colors(),
title="Colors",
description="Color used throughout the CV.",
)
theme_options_text_field_info = pydantic.Field(
default=Text(),
title="Text",
description="Options related to text.",
)
theme_options_links_field_info = pydantic.Field(
default=Links(),
title="Links",
description="Options related to links.",
)
theme_options_header_field_info = pydantic.Field(
default=Header(),
title="Headers",
description="Options related to headers.",
)
theme_options_section_titles_field_info = pydantic.Field(
default=SectionTitles(),
title="Section Titles",
description="Options related to section titles.",
)
theme_options_entries_field_info = pydantic.Field(
default=Entries(),
title="Entries",
description="Options related to entries.",
)
theme_options_highlights_field_info = pydantic.Field(
default=Highlights(),
title="Highlights",
description="Options related to highlights.",
)
theme_options_entry_types_field_info = pydantic.Field(
default=EntryTypes(),
title="Templates",
description="Options related to the templates.",
)
class ThemeOptions(RenderCVBaseModelWithoutExtraKeys):
"""Full design options."""
model_config = pydantic.ConfigDict(title="Theme Options")
theme: str = theme_options_theme_field_info
page: Page = theme_options_page_field_info
colors: Colors = theme_options_colors_field_info
text: Text = theme_options_text_field_info
links: Links = theme_options_links_field_info
header: Header = theme_options_header_field_info
section_titles: SectionTitles = theme_options_section_titles_field_info
entries: Entries = theme_options_entries_field_info
highlights: Highlights = theme_options_highlights_field_info
entry_types: EntryTypes = theme_options_entry_types_field_info

View File

@@ -1,129 +0,0 @@
from typing import Literal
import pydantic_extra_types.color as pydantic_color
import rendercv.themes.options as o
o.colors_name_field_info.default = "rgb(0,0,0)"
o.colors_connections_field_info.default = "rgb(0,0,0)"
o.colors_section_titles_field_info.default = "rgb(0,0,0)"
class Colors(o.Colors):
name: pydantic_color.Color = o.colors_name_field_info
connections: pydantic_color.Color = o.colors_connections_field_info
section_titles: pydantic_color.Color = o.colors_section_titles_field_info
o.header_name_font_family_field_info.default = "New Computer Modern"
o.header_connections_font_family_field_info.default = "New Computer Modern"
class Header(o.Header):
name_font_family: o.FontFamily = o.header_name_font_family_field_info
connections_font_family: o.FontFamily = o.header_connections_font_family_field_info
o.links_underline_field_info.default = True
o.links_use_external_link_icon_field_info.default = False
class Links(o.Links):
underline: bool = o.links_underline_field_info
use_external_link_icon: bool = o.links_use_external_link_icon_field_info
o.text_font_family_field_info.default = "New Computer Modern"
class Text(o.Text):
font_family: o.FontFamily = o.text_font_family_field_info
o.section_titles_type_field_info.default = "with-full-line"
o.section_titles_font_family_field_info.default = "New Computer Modern"
class SectionTitles(o.SectionTitles):
font_family: o.FontFamily = o.section_titles_font_family_field_info
type: o.SectionTitleType = o.section_titles_type_field_info
o.highlights_bullet_field_info.default = ""
class Highlights(o.Highlights):
bullet: o.BulletPoint = o.highlights_bullet_field_info
o.education_entry_main_column_first_row_template_field_info.default = (
"**INSTITUTION**\n*DEGREE in AREA*"
)
o.education_entry_degree_column_template_field_info.default = None
o.entry_base_with_date_date_and_location_column_template_field_info.default = (
"*LOCATION*\n*DATE*"
)
class EducationEntryOptions(o.EducationEntryOptions):
main_column_first_row_template: str = (
o.education_entry_main_column_first_row_template_field_info
)
degree_column_template: str | None = (
o.education_entry_degree_column_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
class NormalEntryOptions(o.NormalEntryOptions):
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.experience_entry_main_column_first_row_template_field_info.default = (
"**POSITION**\n*COMPANY*"
)
class ExperienceEntryOptions(o.ExperienceEntryOptions):
main_column_first_row_template: str = (
o.experience_entry_main_column_first_row_template_field_info
)
date_and_location_column_template: str = (
o.entry_base_with_date_date_and_location_column_template_field_info
)
o.entry_types_education_entry_field_info.default = EducationEntryOptions()
o.entry_types_normal_entry_field_info.default = NormalEntryOptions()
o.entry_types_experience_entry_field_info.default = ExperienceEntryOptions()
class EntryOptionsTypes(o.EntryTypes):
education_entry: EducationEntryOptions = o.entry_types_education_entry_field_info
normal_entry: NormalEntryOptions = o.entry_types_normal_entry_field_info
experience_entry: ExperienceEntryOptions = o.entry_types_experience_entry_field_info
o.theme_options_text_field_info.default = Text()
o.theme_options_colors_field_info.default = Colors()
o.theme_options_links_field_info.default = Links()
o.theme_options_highlights_field_info.default = Highlights()
o.theme_options_entry_types_field_info.default = EntryOptionsTypes()
o.theme_options_section_titles_field_info.default = SectionTitles()
o.theme_options_header_field_info.default = Header()
o.theme_options_theme_field_info.default = "sb2nov"
class Sb2novThemeOptions(o.ThemeOptions):
theme: Literal["sb2nov"] = o.theme_options_theme_field_info
header: Header = o.theme_options_header_field_info
links: Links = o.theme_options_links_field_info
text: Text = o.theme_options_text_field_info
colors: Colors = o.theme_options_colors_field_info
highlights: Highlights = o.theme_options_highlights_field_info
entry_types: EntryOptionsTypes = o.theme_options_entry_types_field_info
section_titles: SectionTitles = o.theme_options_section_titles_field_info

View File

@@ -0,0 +1,7 @@
from typing import Literal
from rendercv.themes.options import ThemeOptions
class ClassicThemeOptions(ThemeOptions):
theme: Literal["classic"] = "classic"

View File

@@ -0,0 +1,63 @@
from typing import Literal
import rendercv.themes.options as o
class Page(o.Page):
show_page_numbering: bool = False
class Header(o.Header):
name_font_family: o.FontFamily = "Raleway"
name_bold: bool = False
alignment: o.Alignment = "left"
connections_font_family: o.FontFamily = "Raleway"
class Links(o.Links):
use_external_link_icon: bool = False
class Text(o.Text):
font_family: o.FontFamily = "Raleway"
class SectionTitles(o.SectionTitles):
font_family: o.FontFamily = "Raleway"
bold: bool = False
class Highlights(o.Highlights):
left_margin: o.TypstDimension = "0cm"
class EducationEntryOptions(o.EducationEntryOptions):
main_column_first_row_template: str = "**INSTITUTION**, AREA -- LOCATION"
date_and_location_column_template: str = "DATE"
class NormalEntryOptions(o.NormalEntryOptions):
main_column_first_row_template: str = "**NAME** -- **LOCATION**"
date_and_location_column_template: str = "DATE"
class ExperienceEntryOptions(o.ExperienceEntryOptions):
main_column_first_row_template: str = "**POSITION**, COMPANY -- LOCATION"
date_and_location_column_template: str = "DATE"
class EntryOptionsTypes(o.EntryTypes):
education_entry: EducationEntryOptions = EducationEntryOptions()
normal_entry: NormalEntryOptions = NormalEntryOptions()
experience_entry: ExperienceEntryOptions = ExperienceEntryOptions()
class EngineeringclassicThemeOptions(o.ThemeOptions):
theme: Literal["engineeringclassic"] = "engineeringclassic"
page: Page = Page()
header: Header = Header()
highlights: Highlights = Highlights()
text: Text = Text()
links: Links = Links()
entry_types: EntryOptionsTypes = EntryOptionsTypes()
section_titles: SectionTitles = SectionTitles()

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