mirror of
https://github.com/rendercv/rendercv.git
synced 2025-12-23 13:38:01 -05:00
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:
@@ -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",
|
||||
}
|
||||
16
.github/ISSUE_TEMPLATE/bug_report.md
vendored
16
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -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.
|
||||
9
.github/ISSUE_TEMPLATE/enhancement.md
vendored
9
.github/ISSUE_TEMPLATE/enhancement.md
vendored
@@ -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.
|
||||
@@ -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.
|
||||
17
.github/workflows/create-executables.yaml
vendored
17
.github/workflows/create-executables.yaml
vendored
@@ -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
|
||||
|
||||
17
.github/workflows/deploy-docs.yaml
vendored
17
.github/workflows/deploy-docs.yaml
vendored
@@ -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:
|
||||
|
||||
@@ -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
|
||||
40
.github/workflows/test.yaml
vendored
40
.github/workflows/test.yaml
vendored
@@ -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
|
||||
|
||||
42
.github/workflows/update-files.yaml
vendored
42
.github/workflows/update-files.yaml
vendored
@@ -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
59
justfile
Normal 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
|
||||
284
pyproject.toml
284
pyproject.toml
@@ -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']
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
7
src/rendercv/themes/classic/__init__.py
Normal file
7
src/rendercv/themes/classic/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from typing import Literal
|
||||
|
||||
from rendercv.themes.options import ThemeOptions
|
||||
|
||||
|
||||
class ClassicThemeOptions(ThemeOptions):
|
||||
theme: Literal["classic"] = "classic"
|
||||
63
src/rendercv/themes/engineeringclassic/__init__.py
Normal file
63
src/rendercv/themes/engineeringclassic/__init__.py
Normal 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
Reference in New Issue
Block a user