Skip to content

rendercv.data

The rendercv.data package contains the necessary classes and functions for

  • Parsing and validating a YAML input file
  • Computing some properties based on a YAML input file (like converting ISO dates to plain English, URLs of social networks, etc.)
  • Generating a JSON Schema for RenderCV's data format
  • Generating a sample YAML input file

The validators and data format of RenderCV are written using Pydantic.

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.",
    )

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.",
    )
    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("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(
                {
                    "latex_icon": "\\faMapMarker*",
                    "url": None,
                    "clean_url": None,
                    "placeholder": self.location,
                }
            )

        if self.email is not None:
            connections.append(
                {
                    "latex_icon": "\\faEnvelope[regular]",
                    "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(
                {
                    "latex_icon": "\\faPhone*",
                    "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(
                {
                    "latex_icon": "\\faLink",
                    "url": str(self.website),
                    "clean_url": website_placeholder,
                    "placeholder": website_placeholder,
                }
            )

        if self.social_networks is not None:
            icon_dictionary = {
                "LinkedIn": "\\faLinkedinIn",
                "GitHub": "\\faGithub",
                "GitLab": "\\faGitlab",
                "Instagram": "\\faInstagram",
                "Mastodon": "\\faMastodon",
                "ORCID": "\\faOrcid",
                "StackOverflow": "\\faStackOverflow",
                "ResearchGate": "\\faResearchgate",
                "YouTube": "\\faYoutube",
                "Google Scholar": "\\faGraduationCap",
                "Telegram": "\\faTelegram",
            }
            for social_network in self.social_networks:
                clean_url = computers.make_a_url_clean(social_network.url)
                connection = {
                    "latex_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():
                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=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_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

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.
    """

    pass

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.
    """

    pass

LocaleCatalog

Bases: RenderCVBaseModelWithoutExtraKeys

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

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

    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'."
            ),
        )
    )
    date_style: Optional[str] = pydantic.Field(
        default="MONTH_ABBREVIATION YEAR",
        title="Date Style",
        description=(
            "The style 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="–",  # en dash
        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_style",
    )
    @classmethod
    def update_locale_catalog(cls, value: str, info: pydantic.ValidationInfo) -> str:
        """Update the `locale_catalog` dictionary."""
        if value:
            LOCALE_CATALOG[info.field_name] = value  # type: ignore

        return value

update_locale_catalog(value, info) classmethod

Update the locale_catalog dictionary.

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

    return value

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.
    """

    pass

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.",
    )

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.
    """

    pass

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."""

    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".'
        ),
    )

    use_local_latex_command: Optional[str] = pydantic.Field(
        default=None,
        title="Local LaTeX Command",
        description=(
            "The command to compile the LaTeX file to a PDF file. The default value is"
            ' "pdflatex".'
        ),
    )

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

    latex_path: Optional[pathlib.Path] = pydantic.Field(
        default=None,
        title="LaTeX Path",
        description=(
            "The path of the LaTeX file. If it is not provided, the LaTeX file will not"
            f" be generated. {file_path_placeholder_description}"
        ),
    )

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

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

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

    dont_generate_html: bool = pydantic.Field(
        default=False,
        title="Generate HTML Flag",
        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="Generate Markdown Flag",
        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="Generate PNG Flag",
        description=(
            "A boolean value to determine whether the PNG file will be generated. 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(
        "pdf_path",
        "latex_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(
    "pdf_path",
    "latex_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)

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: 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_catalog: Optional[LocaleCatalog] = pydantic.Field(
        default=None,
        title="Locale Catalog",
        description=(
            "The locale catalog of the CV to allow the support of multiple languages."
        ),
    )
    rendercv_settings: Optional[RenderCVSettings] = pydantic.Field(
        default=None,
        title="RenderCV Settings",
        description="The settings of the RenderCV.",
    )

    @pydantic.field_validator("locale_catalog")
    @classmethod
    def initialize_locale_catalog(
        cls, locale_catalog: Optional[LocaleCatalog]
    ) -> Optional[LocaleCatalog]:
        """Even if the locale catalog is not provided, initialize it with the default
        values."""
        if locale_catalog is None:
            LocaleCatalog()

        return locale_catalog

initialize_locale_catalog(locale_catalog) classmethod

Even if the locale catalog is not provided, initialize it with the default values.

Source code in rendercv/data/models/rendercv_data_model.py
@pydantic.field_validator("locale_catalog")
@classmethod
def initialize_locale_catalog(
    cls, locale_catalog: Optional[LocaleCatalog]
) -> Optional[LocaleCatalog]:
    """Even if the locale catalog is not provided, initialize it with the default
    values."""
    if locale_catalog is None:
        LocaleCatalog()

    return locale_catalog

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."""

    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."
        ),
    )

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"]

        username = validate_a_social_network_username(username, network)

        return username

    @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"]

    username = validate_a_social_network_username(username, network)

    return username

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

create_a_sample_data_model(name='John Doe', theme='classic')

Return a sample data model for new users to start with.

Parameters:

  • name (str, default: 'John Doe' ) –

    The name of the person. Defaults to "John Doe".

Returns:

Source code in rendercv/data/generator.py
def create_a_sample_data_model(
    name: str = "John Doe", theme: str = "classic"
) -> models.RenderCVDataModel:
    """Return a sample data model for new users to start with.

    Args:
        name: The name of the person. Defaults to "John Doe".

    Returns:
        A sample data model.
    """
    # Check if the theme is valid:
    if theme not in models.available_theme_options:
        available_themes_string = ", ".join(models.available_theme_options.keys())
        raise ValueError(
            f"The theme should be one of the following: {available_themes_string}!"
            f' The provided theme is "{theme}".'
        )

    # read the sample_content.yaml file
    sample_content = pathlib.Path(__file__).parent / "sample_content.yaml"
    sample_content_dictionary = reader.read_a_yaml_file(sample_content)
    cv = models.CurriculumVitae(**sample_content_dictionary)

    # Update the name:
    name = name.encode().decode("unicode-escape")
    cv.name = name

    design = models.available_theme_options[theme](theme=theme)

    return models.RenderCVDataModel(cv=cv, design=design)

create_a_sample_yaml_input_file(input_file_path=None, name='John Doe', theme='classic')

Create a sample YAML input file and return it as a string. If the input file path is provided, then also save the contents to the file.

Parameters:

  • input_file_path (Optional[Path], default: None ) –

    The path to save the input file. Defaults to None.

  • name (str, default: 'John Doe' ) –

    The name of the person. Defaults to "John Doe".

  • theme (str, default: 'classic' ) –

    The theme of the CV. Defaults to "classic".

Returns:

  • str

    The sample YAML input file as a string.

Source code in rendercv/data/generator.py
def create_a_sample_yaml_input_file(
    input_file_path: Optional[pathlib.Path] = None,
    name: str = "John Doe",
    theme: str = "classic",
) -> str:
    """Create a sample YAML input file and return it as a string. If the input file path
    is provided, then also save the contents to the file.

    Args:
        input_file_path: The path to save the input file. Defaults to None.
        name: The name of the person. Defaults to "John Doe".
        theme: The theme of the CV. Defaults to "classic".

    Returns:
        The sample YAML input file as a string.
    """
    data_model = create_a_sample_data_model(name=name, theme=theme)

    # Instead of getting the dictionary with data_model.model_dump() directly, we
    # convert it to JSON and then to a dictionary. Because the YAML library we are
    # using sometimes has problems with the dictionary returned by model_dump().

    # We exclude "cv.sections" because the data model automatically generates them.
    # The user's "cv.sections" input is actually "cv.sections_input" in the data
    # model. It is shown as "cv.sections" in the YAML file because an alias is being
    # used. If"cv.sections" were not excluded, the automatically generated
    # "cv.sections" would overwrite the "cv.sections_input". "cv.sections" are
    # automatically generated from "cv.sections_input" to make the templating
    # process easier. "cv.sections_input" exists for the convenience of the user.
    data_model_as_json = data_model.model_dump_json(
        exclude_none=True, by_alias=True, exclude={"cv": {"sections"}}
    )
    data_model_as_dictionary = json.loads(data_model_as_json)

    yaml_string = dictionary_to_yaml(data_model_as_dictionary)

    if input_file_path is not None:
        input_file_path.write_text(yaml_string, encoding="utf-8")

    return yaml_string

generate_json_schema()

Generate the JSON schema of RenderCV.

JSON schema is generated for the users to make it easier for them to write the input file. The JSON Schema of RenderCV is saved in the root directory of the repository and distributed to the users with the JSON Schema Store.

Returns:

  • dict

    The JSON schema of RenderCV.

Source code in rendercv/data/generator.py
def generate_json_schema() -> dict:
    """Generate the JSON schema of RenderCV.

    JSON schema is generated for the users to make it easier for them to write the input
    file. The JSON Schema of RenderCV is saved in the root directory of the repository
    and distributed to the users with the
    [JSON Schema Store](https://www.schemastore.org/).

    Returns:
        The JSON schema of RenderCV.
    """

    class RenderCVSchemaGenerator(pydantic.json_schema.GenerateJsonSchema):
        def generate(self, schema, mode="validation"):  # type: ignore
            json_schema = super().generate(schema, mode=mode)

            # Basic information about the schema:
            json_schema["title"] = "RenderCV"
            json_schema["description"] = "RenderCV data model."
            json_schema["$id"] = (
                "https://raw.githubusercontent.com/sinaatalay/rendercv/main/schema.json"
            )
            json_schema["$schema"] = "http://json-schema.org/draft-07/schema#"

            # Loop through $defs and remove docstring descriptions and fix optional
            # fields
            for object_name, value in json_schema["$defs"].items():
                # Don't allow additional properties
                value["additionalProperties"] = False

                # If a type is optional, then Pydantic sets the type to a list of two
                # types, one of which is null. The null type can be removed since we
                # already have the required field. Moreover, we would like to warn
                # users if they provide null values. They can remove the fields if they
                # don't want to provide them.
                null_type_dict = {
                    "type": "null",
                }
                for field_name, field in value["properties"].items():
                    if "anyOf" in field:
                        if null_type_dict in field["anyOf"]:
                            field["anyOf"].remove(null_type_dict)

                        field["oneOf"] = field["anyOf"]
                        del field["anyOf"]

            # Currently, YAML extension in VS Code doesn't work properly with the
            # `ListOfEntries` objects. For the best user experience, we will update
            # the JSON Schema. If YAML extension in VS Code starts to work properly,
            # then we should remove the following code for the correct JSON Schema.
            ListOfEntriesForJsonSchema = list[models.Entry]
            list_of_entries_json_schema = pydantic.TypeAdapter(
                ListOfEntriesForJsonSchema
            ).json_schema()
            del list_of_entries_json_schema["$defs"]

            # Update the JSON Schema:
            json_schema["$defs"]["CurriculumVitae"]["properties"]["sections"]["oneOf"][
                0
            ]["additionalProperties"] = list_of_entries_json_schema

            return json_schema

    schema = models.RenderCVDataModel.model_json_schema(
        schema_generator=RenderCVSchemaGenerator
    )

    return schema

generate_json_schema_file(json_schema_path)

Generate the JSON schema of RenderCV and save it to a file.

Parameters:

  • json_schema_path (Path) –

    The path to save the JSON schema.

Source code in rendercv/data/generator.py
def generate_json_schema_file(json_schema_path: pathlib.Path):
    """Generate the JSON schema of RenderCV and save it to a file.

    Args:
        json_schema_path: The path to save the JSON schema.
    """
    schema = generate_json_schema()
    schema_json = json.dumps(schema, indent=2, ensure_ascii=False)
    json_schema_path.write_text(schema_json, encoding="utf-8")

format_date(date, date_style=None)

Formats a Date object to a string in the following format: "Jan 2021". The month names are taken from the locale_catalog 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_style (Optional[str], default: None ) –

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

Returns:

  • str

    The formatted date.

Source code in rendercv/data/models/computers.py
def format_date(date: Date, date_style: 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_catalog` 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_style: The style of the date string. If not provided, the default date
            style from the `locale_catalog` dictionary will be used.

    Returns:
        The formatted date.
    """
    full_month_names = LOCALE_CATALOG["full_names_of_months"]
    short_month_names = LOCALE_CATALOG["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_style is None:
        date_style = LOCALE_CATALOG["date_style"]  # type: ignore

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

    date_string = date_style

    return date_string  # type: ignore

read_a_yaml_file(file_path_or_contents)

Read a YAML file and return its content as a dictionary. The YAML file can be given as a path to the file or as the contents of the file as a string.

Parameters:

  • file_path_or_contents (Path | str) –

    The path to the YAML file or the contents of the YAML file as a string.

Returns:

  • dict

    The content of the YAML file as a dictionary.

Source code in rendercv/data/reader.py
def read_a_yaml_file(file_path_or_contents: pathlib.Path | str) -> dict:
    """Read a YAML file and return its content as a dictionary. The YAML file can be
    given as a path to the file or as the contents of the file as a string.

    Args:
        file_path_or_contents: The path to the YAML file or the contents of the YAML
            file as a string.

    Returns:
        The content of the YAML file as a dictionary.
    """
    if isinstance(file_path_or_contents, pathlib.Path):
        # Check if the file exists:
        if not file_path_or_contents.exists():
            raise FileNotFoundError(
                f"The input file [magenta]{file_path_or_contents}[/magenta] doesn't"
                " exist!"
            )

        # Check the file extension:
        accepted_extensions = [".yaml", ".yml", ".json", ".json5"]
        if file_path_or_contents.suffix not in accepted_extensions:
            user_friendly_accepted_extensions = [
                f"[green]{ext}[/green]" for ext in accepted_extensions
            ]
            user_friendly_accepted_extensions = ", ".join(
                user_friendly_accepted_extensions
            )
            raise ValueError(
                "The input file should have one of the following extensions:"
                f" {user_friendly_accepted_extensions}. The input file is"
                f" [magenta]{file_path_or_contents}[/magenta]."
            )

        file_content = file_path_or_contents.read_text(encoding="utf-8")
    else:
        file_content = file_path_or_contents

    yaml_as_a_dictionary: dict = ruamel.yaml.YAML().load(file_content)

    return yaml_as_a_dictionary

read_input_file(file_path_or_contents)

Read the input file (YAML or JSON) and return them as an instance of RenderCVDataModel, which is a Pydantic data model of RenderCV's data format.

Parameters:

  • file_path_or_contents (Path | str) –

    The path to the input file or the contents of the input file as a string.

Returns:

Source code in rendercv/data/reader.py
def read_input_file(
    file_path_or_contents: pathlib.Path | str,
) -> models.RenderCVDataModel:
    """Read the input file (YAML or JSON) and return them as an instance of
    `RenderCVDataModel`, which is a Pydantic data model of RenderCV's data format.

    Args:
        file_path_or_contents: The path to the input file or the contents of the input
            file as a string.

    Returns:
        The data model.
    """
    input_as_dictionary = read_a_yaml_file(file_path_or_contents)

    rendercv_data_model = validate_input_dictionary_and_return_the_data_model(
        input_as_dictionary
    )

    return rendercv_data_model

validate_input_dictionary_and_return_the_data_model(input_dictionary)

Validate the input dictionary by creating an instance of RenderCVDataModel, which is a Pydantic data model of RenderCV's data format.

Parameters:

  • input_dictionary (dict) –

    The input dictionary.

Returns:

Source code in rendercv/data/reader.py
def validate_input_dictionary_and_return_the_data_model(
    input_dictionary: dict,
) -> models.RenderCVDataModel:
    """Validate the input dictionary by creating an instance of `RenderCVDataModel`,
    which is a Pydantic data model of RenderCV's data format.

    Args:
        input_dictionary: The input dictionary.

    Returns:
        The data model.
    """

    # Validate the parsed dictionary by creating an instance of RenderCVDataModel:
    rendercv_data_model = models.RenderCVDataModel(**input_dictionary)

    return rendercv_data_model