Skip to content

Data Models

This module contains all the necessary classes to store CV data. These classes are called data models. The YAML input file is transformed into instances of these classes (i.e., the input file is read) with the read_input_file function. RenderCV utilizes these instances to generate a $\LaTeX$ file which is then rendered into a PDF file.

The data models are initialized with data validation to prevent unexpected bugs. During the initialization, we ensure that everything is in the correct place and that the user has provided a valid RenderCV input. This is achieved through the use of Pydantic. Each class method decorated with pydantic.model_validator or pydantic.field_validator is executed automatically during the data classes' initialization.

RenderCVBaseModel

Bases: BaseModel

This class is the parent class of all the data models in RenderCV. It has only one difference from the default pydantic.BaseModel: It raises an error if an unknown key is provided in the input file.

OneLineEntry

Bases: RenderCVBaseModel

This class is the data model of OneLineEntry.

PublicationEntry

Bases: RenderCVBaseModel

This class is the data model of PublicationEntry.

doi_url: str cached property

Return the URL of the DOI.

date_string: str cached property

Return the date string of the publication.

check_date(date) classmethod

Check if the date is a valid date.

Source code in rendercv/data_models.py
@pydantic.field_validator("date")
@classmethod
def check_date(cls, date: int | RenderCVDate) -> int | RenderCVDate:
    """Check if the date is a valid date."""
    # The function below will raise an error if the date is not valid:
    get_date_object(date)

    return date

check_doi(doi) classmethod

Check if the DOI exists in the DOI System.

Source code in rendercv/data_models.py
@pydantic.field_validator("doi")
@classmethod
def check_doi(cls, doi: Optional[str]) -> Optional[str]:
    """Check if the DOI exists in the DOI System."""
    if doi is not None:
        # see https://stackoverflow.com/a/60671292/18840665 for the explanation of
        # the next line:
        ssl._create_default_https_context = ssl._create_unverified_context  # type: ignore

        doi_url = f"http://doi.org/{doi}"

        try:
            urlopen(doi_url)
        except HTTPError as err:
            if err.code == 404:
                raise ValueError("DOI cannot be found in the DOI System!")
        except InvalidURL:
            raise ValueError("This DOI is not valid!")

    return doi

BulletEntry

Bases: RenderCVBaseModel

This class is the data model of BulletEntry.

EntryBase

Bases: RenderCVBaseModel

This class is the parent class of some of the entry types. It is being used because some of the entry types have common fields like dates, highlights, location, etc.

date_string: str cached property

Return a date string based on the date, start_date, and end_date fields.

Example

entry = dm.EntryBase(start_date=2020-10-11, end_date=2021-04-04).date_string
will return: "2020-10-11 to 2021-04-04"

date_string_only_years: str cached property

Return a date string that only contains years based on the date, start_date, and end_date fields.

Example

entry = dm.EntryBase(start_date=2020-10-11, end_date=2021-04-04).date_string
will return: "2020 to 2021"

time_span_string: str cached property

Return a time span string based on the date, start_date, and end_date fields.

Example

entry = dm.EntryBase(start_date=2020-01-01, end_date=2020-04-20).time_span
will return: "4 months"

check_and_adjust_dates()

Check if the dates are provided correctly and do the necessary adjustments.

Source code in rendercv/data_models.py
@pydantic.model_validator(
    mode="after",
)
def check_and_adjust_dates(self) -> "EntryBase":
    """
    Check if the dates are provided correctly and do the necessary adjustments.
    """
    date_is_provided = self.date is not None
    start_date_is_provided = self.start_date is not None
    end_date_is_provided = self.end_date is not None

    if date_is_provided:
        # If only date is provided, ignore start_date and end_date:
        self.start_date = None
        self.end_date = None

    elif not start_date_is_provided and end_date_is_provided:
        # If only end_date is provided, assume it is a one-day event and act like
        # only the date is provided:
        self.date = self.end_date
        self.start_date = None
        self.end_date = None
    elif start_date_is_provided:
        start_date = get_date_object(self.start_date)
        if not end_date_is_provided:
            # Then it means only the start_date is provided, so it is an ongoing
            # event:
            self.end_date = "present"
            end_date = Date.today()
        else:
            end_date = get_date_object(self.end_date)

        if start_date > end_date:
            raise ValueError(
                '"start_date" can not be after "end_date"!',
                "start_date",  # this is the location of the error
                str(start_date),  # this is value of the error
            )

    return self

NormalEntry

Bases: EntryBase, NormalEntryBase

This class is the data model of NormalEntry.

ExperienceEntry

Bases: EntryBase, ExperienceEntryBase

This class is the data model of ExperienceEntry.

EducationEntry

Bases: EntryBase, EducationEntryBase

This class is the data model of EducationEntry.

SectionBase

Bases: RenderCVBaseModel

This class is the parent class of all the section types. It is being used because all of the section types have a common field called title.

SocialNetwork

Bases: RenderCVBaseModel

This class is the data model of a social network.

url: str cached property

Return the URL of the social network.

check_username(username, info) classmethod

Check if the username is provided correctly.

Source code in rendercv/data_models.py
@pydantic.field_validator("username")
@classmethod
def check_username(cls, username: str, info: pydantic.ValidationInfo) -> str:
    """Check if the username is provided correctly."""
    network = info.data["network"]

    if network == "Mastodon":
        if not username.startswith("@"):
            raise ValueError("Mastodon username should start with '@'!")
        if username.count("@") != 2:
            raise ValueError("Mastodon username should contain two '@'!")

    return username

validate_urls()

Validate the URLs of the social networks.

Source code in rendercv/data_models.py
@pydantic.model_validator(mode="after")  # type: ignore
def validate_urls(self) -> "SocialNetwork":
    """Validate the URLs of the social networks."""
    url = self.url

    url_validator.validate_strings(url)

    return self

CurriculumVitae

Bases: RenderCVBaseModel

This class is the data model of the CV.

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

Return all the connections of the person.

sections: list[SectionBase] cached property

Return all the sections of the CV with their titles.

LocaleCatalog

Bases: RenderCVBaseModel

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

check_translations(value, info) classmethod

Check if the translations are provided correctly.

Source code in rendercv/data_models.py
@pydantic.field_validator(
    "month", "months", "year", "years", "present", "abbreviations_for_months", "to"
)
@classmethod
def check_translations(cls, value: str, info: pydantic.ValidationInfo) -> str:
    """Check if the translations are provided correctly."""
    if value:
        locale_catalog[info.field_name] = value

RenderCVDataModel

Bases: RenderCVBaseModel

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

initialize_if_custom_theme_is_used(design) classmethod

Initialize the custom theme if it is used and validate it. Otherwise, return the built-in theme.

Source code in rendercv/data_models.py
@pydantic.field_validator("design", mode="before")
@classmethod
def initialize_if_custom_theme_is_used(
    cls, design: RenderCVDesign | Any
) -> RenderCVDesign | Any:
    """Initialize the custom theme if it is used and validate it. Otherwise, return
    the built-in theme."""
    # `get_args` for an Annotated object returns the arguments when Annotated is
    # used. The first argument is actually the union of the types, so we need to
    # access the first argument to use isinstance function.
    theme_data_model_types = get_args(RenderCVDesign)[0]

    if isinstance(design, theme_data_model_types):
        # then it means RenderCVDataModel is already initialized with a design, so
        # return it as is:
        return design
    elif design["theme"] in available_themes:  # type: ignore
        # then it means it's a built-in theme, but it is not initialized (validated)
        # yet. So, validate and return it:
        return rendercv_design_validator.validate_python(design)
    else:
        # then it means it is a custom theme, so initialize and validate it:
        theme_name: str = str(design["theme"])

        # check if the theme name is valid:
        if not theme_name.isalpha():
            raise ValueError(
                "The custom theme name should contain only letters.",
                "theme",  # this is the location of the error
                theme_name,  # this is value of the error
            )

        # then it is a custom theme
        custom_theme_folder = pathlib.Path(theme_name)

        # check if the custom theme folder exists:
        if not custom_theme_folder.exists():
            raise ValueError(
                f"The custom theme folder `{custom_theme_folder}` does not exist."
                " It should be in the working directory as the input file.",
                "",  # this is the location of the error
                theme_name,  # this is value of the error
            )

        # check if all the necessary files are provided in the custom theme folder:
        required_entry_files = [
            entry_type_name + ".j2.tex" for entry_type_name in entry_type_names
        ]
        required_files = [
            "SectionBeginning.j2.tex",  # section beginning template
            "SectionEnding.j2.tex",  # section ending template
            "Preamble.j2.tex",  # preamble template
            "Header.j2.tex",  # header template
        ] + required_entry_files

        for file in required_files:
            file_path = custom_theme_folder / file
            if not file_path.exists():
                raise ValueError(
                    f"You provided a custom theme, but the file `{file}` is not"
                    f" found in the folder `{custom_theme_folder}`.",
                    "",  # this is the location of the error
                    theme_name,  # this is value of the error
                )

        # import __init__.py file from the custom theme folder if it exists:
        path_to_init_file = pathlib.Path(f"{theme_name}/__init__.py")

        if path_to_init_file.exists():
            spec = importlib.util.spec_from_file_location(
                "theme",
                path_to_init_file,
            )

            theme_module = importlib.util.module_from_spec(spec)
            try:
                spec.loader.exec_module(theme_module)  # type: ignore
            except SyntaxError or ImportError:
                raise ValueError(
                    f"The custom theme {theme_name}'s __init__.py file is not"
                    " valid. Please check the file and try again.",
                )

            ThemeDataModel = getattr(
                theme_module, f"{theme_name.capitalize()}ThemeOptions"  # type: ignore
            )

            # initialize and validate the custom theme data model:
            theme_data_model = ThemeDataModel(**design)
        else:
            # Then it means there is no __init__.py file in the custom theme folder.
            # So, create a dummy data model and use that instead.
            class ThemeOptionsAreNotProvided(RenderCVBaseModel):
                theme: str = theme_name

            theme_data_model = ThemeOptionsAreNotProvided(theme=theme_name)

        return theme_data_model

get_date_object(date)

Parse a date string in YYYY-MM-DD, YYYY-MM, or YYYY format and return a datetime.date object. This function is used throughout the validation process of the data models.

Parameters:

  • date (str) –

    The date string to parse.

Returns: datetime.date: The parsed date.

Source code in rendercv/data_models.py
def get_date_object(date: str | int) -> Date:
    """Parse a date string in YYYY-MM-DD, YYYY-MM, or YYYY format and return a
    `datetime.date` object. This function is used throughout the validation process of
    the data models.

    Args:
        date (str): The date string to parse.
    Returns:
        datetime.date: The parsed date.
    """
    if isinstance(date, int):
        date_object = Date.fromisoformat(f"{date}-01-01")
    elif re.fullmatch(r"\d{4}-\d{2}-\d{2}", date):
        # Then it is in YYYY-MM-DD format
        date_object = Date.fromisoformat(date)
    elif re.fullmatch(r"\d{4}-\d{2}", date):
        # Then it is in YYYY-MM format
        date_object = Date.fromisoformat(f"{date}-01")
    elif re.fullmatch(r"\d{4}", date):
        # Then it is in YYYY format
        date_object = Date.fromisoformat(f"{date}-01-01")
    elif date == "present":
        date_object = Date.today()
    else:
        raise ValueError(
            "This is not a valid date! Please use either YYYY-MM-DD, YYYY-MM, or"
            " YYYY format."
        )

    return date_object

format_date(date)

Formats a Date object to a string in the following format: "Jan. 2021".

It uses month abbreviations, taken from Yale University Library.

Example

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

"May 2024"

Parameters:

  • date (date) –

    The date to format.

Returns:

  • str ( str ) –

    The formatted date.

Source code in rendercv/data_models.py
def format_date(date: Date) -> str:
    """Formats a `Date` object to a string in the following format: "Jan. 2021".

    It uses month abbreviations, taken from
    [Yale University Library](https://web.library.yale.edu/cataloging/months).

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

        `#!python "May 2024"`

    Args:
        date (Date): The date to format.

    Returns:
        str: The formatted date.
    """
    # Month abbreviations,
    # taken from: https://web.library.yale.edu/cataloging/months
    abbreviations_of_months = locale_catalog["abbreviations_for_months"]

    month = int(date.strftime("%m"))
    month_abbreviation = abbreviations_of_months[month - 1]
    year = date.strftime(format="%Y")
    date_string = f"{month_abbreviation} {year}"

    return date_string

create_a_section_model(entry_type)

Create a section model based on the entry type. See Pydantic's documentation about dynamic model creation for more information.

Parameters:

  • entry_type (Type[Entry]) –

    The entry type to create the section model.

Returns: Type[SectionBase]: The section model.

Source code in rendercv/data_models.py
def create_a_section_model(entry_type: Type[Entry]) -> Type[SectionBase]:
    """Create a section model based on the entry type. See [Pydantic's documentation
    about dynamic model
    creation](https://pydantic-docs.helpmanual.io/usage/models/#dynamic-model-creation)
    for more information.

    Args:
        entry_type (Type[Entry]): The entry type to create the section model.
    Returns:
        Type[SectionBase]: The section model.
    """
    if entry_type == str:
        model_name = "SectionWithTextEntries"
        entry_type_name = "TextEntry"
    else:
        model_name = "SectionWith" + entry_type.__name__.replace("Entry", "Entries")
        entry_type_name = entry_type.__name__

    SectionModel = pydantic.create_model(
        model_name,
        entry_type=(Literal[entry_type_name], ...),  # type: ignore
        entries=(list[entry_type], ...),
        __base__=SectionBase,
    )

    return SectionModel

get_entry_and_section_type(entry)

Determine the entry and section type based on the entry.

Parameters:

  • entry (dict[str, Any] | Entry) –

    The entry to determine the type.

Returns: tuple[str, Type[Section]]: The entry type and the section type.

Source code in rendercv/data_models.py
def get_entry_and_section_type(
    entry: dict[str, Any] | Entry,
) -> tuple[
    str,
    Type[SectionBase],
]:
    """Determine the entry and section type based on the entry.

    Args:
        entry: The entry to determine the type.
    Returns:
        tuple[str, Type[Section]]: The entry type and the section type.
    """
    # Get class attributes of EntryBase class:
    common_attributes = set(EntryBase.model_fields.keys())

    if isinstance(entry, dict):
        entry_type = None  # the entry type is not determined yet

        for EntryType in entry_types:
            characteristic_entry_attributes = (
                set(EntryType.model_fields.keys()) - common_attributes
            )

            # If at least one of the characteristic_entry_attributes is in the entry,
            # then it means the entry is of this type:
            if characteristic_entry_attributes & set(entry.keys()):
                entry_type = EntryType.__name__
                section_type = create_a_section_model(EntryType)
                break

        if entry_type is None:
            raise ValueError("The entry is not provided correctly.")

    elif isinstance(entry, str):
        # Then it is a TextEntry
        entry_type = "TextEntry"
        section_type = create_a_section_model(str)

    else:
        # Then the entry is already initialized with a data model:
        entry_type = entry.__class__.__name__
        section_type = create_a_section_model(entry.__class__)

    return entry_type, section_type

validate_section_input(sections_input)

Validate a SectionInput object and raise an error if it is not valid.

Sections input is very complex. It is either a Section object or a list of entries. Since there are multiple entry types, it is not possible to validate it directly. This function looks at the entry list's first element and determines the section's entry type based on the first element. Then, it validates the rest of the list based on the determined entry type. If it is a Section object, then it validates it directly.

Parameters:

  • sections_input (SectionBase | list[Any]) –

    The sections input to validate.

Returns: SectionBase | list[Any]: The validated sections input.

Source code in rendercv/data_models.py
def validate_section_input(
    sections_input: SectionBase | list[Any],
) -> SectionBase | list[Any]:
    """Validate a `SectionInput` object and raise an error if it is not valid.

    Sections input is very complex. It is either a `Section` object or a list of
    entries. Since there are multiple entry types, it is not possible to validate it
    directly. This function looks at the entry list's first element and determines the
    section's entry type based on the first element. Then, it validates the rest of the
    list based on the determined entry type. If it is a `Section` object, then it
    validates it directly.

    Args:
        sections_input (SectionBase | list[Any]): The sections input to validate.
    Returns:
        SectionBase | list[Any]: The validated sections input.
    """
    if isinstance(sections_input, list):
        # find the entry type based on the first identifiable entry:
        entry_type = None
        section_type = None
        for entry in sections_input:
            try:
                entry_type, section_type = get_entry_and_section_type(entry)
                break
            except ValueError:
                pass

        if entry_type is None or section_type is None:
            raise ValueError(
                "RenderCV couldn't match this section with any entry type! Please check"
                " the entries and make sure they are provided correctly.",
                "",  # this is the location of the error
                "",  # this is value of the error
            )

        test_section = {
            "title": "Test Section",
            "entry_type": entry_type,
            "entries": sections_input,
        }

        try:
            section_type.model_validate(
                test_section,
                context={"section": "test"},
            )
        except pydantic.ValidationError as e:
            new_error = ValueError(
                "There are problems with the entries. RenderCV detected the entry type"
                f" of this section to be {entry_type}! The problems are shown below.",
                "",  # this is the location of the error
                "",  # this is value of the error
            )
            raise new_error from e

    return sections_input

set_or_update_a_value(data_model, key, value, sub_model=None)

Set or update a value in a data model for a specific key. For example, a key can be cv.sections.education.3.institution and the value can be "Bogazici University".

Parameters:

  • data_model (BaseModel | dict | list) –

    The data model to set or update the value.

  • key (str) –

    The key to set or update the value.

  • value (Any) –

    The value to set or update.

  • sub_model (BaseModel | dict | list, default: None ) –

    The sub model to set or update the value. This is used for recursive calls. When the value is set to a sub model, the original data model is validated. Defaults to None.

Source code in rendercv/data_models.py
def set_or_update_a_value(
    data_model: pydantic.BaseModel | dict | list,
    key: str,
    value: str,
    sub_model: pydantic.BaseModel | dict | list = None,
):
    """Set or update a value in a data model for a specific key. For example, a key can
    be `cv.sections.education.3.institution` and the value can be "Bogazici University".

    Args:
        data_model (pydantic.BaseModel | dict | list): The data model to set or update
            the value.
        key (str): The key to set or update the value.
        value (Any): The value to set or update.
        sub_model (pydantic.BaseModel | dict | list, optional): The sub model to set or
            update the value. This is used for recursive calls. When the value is set
            to a sub model, the original data model is validated. Defaults to None.
    """
    # recursively call this function until the last key is reached:

    # rename `sections` with `sections_input` since the key is `sections` is an alias:
    key = key.replace("sections.", "sections_input.")
    keys = key.split(".")

    if sub_model is not None:
        model = sub_model
    else:
        model = data_model

    if len(keys) == 1:
        # set the value:
        if value.startswith("{") and value.endswith("}"):
            # allow users to assign dictionaries:
            value = eval(value)
        elif value.startswith("[") and value.endswith("]"):
            # allow users to assign lists:
            value = eval(value)

        if isinstance(model, pydantic.BaseModel):
            setattr(model, key, value)
        elif isinstance(model, dict):
            model[key] = value
        elif isinstance(model, list):
            model[int(key)] = value
        else:
            raise ValueError(
                "The data model should be either a Pydantic data model, dictionary, or"
                " list.",
            )

        data_model = type(data_model).model_validate(
            (data_model.model_dump(by_alias=True))
        )
        return data_model
    else:
        # get the first key and call the function with remaining keys:
        first_key = keys[0]
        key = ".".join(keys[1:])
        if isinstance(model, pydantic.BaseModel):
            sub_model = getattr(model, first_key)
        elif isinstance(model, dict):
            sub_model = model[first_key]
        elif isinstance(model, list):
            sub_model = model[int(first_key)]
        else:
            raise ValueError(
                "The data model should be either a Pydantic data model, dictionary, or"
                " list.",
            )

        set_or_update_a_value(data_model, key, value, sub_model)

read_input_file(file_path_or_contents)

Read the input file and return two instances of RenderCVDataModel. The first instance is the data model with $\LaTeX$ strings and the second instance is the data model with markdown strings.

Parameters:

  • file_path (str) –

    The path to the input file.

Returns:

  • RenderCVDataModel ( RenderCVDataModel ) –

    The data models with $\LaTeX$ and markdown strings.

Source code in rendercv/data_models.py
def read_input_file(
    file_path_or_contents: pathlib.Path | str,
) -> RenderCVDataModel:
    """Read the input file and return two instances of
    [RenderCVDataModel](#rendercv.data_models.RenderCVDataModel). The first instance is
    the data model with $\\LaTeX$ strings and the second instance is the data model with
    markdown strings.

    Args:
        file_path (str): The path to the input file.

    Returns:
        RenderCVDataModel: The data models with $\\LaTeX$ and markdown strings.
    """
    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

    input_as_dictionary: dict[str, Any] = ruamel.yaml.YAML().load(file_content)  # type: ignore

    # validate the parsed dictionary by creating an instance of RenderCVDataModel:
    rendercv_data_model = RenderCVDataModel(**input_as_dictionary)

    return rendercv_data_model

get_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: RenderCVDataModel: A sample data model.

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

    Args:
        name (str, optional): The name of the person. Defaults to "John Doe".
    Returns:
        RenderCVDataModel: A sample data model.
    """
    # check if the theme is valid:
    if theme not in available_themes:
        available_themes_string = ", ".join(available_themes)
        raise ValueError(
            f"The theme should be one of the following: {available_themes_string}!"
            f' The provided theme is "{theme}".'
        )

    name = name.encode().decode("unicode-escape")
    sections = {
        "summary": [
            (
                "This is an example resume to showcase the capabilities of the"
                " open-source LaTeX CV generator,"
                " [RenderCV](https://github.com/sinaatalay/rendercv). A substantial"
                " part of the content is taken from"
                " [here](https://www.careercup.com/resume), where a *clean and tidy CV*"
                " pattern is proposed by **Gayle L. McDowell**."
            ),
        ],
        "education": [
            EducationEntry(
                institution="University of Pennsylvania",
                area="Computer Science",
                degree="BS",
                start_date="2000-09",
                end_date="2005-05",
                highlights=[
                    "GPA: 3.9/4.0 ([Transcript](https://example.com))",
                    (
                        "**Coursework:** Software Foundations, Computer"
                        " Architecture, Algorithms, Artificial Intelligence, Comparison"
                        " of Learning Algorithms, Computational Theory."
                    ),
                ],
            ),
        ],
        "experience": [
            ExperienceEntry(
                company="Apple Computer",
                position="Software Engineer, Intern",
                start_date="2004-06",
                end_date="2004-08",
                location="CA, USA",
                highlights=[
                    (
                        "Reduced time to render the user's buddy list by 75% by"
                        " implementing a prediction algorithm."
                    ),
                    (
                        "Implemented iChat integration with OS X Spotlight Search by"
                        " creating a tool that extracts metadata from saved chat"
                        " transcripts and provides metadata to a system-wide search"
                        " database."
                    ),
                    (
                        "Redesigned chat file format and implemented backward"
                        " compatibility for search."
                    ),
                ],
            ),
            ExperienceEntry(
                company="Microsoft Corporation",
                position="Lead Student Ambassador",
                start_date="2003-09",
                end_date="2005-04",
                location="WA, USA",
                highlights=[
                    (
                        "Promoted to Lead Student Ambassador in the Fall of 2004,"
                        " supervised 10 - 15 Student Ambassadors."
                    ),
                    (
                        "Created and taught a computer science course, CSE 099:"
                        " Software Design and Development."
                    ),
                ],
            ),
            ExperienceEntry(
                company="University of Pennsylvania",
                position="Head Teaching Assistant",
                start_date="2001-10",
                end_date="2005-05",
                location="PA, USA",
                highlights=[
                    (
                        "Implemented a user interface for the VS open file switcher"
                        " (ctrl-tab) and extended it to tool windows."
                    ),
                    (
                        "Created a service to provide gradient across VS and VS"
                        " add-ins. Optimized service via caching."
                    ),
                    "Programmer Productivity Research Center (Summers 2001, 2002)",
                    (
                        "Built app to compute the similarity of all methods in a code"
                        " base, reduced time from $\\mathcal{O}(n^2)$ to"
                        " $\\mathcal{O}(n \\log n)$. "
                    ),
                    (
                        "Created a test case generation tool that creates random XML"
                        " docs from XML Schema."
                    ),
                ],
            ),
            ExperienceEntry(
                company="Microsoft Corporation",
                position="Software Design Engineer, Intern",
                start_date="2003-06",
                end_date="2003-08",
                location="WA, USA",
                highlights=[
                    (
                        "Promoted to Lead Student Ambassador in the Fall of 2004,"
                        " supervised 10 - 15 Student Ambassadors."
                    ),
                ],
            ),
        ],
        "publications": [
            PublicationEntry(
                title=(
                    "Magneto-Thermal Thin Shell Approximation for 3D Finite Element"
                    " Analysis of No-Insulation Coils"
                ),
                authors=[
                    "Albert Smith",
                    name,
                    "Jane Derry",
                    "Harry Tom",
                    "Frodo Baggins",
                ],
                date="2004-01",
                doi="10.1109/TASC.2023.3340648",
            )
        ],
        "projects": [
            NormalEntry(
                name="Multi-User Drawing Tool",
                date="2004",
                highlights=[
                    (
                        "Developed an electronic classroom where multiple users can"
                        ' view and simultaneously draw on a "chalkboard" with each'
                        " person's edits synchronized."
                    ),
                    "Used C++ and MFC.",
                ],
            ),
            NormalEntry(
                name="Synchronized Calendar",
                start_date="2003",
                end_date="2004",
                highlights=[
                    (
                        "Developed a desktop calendar with globally shared and"
                        " synchronized calendars, allowing users to schedule meetings"
                        " with other users."
                    ),
                    "Used C#.NET, SQL, and XML.",
                ],
            ),
            NormalEntry(
                name="Operating System",
                date="2002",
                highlights=[
                    (
                        "Developed a UNIX-style OS with a scheduler, file system, text"
                        " editor, and calculator."
                    ),
                    "Used C.",
                ],
            ),
        ],
        "additional_experience_and_awards": [
            OneLineEntry(
                label="Instructor (2003 - 2005)",
                details="Taught two full-credit Computer Science courses.",
            ),
            OneLineEntry(
                label="Third Prize, Senior Design Projects",
                details=(
                    "Awarded 3rd prize for a synchronized calendar project out of 100"
                    " projects."
                ),
            ),
        ],
        "technologies": [
            OneLineEntry(
                label="Languages",
                details="C++, C, Java, Objective-C, C#.NET, SQL, JavaScript",
            ),
            OneLineEntry(
                label="Software",
                details=(
                    "Visual Studio, Microsoft SQL Server, Eclipse, XCode, Interface"
                    " Builder"
                ),
            ),
        ],
    }

    cv = CurriculumVitae(
        name=name,
        location="Your Location",
        email="[email protected]",
        phone="+905419999999",  # type: ignore
        website="https://yourwebsite.com",  # type: ignore
        social_networks=[
            SocialNetwork(network="LinkedIn", username="yourusername"),
            SocialNetwork(network="GitHub", username="yourusername"),
        ],
        sections=sections,  # type: ignore
    )

    if theme == "classic":
        design = ClassicThemeOptions(theme="classic", show_timespan_in=["Experience"])
    else:
        design = rendercv_design_validator.validate_python({"theme": theme})  # type: ignore

    return RenderCVDataModel(cv=cv, design=design)

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 docs directory of the repository and distributed to the users with the JSON Schema Store.

Returns:

  • dict ( dict[str, Any] ) –

    The JSON schema of RenderCV.

Source code in rendercv/data_models.py
def generate_json_schema() -> dict[str, Any]:
    """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 `docs` directory of the repository
    and distributed to the users with the
    [JSON Schema Store](https://www.schemastore.org/).

    Returns:
        dict: The JSON schema of RenderCV.
    """

    # def loop_through_pro

    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 = {}
                null_type_dict["type"] = "null"
                for field_name, field in value["properties"].items():
                    if "anyOf" in field:
                        if (
                            len(field["anyOf"]) == 2
                            and null_type_dict in field["anyOf"]
                        ):
                            field["oneOf"] = [field["anyOf"][0]]
                            del field["anyOf"]

                            # for sections field of CurriculumVitae:
                            if "additionalProperties" in field["oneOf"][0]:
                                field["oneOf"][0]["additionalProperties"]["oneOf"] = (
                                    field["oneOf"][0]["additionalProperties"]["anyOf"]
                                )
                                del field["oneOf"][0]["additionalProperties"]["anyOf"]

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

                # In date field, we both accept normal strings and Date objects. They
                # are both strings, therefore, if user provides a Date object, then
                # JSON schema will complain that it matches two different types.
                # Remember that all of the anyOfs are changed to oneOfs. Only one of
                # the types can be matched. Therefore, we remove the first type, which
                # is the string with the YYYY-MM-DD format.
                if (
                    "date" in value["properties"]
                    and "oneOf" in value["properties"]["date"]
                ):
                    del value["properties"]["date"]["oneOf"][0]

            return json_schema

    schema = 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_models.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 (pathlib.Path): The path to save the JSON schema.
    """
    schema = generate_json_schema()
    schema_json = json.dumps(schema, indent=2)
    json_schema_path.write_text(schema_json)