Skip to content

rendercv.data.models

The rendercv.data.models package contains all the Pydantic data models, validators, and computed fields that are used in RenderCV. The package is divided into several modules, each containing a different group of data models.

  • base.py: Contains RenderCVBaseModel, which is the parent class of all the data models in RenderCV.
  • computers.py: Contains all the functions that are used to compute some values of the fields in the data models. For example, converting ISO dates to human-readable dates.
  • entry_types.py: Contains all the data models that are used to represent the entries in the CV.
  • curriculum_vitae.py: Contains the CurriculumVitae data model, which is the main data model that contains all the content of the CV.
  • design.py: Contains the data model that is used to represent the design options of the CV.
  • locale.py: Contains the data model that is used to represent the locale catalog of the CV.
  • rendercv_settings.py: Contains the data model that is used to represent the settings of the RenderCV.
  • rendercv_data_model.py: Contains the RenderCVDataModel data model, which is the main data model that defines the whole input file structure.

CurriculumVitae

Bases: RenderCVBaseModelWithExtraKeys

This class is the data model of the cv field.

Source code in rendercv/data/models/curriculum_vitae.py
class CurriculumVitae(RenderCVBaseModelWithExtraKeys):
    """This class is the data model of the `cv` field."""

    name: Optional[str] = pydantic.Field(
        default=None,
        title="Name",
        description="The name of the person.",
    )
    location: Optional[str] = pydantic.Field(
        default=None,
        title="Location",
        description="The location of the person.",
    )
    email: Optional[pydantic.EmailStr] = pydantic.Field(
        default=None,
        title="Email",
        description="The email address of the person.",
    )
    photo: Optional[pathlib.Path] = pydantic.Field(
        default=None,
        title="Photo",
        description="Path to the photo of the person, relatie to the input file.",
    )
    phone: Optional[pydantic_phone_numbers.PhoneNumber] = pydantic.Field(
        default=None,
        title="Phone",
        description="The phone number of the person, including the country code.",
    )
    website: Optional[pydantic.HttpUrl] = pydantic.Field(
        default=None,
        title="Website",
        description="The website of the person.",
    )
    social_networks: Optional[list[SocialNetwork]] = pydantic.Field(
        default=None,
        title="Social Networks",
        description="The social networks of the person.",
    )
    sections_input: Sections = pydantic.Field(
        default=None,
        title="Sections",
        description="The sections of the CV.",
        # This is an alias to allow users to use `sections` in the YAML file:
        # `sections` key is preserved for RenderCV's internal use.
        alias="sections",
    )

    @pydantic.field_validator("photo")
    @classmethod
    def update_photo_path(cls, value: Optional[pathlib.Path]) -> Optional[pathlib.Path]:
        """Cast `photo` to Path and make the path absolute"""
        if value:
            from .rendercv_data_model import INPUT_FILE_DIRECTORY

            if INPUT_FILE_DIRECTORY is not None:
                profile_picture_parent_folder = INPUT_FILE_DIRECTORY
            else:
                profile_picture_parent_folder = pathlib.Path.cwd()

            return profile_picture_parent_folder / str(value)

        return value

    @pydantic.field_validator("name")
    @classmethod
    def update_curriculum_vitae(cls, value: str, info: pydantic.ValidationInfo) -> str:
        """Update the `curriculum_vitae` dictionary."""
        if value:
            curriculum_vitae[info.field_name] = value  # type: ignore

        return value

    @functools.cached_property
    def connections(self) -> list[dict[str, Optional[str]]]:
        """Return all the connections of the person as a list of dictionaries and cache
        `connections` as an attribute of the instance. The connections are used in the
        header of the CV.

        Returns:
            The connections of the person.
        """

        connections: list[dict[str, Optional[str]]] = []

        if self.location is not None:
            connections.append(
                {
                    "typst_icon": "location-dot",
                    "url": None,
                    "clean_url": None,
                    "placeholder": self.location,
                }
            )

        if self.email is not None:
            connections.append(
                {
                    "typst_icon": "envelope",
                    "url": f"mailto:{self.email}",
                    "clean_url": self.email,
                    "placeholder": self.email,
                }
            )

        if self.phone is not None:
            phone_placeholder = computers.format_phone_number(self.phone)
            connections.append(
                {
                    "typst_icon": "phone",
                    "url": self.phone,
                    "clean_url": phone_placeholder,
                    "placeholder": phone_placeholder,
                }
            )

        if self.website is not None:
            website_placeholder = computers.make_a_url_clean(str(self.website))
            connections.append(
                {
                    "typst_icon": "link",
                    "url": str(self.website),
                    "clean_url": website_placeholder,
                    "placeholder": website_placeholder,
                }
            )

        if self.social_networks is not None:
            icon_dictionary = {
                "LinkedIn": "linkedin",
                "GitHub": "github",
                "GitLab": "gitlab",
                "Instagram": "instagram",
                "Mastodon": "mastodon",
                "ORCID": "orcid",
                "StackOverflow": "stack-overflow",
                "ResearchGate": "researchgate",
                "YouTube": "youtube",
                "Google Scholar": "graduation-cap",
                "Telegram": "telegram",
            }
            for social_network in self.social_networks:
                clean_url = computers.make_a_url_clean(social_network.url)
                connection = {
                    "typst_icon": icon_dictionary[social_network.network],
                    "url": social_network.url,
                    "clean_url": clean_url,
                    "placeholder": social_network.username,
                }

                if social_network.network == "StackOverflow":
                    username = social_network.username.split("/")[1]
                    connection["placeholder"] = username
                if social_network.network == "Google Scholar":
                    connection["placeholder"] = "Google Scholar"

                connections.append(connection)  # type: ignore

        return connections

    @functools.cached_property
    def sections(self) -> list[SectionBase]:
        """Compute the sections of the CV based on the input sections.

        The original `sections` input is a dictionary where the keys are the section titles
        and the values are the list of entries in that section. This function converts the
        input sections to a list of `SectionBase` objects. This makes it easier to work with
        the sections in the rest of the code.

        Returns:
            The computed sections.
        """
        sections: list[SectionBase] = []

        if self.sections_input is not None:
            for title, entries in self.sections_input.items():
                formatted_title = computers.dictionary_key_to_proper_section_title(
                    title
                )

                # The first entry can be used because all the entries in the section are
                # already validated with the `validate_a_section` function:
                entry_type_name, _ = get_entry_type_name_and_section_validator(
                    entries[0],  # type: ignore
                    entry_types=entry_types.available_entry_models,
                )

                # SectionBase is used so that entries are not validated again:
                section = SectionBase(
                    title=formatted_title,
                    entry_type=entry_type_name,
                    entries=entries,
                )
                sections.append(section)

        return sections

connections: list[dict[str, Optional[str]]] cached property

Return all the connections of the person as a list of dictionaries and cache connections as an attribute of the instance. The connections are used in the header of the CV.

Returns:

  • list[dict[str, Optional[str]]]

    The connections of the person.

sections: list[SectionBase] cached property

Compute the sections of the CV based on the input sections.

The original sections input is a dictionary where the keys are the section titles and the values are the list of entries in that section. This function converts the input sections to a list of SectionBase objects. This makes it easier to work with the sections in the rest of the code.

Returns:

update_photo_path(value) classmethod

Cast photo to Path and make the path absolute

Source code in rendercv/data/models/curriculum_vitae.py
@pydantic.field_validator("photo")
@classmethod
def update_photo_path(cls, value: Optional[pathlib.Path]) -> Optional[pathlib.Path]:
    """Cast `photo` to Path and make the path absolute"""
    if value:
        from .rendercv_data_model import INPUT_FILE_DIRECTORY

        if INPUT_FILE_DIRECTORY is not None:
            profile_picture_parent_folder = INPUT_FILE_DIRECTORY
        else:
            profile_picture_parent_folder = pathlib.Path.cwd()

        return profile_picture_parent_folder / str(value)

    return value

update_curriculum_vitae(value, info) classmethod

Update the curriculum_vitae dictionary.

Source code in rendercv/data/models/curriculum_vitae.py
@pydantic.field_validator("name")
@classmethod
def update_curriculum_vitae(cls, value: str, info: pydantic.ValidationInfo) -> str:
    """Update the `curriculum_vitae` dictionary."""
    if value:
        curriculum_vitae[info.field_name] = value  # type: ignore

    return value

SocialNetwork

Bases: RenderCVBaseModelWithoutExtraKeys

This class is the data model of a social network.

Source code in rendercv/data/models/curriculum_vitae.py
class SocialNetwork(RenderCVBaseModelWithoutExtraKeys):
    """This class is the data model of a social network."""

    network: SocialNetworkName = pydantic.Field(
        title="Social Network",
        description="Name of the social network.",
    )
    username: str = pydantic.Field(
        title="Username",
        description="The username of the social network. The link will be generated.",
    )

    @pydantic.field_validator("username")
    @classmethod
    def check_username(cls, username: str, info: pydantic.ValidationInfo) -> str:
        """Check if the username is provided correctly."""
        if "network" not in info.data:
            # the network is either not provided or not one of the available social
            # networks. In this case, don't check the username, since Pydantic will
            # raise an error for the network.
            return username

        network = info.data["network"]

        return validate_a_social_network_username(username, network)

    @pydantic.model_validator(mode="after")  # type: ignore
    def check_url(self) -> "SocialNetwork":
        """Validate the URL of the social network."""
        if self.network == "Mastodon":
            # All the other social networks have valid URLs. Mastodon URLs contain both
            # the username and the domain. So, we need to validate if the url is valid.
            validate_url(self.url)

        return self

    @functools.cached_property
    def url(self) -> str:
        """Return the URL of the social network and cache `url` as an attribute of the
        instance.
        """
        if self.network == "Mastodon":
            # Split domain and username
            _, username, domain = self.username.split("@")
            url = f"https://{domain}/@{username}"
        else:
            url_dictionary = {
                "LinkedIn": "https://linkedin.com/in/",
                "GitHub": "https://github.com/",
                "GitLab": "https://gitlab.com/",
                "Instagram": "https://instagram.com/",
                "ORCID": "https://orcid.org/",
                "StackOverflow": "https://stackoverflow.com/users/",
                "ResearchGate": "https://researchgate.net/profile/",
                "YouTube": "https://youtube.com/@",
                "Google Scholar": "https://scholar.google.com/citations?user=",
                "Telegram": "https://t.me/",
            }
            url = url_dictionary[self.network] + self.username

        return url

url: str cached property

Return the URL of the social network and cache url as an attribute of the instance.

check_username(username, info) classmethod

Check if the username is provided correctly.

Source code in rendercv/data/models/curriculum_vitae.py
@pydantic.field_validator("username")
@classmethod
def check_username(cls, username: str, info: pydantic.ValidationInfo) -> str:
    """Check if the username is provided correctly."""
    if "network" not in info.data:
        # the network is either not provided or not one of the available social
        # networks. In this case, don't check the username, since Pydantic will
        # raise an error for the network.
        return username

    network = info.data["network"]

    return validate_a_social_network_username(username, network)

check_url()

Validate the URL of the social network.

Source code in rendercv/data/models/curriculum_vitae.py
@pydantic.model_validator(mode="after")  # type: ignore
def check_url(self) -> "SocialNetwork":
    """Validate the URL of the social network."""
    if self.network == "Mastodon":
        # All the other social networks have valid URLs. Mastodon URLs contain both
        # the username and the domain. So, we need to validate if the url is valid.
        validate_url(self.url)

    return self

BulletEntry

Bases: RenderCVBaseModelWithExtraKeys

This class is the data model of BulletEntry.

Source code in rendercv/data/models/entry_types.py
class BulletEntry(RenderCVBaseModelWithExtraKeys):
    """This class is the data model of `BulletEntry`."""

    bullet: str = pydantic.Field(
        title="Bullet",
        description="The bullet of the BulletEntry.",
    )

    def make_keywords_bold(self, keywords: list[str]) -> "BulletEntry":
        """Make the given keywords bold in the `bullet` field.

        Args:
            keywords: The keywords to make bold.

        Returns:
            A BulletEntry with the keywords made bold in the `bullet` field.
        """
        self.bullet = make_keywords_bold_in_a_string(self.bullet, keywords)
        return self

make_keywords_bold(keywords)

Make the given keywords bold in the bullet field.

Parameters:

  • keywords (list[str]) –

    The keywords to make bold.

Returns:

  • BulletEntry

    A BulletEntry with the keywords made bold in the bullet field.

Source code in rendercv/data/models/entry_types.py
def make_keywords_bold(self, keywords: list[str]) -> "BulletEntry":
    """Make the given keywords bold in the `bullet` field.

    Args:
        keywords: The keywords to make bold.

    Returns:
        A BulletEntry with the keywords made bold in the `bullet` field.
    """
    self.bullet = make_keywords_bold_in_a_string(self.bullet, keywords)
    return self

EducationEntry

Bases: EntryBase, EducationEntryBase

This class is the data model of EducationEntry. EducationEntry class is created by combining the EntryBase and EducationEntryBase classes to have the fields in the correct order.

Source code in rendercv/data/models/entry_types.py
class EducationEntry(EntryBase, EducationEntryBase):
    """This class is the data model of `EducationEntry`. `EducationEntry` class is
    created by combining the `EntryBase` and `EducationEntryBase` classes to have the
    fields in the correct order.
    """

ExperienceEntry

Bases: EntryBase, ExperienceEntryBase

This class is the data model of ExperienceEntry. ExperienceEntry class is created by combining the EntryBase and ExperienceEntryBase classes to have the fields in the correct order.

Source code in rendercv/data/models/entry_types.py
class ExperienceEntry(EntryBase, ExperienceEntryBase):
    """This class is the data model of `ExperienceEntry`. `ExperienceEntry` class is
    created by combining the `EntryBase` and `ExperienceEntryBase` classes to have the
    fields in the correct order.
    """

NormalEntry

Bases: EntryBase, NormalEntryBase

This class is the data model of NormalEntry. NormalEntry class is created by combining the EntryBase and NormalEntryBase classes to have the fields in the correct order.

Source code in rendercv/data/models/entry_types.py
class NormalEntry(EntryBase, NormalEntryBase):
    """This class is the data model of `NormalEntry`. `NormalEntry` class is created by
    combining the `EntryBase` and `NormalEntryBase` classes to have the fields in the
    correct order.
    """

OneLineEntry

Bases: RenderCVBaseModelWithExtraKeys

This class is the data model of OneLineEntry.

Source code in rendercv/data/models/entry_types.py
class OneLineEntry(RenderCVBaseModelWithExtraKeys):
    """This class is the data model of `OneLineEntry`."""

    label: str = pydantic.Field(
        title="Name",
        description="The label of the OneLineEntry.",
    )
    details: str = pydantic.Field(
        title="Details",
        description="The details of the OneLineEntry.",
    )

    def make_keywords_bold(self, keywords: list[str]) -> "OneLineEntry":
        """Make the given keywords bold in the `details` field.

        Args:
            keywords: The keywords to make bold.

        Returns:
            A OneLineEntry with the keywords made bold in the `details` field.
        """
        self.details = make_keywords_bold_in_a_string(self.details, keywords)
        return self

make_keywords_bold(keywords)

Make the given keywords bold in the details field.

Parameters:

  • keywords (list[str]) –

    The keywords to make bold.

Returns:

  • OneLineEntry

    A OneLineEntry with the keywords made bold in the details field.

Source code in rendercv/data/models/entry_types.py
def make_keywords_bold(self, keywords: list[str]) -> "OneLineEntry":
    """Make the given keywords bold in the `details` field.

    Args:
        keywords: The keywords to make bold.

    Returns:
        A OneLineEntry with the keywords made bold in the `details` field.
    """
    self.details = make_keywords_bold_in_a_string(self.details, keywords)
    return self

PublicationEntry

Bases: EntryWithDate, PublicationEntryBase

This class is the data model of PublicationEntry. PublicationEntry class is created by combining the EntryWithDate and PublicationEntryBase classes to have the fields in the correct order.

Source code in rendercv/data/models/entry_types.py
class PublicationEntry(EntryWithDate, PublicationEntryBase):
    """This class is the data model of `PublicationEntry`. `PublicationEntry` class is
    created by combining the `EntryWithDate` and `PublicationEntryBase` classes to have
    the fields in the correct order.
    """

Locale

Bases: RenderCVBaseModelWithoutExtraKeys

This class is the data model of the locale catalog. The values of each field updates the locale dictionary.

Source code in rendercv/data/models/locale.py
class Locale(RenderCVBaseModelWithoutExtraKeys):
    """This class is the data model of the locale catalog. The values of each field
    updates the `locale` dictionary.
    """

    language: pydantic_extra_types.language_code.LanguageAlpha2 = pydantic.Field(
        default="en",  # type: ignore
        title="Language",
        description=(
            "The language as an ISO 639 alpha-2 code. It is used for hyphenation"
            " patterns."
        ),
    )
    phone_number_format: Optional[Literal["national", "international", "E164"]] = (
        pydantic.Field(
            default="national",
            title="Phone Number Format",
            description=(
                "If 'national', phone numbers are formatted without the country code."
                " If 'international', phone numbers are formatted with the country"
                ' code. The default value is "national"'
            ),
        )
    )
    page_numbering_template: str = pydantic.Field(
        default="NAME - Page PAGE_NUMBER of TOTAL_PAGES",
        title="Page Numbering Template",
        description=(
            "The template of the page numbering. The following placeholders can be"
            " used:\n- NAME: The name of the person\n- PAGE_NUMBER: The current page"
            " number\n- TOTAL_PAGES: The total number of pages\n- TODAY: Today's date"
            ' with `locale.date_template`\nThe default value is "NAME -'
            ' Page PAGE_NUMBER of TOTAL_PAGES".'
        ),
    )
    last_updated_date_template: str = pydantic.Field(
        default="Last updated in TODAY",
        title="Last Updated Date Template",
        description=(
            "The template of the last updated date. The following placeholders can be"
            " used:\n- TODAY: Today's date with `locale.date_template`\nThe"
            ' default value is "Last updated in TODAY".'
        ),
    )
    date_template: Optional[str] = pydantic.Field(
        default="MONTH_ABBREVIATION YEAR",
        title="Date Template",
        description=(
            "The template of the date. The following placeholders can be"
            " used:\n-FULL_MONTH_NAME: Full name of the month\n- MONTH_ABBREVIATION:"
            " Abbreviation of the month\n- MONTH: Month as a number\n-"
            " MONTH_IN_TWO_DIGITS: Month as a number in two digits\n- YEAR: Year as a"
            " number\n- YEAR_IN_TWO_DIGITS: Year as a number in two digits\nThe"
            ' default value is "MONTH_ABBREVIATION YEAR".'
        ),
    )
    month: Optional[str] = pydantic.Field(
        default="month",
        title='Translation of "Month"',
        description='Translation of the word "month" in the locale.',
    )
    months: Optional[str] = pydantic.Field(
        default="months",
        title='Translation of "Months"',
        description='Translation of the word "months" in the locale.',
    )
    year: Optional[str] = pydantic.Field(
        default="year",
        title='Translation of "Year"',
        description='Translation of the word "year" in the locale.',
    )
    years: Optional[str] = pydantic.Field(
        default="years",
        title='Translation of "Years"',
        description='Translation of the word "years" in the locale.',
    )
    present: Optional[str] = pydantic.Field(
        default="present",
        title='Translation of "Present"',
        description='Translation of the word "present" in the locale.',
    )
    to: Optional[str] = pydantic.Field(
        default="–",  # NOQA: RUF001
        title='Translation of "To"',
        description=(
            "The word or character used to indicate a range in the locale (e.g.,"
            ' "2020 - 2021").'
        ),
    )
    abbreviations_for_months: Optional[
        Annotated[list[str], at.Len(min_length=12, max_length=12)]
    ] = pydantic.Field(
        # Month abbreviations are taken from
        # https://web.library.yale.edu/cataloging/months:
        default=[
            "Jan",
            "Feb",
            "Mar",
            "Apr",
            "May",
            "June",
            "July",
            "Aug",
            "Sept",
            "Oct",
            "Nov",
            "Dec",
        ],
        title="Abbreviations of Months",
        description="Abbreviations of the months in the locale.",
    )
    full_names_of_months: Optional[
        Annotated[list[str], at.Len(min_length=12, max_length=12)]
    ] = pydantic.Field(
        default=[
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December",
        ],
        title="Full Names of Months",
        description="Full names of the months in the locale.",
    )

    @pydantic.field_validator(
        "month",
        "months",
        "year",
        "years",
        "present",
        "abbreviations_for_months",
        "to",
        "full_names_of_months",
        "phone_number_format",
        "date_template",
    )
    @classmethod
    def update_locale(cls, value: str, info: pydantic.ValidationInfo) -> str:
        """Update the `locale` dictionary."""
        if value:
            locale[info.field_name] = value  # type: ignore

        return value

update_locale(value, info) classmethod

Update the locale dictionary.

Source code in rendercv/data/models/locale.py
@pydantic.field_validator(
    "month",
    "months",
    "year",
    "years",
    "present",
    "abbreviations_for_months",
    "to",
    "full_names_of_months",
    "phone_number_format",
    "date_template",
)
@classmethod
def update_locale(cls, value: str, info: pydantic.ValidationInfo) -> str:
    """Update the `locale` dictionary."""
    if value:
        locale[info.field_name] = value  # type: ignore

    return value

RenderCVDataModel

Bases: RenderCVBaseModelWithoutExtraKeys

This class binds both the CV and the design information together.

Source code in rendercv/data/models/rendercv_data_model.py
class RenderCVDataModel(RenderCVBaseModelWithoutExtraKeys):
    """This class binds both the CV and the design information together."""

    # `cv` is normally required, but don't enforce it in JSON Schema to allow
    # `design` or `locale` fields to have individual YAML files.
    model_config = pydantic.ConfigDict(json_schema_extra={"required": []})
    cv: CurriculumVitae = pydantic.Field(
        title="Curriculum Vitae",
        description="The data of the CV.",
    )
    design: RenderCVDesign = pydantic.Field(
        default=ClassicThemeOptions(theme="classic"),
        title="Design",
        description=(
            "The design information of the CV. The default is the classic theme."
        ),
    )
    locale: Locale = pydantic.Field(
        default=None,  # type: ignore
        title="Locale Catalog",
        description=(
            "The locale catalog of the CV to allow the support of multiple languages."
        ),
    )
    rendercv_settings: RenderCVSettings = pydantic.Field(
        default=RenderCVSettings(),
        title="RenderCV Settings",
        description="The settings of the RenderCV.",
    )

    @pydantic.model_validator(mode="before")
    @classmethod
    def update_paths(
        cls, model, info: pydantic.ValidationInfo
    ) -> Optional[RenderCVSettings]:
        """Update the paths in the RenderCV settings."""
        global INPUT_FILE_DIRECTORY  # NOQA: PLW0603

        context = info.context
        if context:
            input_file_directory = context.get("input_file_directory", None)
            INPUT_FILE_DIRECTORY = input_file_directory
        else:
            INPUT_FILE_DIRECTORY = None

        return model

    @pydantic.field_validator("locale", mode="before")
    @classmethod
    def update_locale(cls, value) -> Locale:
        """Update the output folder name in the RenderCV settings."""
        # Somehow, we need this for `test_if_local_catalog_resets` to pass.
        if value is None:
            return Locale()

        return value

update_paths(model, info) classmethod

Update the paths in the RenderCV settings.

Source code in rendercv/data/models/rendercv_data_model.py
@pydantic.model_validator(mode="before")
@classmethod
def update_paths(
    cls, model, info: pydantic.ValidationInfo
) -> Optional[RenderCVSettings]:
    """Update the paths in the RenderCV settings."""
    global INPUT_FILE_DIRECTORY  # NOQA: PLW0603

    context = info.context
    if context:
        input_file_directory = context.get("input_file_directory", None)
        INPUT_FILE_DIRECTORY = input_file_directory
    else:
        INPUT_FILE_DIRECTORY = None

    return model

update_locale(value) classmethod

Update the output folder name in the RenderCV settings.

Source code in rendercv/data/models/rendercv_data_model.py
@pydantic.field_validator("locale", mode="before")
@classmethod
def update_locale(cls, value) -> Locale:
    """Update the output folder name in the RenderCV settings."""
    # Somehow, we need this for `test_if_local_catalog_resets` to pass.
    if value is None:
        return Locale()

    return value

RenderCommandSettings

Bases: RenderCVBaseModelWithoutExtraKeys

This class is the data model of the render command's settings.

Source code in rendercv/data/models/rendercv_settings.py
class RenderCommandSettings(RenderCVBaseModelWithoutExtraKeys):
    """This class is the data model of the `render` command's settings."""

    design: Optional[str] = pydantic.Field(
        default=None,
        title="`design` Field's YAML File",
        description=(
            "The file path to the yaml file containing the `design` field separately."
        ),
    )

    rendercv_settings: Optional[str] = pydantic.Field(
        default=None,
        title="`rendercv_settings` Field's YAML File",
        description=(
            "The file path to the yaml file containing the `rendercv_settings` field"
            " separately."
        ),
    )

    locale: Optional[str] = pydantic.Field(
        default=None,
        title="`locale` Field's YAML File",
        description=(
            "The file path to the yaml file containing the `locale` field separately."
        ),
    )

    output_folder_name: str = pydantic.Field(
        default="rendercv_output",
        title="Output Folder Name",
        description=(
            "The name of the folder where the output files will be saved."
            f" {file_path_placeholder_description_without_default}\nThe default value"
            ' is "rendercv_output".'
        ),
    )

    pdf_path: Optional[pathlib.Path] = pydantic.Field(
        default=None,
        title="PDF Path",
        description=(
            "The path to copy the PDF file to. If it is not provided, the PDF file will"
            f" not be copied. {file_path_placeholder_description}"
        ),
    )

    typst_path: Optional[pathlib.Path] = pydantic.Field(
        default=None,
        title="Typst Path",
        description=(
            "The path to copy the Typst file to. If it is not provided, the Typst file"
            f" will not be copied. {file_path_placeholder_description}"
        ),
    )

    html_path: Optional[pathlib.Path] = pydantic.Field(
        default=None,
        title="HTML Path",
        description=(
            "The path to copy the HTML file to. If it is not provided, the HTML file"
            f" will not be copied. {file_path_placeholder_description}"
        ),
    )

    png_path: Optional[pathlib.Path] = pydantic.Field(
        default=None,
        title="PNG Path",
        description=(
            "The path to copy the PNG file to. If it is not provided, the PNG file will"
            f" not be copied. {file_path_placeholder_description}"
        ),
    )

    markdown_path: Optional[pathlib.Path] = pydantic.Field(
        default=None,
        title="Markdown Path",
        description=(
            "The path to copy the Markdown file to. If it is not provided, the Markdown"
            f" file will not be copied. {file_path_placeholder_description}"
        ),
    )

    dont_generate_html: bool = pydantic.Field(
        default=False,
        title="Don't Generate HTML",
        description=(
            "A boolean value to determine whether the HTML file will be generated. The"
            " default value is False."
        ),
    )

    dont_generate_markdown: bool = pydantic.Field(
        default=False,
        title="Don't Generate Markdown",
        description=(
            "A boolean value to determine whether the Markdown file will be generated."
            ' The default value is "false".'
        ),
    )

    dont_generate_png: bool = pydantic.Field(
        default=False,
        title="Don't Generate PNG",
        description=(
            "A boolean value to determine whether the PNG file will be generated. The"
            " default value is False."
        ),
    )

    watch: bool = pydantic.Field(
        default=False,
        title="Re-run RenderCV When the Input File is Updated",
        description=(
            "A boolean value to determine whether to re-run RenderCV when the input"
            'file is updated. The default value is "false".'
        ),
    )

    @pydantic.field_validator(
        "output_folder_name",
        mode="before",
    )
    @classmethod
    def replace_placeholders(cls, value: str) -> str:
        """Replaces the placeholders in a string with the corresponding values."""
        return replace_placeholders(value)

    @pydantic.field_validator(
        "design",
        "locale",
        "rendercv_settings",
        "pdf_path",
        "typst_path",
        "html_path",
        "png_path",
        "markdown_path",
        mode="before",
    )
    @classmethod
    def convert_string_to_path(cls, value: Optional[str]) -> Optional[pathlib.Path]:
        """Converts a string to a `pathlib.Path` object by replacing the placeholders
        with the corresponding values. If the path is not an absolute path, it is
        converted to an absolute path by prepending the current working directory.
        """
        if value is None:
            return None

        return convert_string_to_path(value)

replace_placeholders(value) classmethod

Replaces the placeholders in a string with the corresponding values.

Source code in rendercv/data/models/rendercv_settings.py
@pydantic.field_validator(
    "output_folder_name",
    mode="before",
)
@classmethod
def replace_placeholders(cls, value: str) -> str:
    """Replaces the placeholders in a string with the corresponding values."""
    return replace_placeholders(value)

convert_string_to_path(value) classmethod

Converts a string to a pathlib.Path object by replacing the placeholders with the corresponding values. If the path is not an absolute path, it is converted to an absolute path by prepending the current working directory.

Source code in rendercv/data/models/rendercv_settings.py
@pydantic.field_validator(
    "design",
    "locale",
    "rendercv_settings",
    "pdf_path",
    "typst_path",
    "html_path",
    "png_path",
    "markdown_path",
    mode="before",
)
@classmethod
def convert_string_to_path(cls, value: Optional[str]) -> Optional[pathlib.Path]:
    """Converts a string to a `pathlib.Path` object by replacing the placeholders
    with the corresponding values. If the path is not an absolute path, it is
    converted to an absolute path by prepending the current working directory.
    """
    if value is None:
        return None

    return convert_string_to_path(value)

RenderCVSettings

Bases: RenderCVBaseModelWithoutExtraKeys

This class is the data model of the RenderCV settings.

Source code in rendercv/data/models/rendercv_settings.py
class RenderCVSettings(RenderCVBaseModelWithoutExtraKeys):
    """This class is the data model of the RenderCV settings."""

    date: datetime.date = pydantic.Field(
        default=datetime.date.today(),
        title="Date",
        description=(
            "The date that will be used everywhere (e.g., in the output file names,"
            " last updated date, computation of time spans for the events that are"
            " currently happening, etc.). The default value is the current date."
        ),
    )
    render_command: Optional[RenderCommandSettings] = pydantic.Field(
        default=None,
        title="Render Command Settings",
        description=(
            "RenderCV's `render` command settings. They are the same as the command"
            " line arguments. CLI arguments have higher priority than the settings in"
            " the input file."
        ),
    )
    bold_keywords: list[str] = pydantic.Field(
        default=[],
        title="Bold Keywords",
        description=(
            "The keywords that will be bold in the output. The default value is an"
            " empty list."
        ),
    )

    @pydantic.field_validator("date")
    @classmethod
    def mock_today(cls, value: datetime.date) -> datetime.date:
        """Mocks the current date for testing."""

        global DATE_INPUT  # NOQA: PLW0603

        DATE_INPUT = value

        return value

mock_today(value) classmethod

Mocks the current date for testing.

Source code in rendercv/data/models/rendercv_settings.py
@pydantic.field_validator("date")
@classmethod
def mock_today(cls, value: datetime.date) -> datetime.date:
    """Mocks the current date for testing."""

    global DATE_INPUT  # NOQA: PLW0603

    DATE_INPUT = value

    return value

format_date(date, date_template=None)

Formats a Date object to a string in the following format: "Jan 2021". The month names are taken from the locale dictionary from the rendercv.data_models.models module.

Example

format_date(Date(2024, 5, 1))
will return

"May 2024"

Parameters:

  • date (date) –

    The date to format.

  • date_template (Optional[str], default: None ) –

    The template of the date string. If not provided, the default date style from the locale dictionary will be used.

Returns:

  • str

    The formatted date.

Source code in rendercv/data/models/computers.py
def format_date(date: Date, date_template: Optional[str] = None) -> str:
    """Formats a `Date` object to a string in the following format: "Jan 2021". The
    month names are taken from the `locale` dictionary from the
    `rendercv.data_models.models` module.

    Example:
        ```python
        format_date(Date(2024, 5, 1))
        ```
        will return

        `"May 2024"`

    Args:
        date: The date to format.
        date_template: The template of the date string. If not provided, the default date
            style from the `locale` dictionary will be used.

    Returns:
        The formatted date.
    """
    full_month_names = locale["full_names_of_months"]
    short_month_names = locale["abbreviations_for_months"]

    month = int(date.strftime("%m"))
    year = date.strftime(format="%Y")

    placeholders = {
        "FULL_MONTH_NAME": full_month_names[month - 1],
        "MONTH_ABBREVIATION": short_month_names[month - 1],
        "MONTH_IN_TWO_DIGITS": f"{month:02d}",
        "YEAR_IN_TWO_DIGITS": str(year[-2:]),
        "MONTH": str(month),
        "YEAR": str(year),
    }
    if date_template is None:
        date_template = locale["date_template"]  # type: ignore

    assert isinstance(date_template, str)

    for placeholder, value in placeholders.items():
        date_template = date_template.replace(placeholder, value)  # type: ignore

    return date_template

get_date_input()

Return the date input.

Returns:

  • date

    The date input.

Source code in rendercv/data/models/computers.py
def get_date_input() -> Date:
    """Return the date input.

    Returns:
        The date input.
    """
    from .rendercv_settings import DATE_INPUT

    return DATE_INPUT

make_a_url_clean(url)

Make a URL clean by removing the protocol, www, and trailing slashes.

Example

make_a_url_clean("https://www.example.com/")
returns "example.com"

Parameters:

  • url (str) –

    The URL to make clean.

Returns:

  • str

    The clean URL.

Source code in rendercv/data/models/computers.py
def make_a_url_clean(url: str) -> str:
    """Make a URL clean by removing the protocol, www, and trailing slashes.

    Example:
        ```python
        make_a_url_clean("https://www.example.com/")
        ```
        returns
        `"example.com"`

    Args:
        url: The URL to make clean.

    Returns:
        The clean URL.
    """
    url = url.replace("https://", "").replace("http://", "")
    if url.endswith("/"):
        url = url[:-1]

    return url

make_keywords_bold_in_a_string(string, keywords)

Make the given keywords bold in the given string.

Source code in rendercv/data/models/entry_types.py
def make_keywords_bold_in_a_string(string: str, keywords: list[str]) -> str:
    """Make the given keywords bold in the given string."""
    replacement_map = {keyword: f"**{keyword}**" for keyword in keywords}
    for keyword, replacement in replacement_map.items():
        string = string.replace(keyword, replacement)

    return string