From 120b63cc0897b71c7032b8e636a16ec5dcdc3de4 Mon Sep 17 00:00:00 2001 From: Sina Atalay Date: Fri, 5 Jul 2024 00:29:25 +0300 Subject: [PATCH] update subpackage names and packaging structure --- docs/update_entry_figures.py | 2 +- docs/update_examples.py | 2 +- docs/update_schema.py | 2 +- rendercv/cli/commands.py | 7 +- rendercv/cli/printer.py | 17 +-- rendercv/cli/utilities.py | 76 +++++++++- rendercv/{reader => data}/__init__.py | 2 + .../{reader/reader.py => data/generator.py} | 142 ------------------ rendercv/{reader => data}/models/__init__.py | 5 +- rendercv/{reader => data}/models/base.py | 0 rendercv/{reader => data}/models/computers.py | 0 .../models/curriculum_vitae.py | 0 rendercv/{reader => data}/models/design.py | 0 .../{reader => data}/models/entry_types.py | 0 .../{reader => data}/models/locale_catalog.py | 0 .../models/rendercv_data_model.py | 0 rendercv/data/reader.py | 78 ++++++++++ rendercv/{reader => data}/sample_content.yaml | 0 rendercv/renderer/renderer.py | 4 +- .../renderer/{templating.py => templater.py} | 2 +- rendercv/{ => renderer}/themes/__init__.py | 0 .../themes/classic/BulletEntry.j2.tex | 0 .../themes/classic/EducationEntry.j2.tex | 0 .../themes/classic/ExperienceEntry.j2.tex | 0 .../themes/classic/Header.j2.tex | 0 .../themes/classic/NormalEntry.j2.tex | 0 .../themes/classic/OneLineEntry.j2.tex | 0 .../themes/classic/Preamble.j2.tex | 0 .../themes/classic/PublicationEntry.j2.tex | 0 .../themes/classic/SectionBeginning.j2.tex | 0 .../themes/classic/SectionEnding.j2.tex | 0 .../themes/classic/TextEntry.j2.tex | 0 .../{ => renderer}/themes/classic/__init__.py | 0 .../engineeringresumes/BulletEntry.j2.tex | 0 .../engineeringresumes/EducationEntry.j2.tex | 0 .../engineeringresumes/ExperienceEntry.j2.tex | 0 .../themes/engineeringresumes/Header.j2.tex | 0 .../engineeringresumes/NormalEntry.j2.tex | 0 .../engineeringresumes/OneLineEntry.j2.tex | 0 .../themes/engineeringresumes/Preamble.j2.tex | 0 .../PublicationEntry.j2.tex | 0 .../SectionBeginning.j2.tex | 0 .../engineeringresumes/SectionEnding.j2.tex | 0 .../engineeringresumes/TextEntry.j2.tex | 0 .../themes/engineeringresumes/__init__.py | 0 rendercv/{ => renderer}/themes/main.j2.html | 0 rendercv/{ => renderer}/themes/main.j2.md | 0 rendercv/{ => renderer}/themes/main.j2.tex | 0 .../themes/markdown/BulletEntry.j2.md | 0 .../themes/markdown/EducationEntry.j2.md | 0 .../themes/markdown/ExperienceEntry.j2.md | 0 .../themes/markdown/Header.j2.md | 0 .../themes/markdown/NormalEntry.j2.md | 0 .../themes/markdown/OneLineEntry.j2.md | 0 .../themes/markdown/PublicationEntry.j2.md | 0 .../themes/markdown/SectionBeginning.j2.md | 0 .../themes/markdown/TextEntry.j2.md | 0 .../themes/moderncv/BulletEntry.j2.tex | 0 .../themes/moderncv/EducationEntry.j2.tex | 0 .../themes/moderncv/ExperienceEntry.j2.tex | 0 .../themes/moderncv/Header.j2.tex | 0 .../themes/moderncv/NormalEntry.j2.tex | 0 .../themes/moderncv/OneLineEntry.j2.tex | 0 .../themes/moderncv/Preamble.j2.tex | 0 .../themes/moderncv/PublicationEntry.j2.tex | 0 .../themes/moderncv/SectionBeginning.j2.tex | 0 .../themes/moderncv/SectionEnding.j2.tex | 0 .../themes/moderncv/TextEntry.j2.tex | 0 .../themes/moderncv/__init__.py | 0 .../themes/sb2nov/BulletEntry.j2.tex | 0 .../themes/sb2nov/EducationEntry.j2.tex | 0 .../themes/sb2nov/ExperienceEntry.j2.tex | 0 .../themes/sb2nov/Header.j2.tex | 0 .../themes/sb2nov/NormalEntry.j2.tex | 0 .../themes/sb2nov/OneLineEntry.j2.tex | 0 .../themes/sb2nov/Preamble.j2.tex | 0 .../themes/sb2nov/PublicationEntry.j2.tex | 0 .../themes/sb2nov/SectionBeginning.j2.tex | 0 .../themes/sb2nov/SectionEnding.j2.tex | 0 .../themes/sb2nov/TextEntry.j2.tex | 0 .../{ => renderer}/themes/sb2nov/__init__.py | 0 tests/conftest.py | 4 +- tests/test_cli.py | 6 +- tests/test_reader.py | 2 +- tests/test_renderer.py | 2 +- 85 files changed, 183 insertions(+), 170 deletions(-) rename rendercv/{reader => data}/__init__.py (95%) rename rendercv/{reader/reader.py => data/generator.py} (54%) rename rendercv/{reader => data}/models/__init__.py (81%) rename rendercv/{reader => data}/models/base.py (100%) rename rendercv/{reader => data}/models/computers.py (100%) rename rendercv/{reader => data}/models/curriculum_vitae.py (100%) rename rendercv/{reader => data}/models/design.py (100%) rename rendercv/{reader => data}/models/entry_types.py (100%) rename rendercv/{reader => data}/models/locale_catalog.py (100%) rename rendercv/{reader => data}/models/rendercv_data_model.py (100%) create mode 100644 rendercv/data/reader.py rename rendercv/{reader => data}/sample_content.yaml (100%) rename rendercv/renderer/{templating.py => templater.py} (99%) rename rendercv/{ => renderer}/themes/__init__.py (100%) rename rendercv/{ => renderer}/themes/classic/BulletEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/EducationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/ExperienceEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/Header.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/NormalEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/OneLineEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/Preamble.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/PublicationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/SectionBeginning.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/SectionEnding.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/TextEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/classic/__init__.py (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/BulletEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/EducationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/ExperienceEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/Header.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/NormalEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/OneLineEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/Preamble.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/PublicationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/SectionBeginning.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/SectionEnding.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/TextEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/engineeringresumes/__init__.py (100%) rename rendercv/{ => renderer}/themes/main.j2.html (100%) rename rendercv/{ => renderer}/themes/main.j2.md (100%) rename rendercv/{ => renderer}/themes/main.j2.tex (100%) rename rendercv/{ => renderer}/themes/markdown/BulletEntry.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/EducationEntry.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/ExperienceEntry.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/Header.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/NormalEntry.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/OneLineEntry.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/PublicationEntry.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/SectionBeginning.j2.md (100%) rename rendercv/{ => renderer}/themes/markdown/TextEntry.j2.md (100%) rename rendercv/{ => renderer}/themes/moderncv/BulletEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/EducationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/ExperienceEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/Header.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/NormalEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/OneLineEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/Preamble.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/PublicationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/SectionBeginning.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/SectionEnding.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/TextEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/moderncv/__init__.py (100%) rename rendercv/{ => renderer}/themes/sb2nov/BulletEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/EducationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/ExperienceEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/Header.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/NormalEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/OneLineEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/Preamble.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/PublicationEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/SectionBeginning.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/SectionEnding.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/TextEntry.j2.tex (100%) rename rendercv/{ => renderer}/themes/sb2nov/__init__.py (100%) diff --git a/docs/update_entry_figures.py b/docs/update_entry_figures.py index bbb00e74..e1340c51 100644 --- a/docs/update_entry_figures.py +++ b/docs/update_entry_figures.py @@ -14,7 +14,7 @@ from typing import Any import pdfCropMargins import ruamel.yaml -import rendercv.reader as dm +import rendercv.data as dm import rendercv.renderer as r repository_root = pathlib.Path(__file__).parent.parent diff --git a/docs/update_examples.py b/docs/update_examples.py index 8a0935f9..0e90bff2 100644 --- a/docs/update_examples.py +++ b/docs/update_examples.py @@ -5,7 +5,7 @@ import pathlib import shutil import rendercv.cli as cli -import rendercv.reader as dm +import rendercv.data as dm import rendercv.renderer as r repository_root = pathlib.Path(__file__).parent.parent diff --git a/docs/update_schema.py b/docs/update_schema.py index 1ac53472..4bb2c5ca 100644 --- a/docs/update_schema.py +++ b/docs/update_schema.py @@ -2,7 +2,7 @@ import pathlib -import rendercv.reader as dm +import rendercv.data as dm repository_root = pathlib.Path(__file__).parent.parent diff --git a/rendercv/cli/commands.py b/rendercv/cli/commands.py index 5fd16baa..69eeadda 100644 --- a/rendercv/cli/commands.py +++ b/rendercv/cli/commands.py @@ -13,20 +13,21 @@ import typer from rich import print from .. import __version__ -from .. import reader as dm +from .. import data as dm from .. import renderer as r from .printer import ( LiveProgressReporter, error, + handle_and_print_raised_exceptions, information, warn_if_new_version_is_available, warning, welcome, - handle_and_print_raised_exceptions, ) from .utilities import ( copy_templates, parse_render_command_override_arguments, + set_or_update_a_value, ) app = typer.Typer( @@ -189,7 +190,7 @@ def cli_command_render( try: # set the key (for example, cv.sections.education.0.institution) to # the value - data_model = dm.set_or_update_a_value(data_model, key, value) + data_model = set_or_update_a_value(data_model, key, value) except pydantic.ValidationError as e: raise e except (ValueError, KeyError, IndexError, AttributeError): diff --git a/rendercv/cli/printer.py b/rendercv/cli/printer.py index 9c1cf915..13968b30 100644 --- a/rendercv/cli/printer.py +++ b/rendercv/cli/printer.py @@ -3,13 +3,17 @@ The `rendercv.cli.printer` module contains all the functions and classes that ar to print nice-looking messages to the terminal. """ -from typing import Optional +import functools +from typing import Callable, Optional +import jinja2 import pydantic import rich +import rich.live +import ruamel.yaml +import ruamel.yaml.parser import typer from rich import print -import rich.live from .. import __version__ from .utilities import ( @@ -17,15 +21,6 @@ from .utilities import ( get_latest_version_number_from_pypi, ) -import functools -from typing import Callable - -import jinja2 -import pydantic -import ruamel.yaml -import ruamel.yaml.parser -import typer - class LiveProgressReporter(rich.live.Live): """This class is a wrapper around `rich.live.Live` that provides the live progress diff --git a/rendercv/cli/utilities.py b/rendercv/cli/utilities.py index e6594aad..a670ad6a 100644 --- a/rendercv/cli/utilities.py +++ b/rendercv/cli/utilities.py @@ -10,6 +10,80 @@ import urllib.request from typing import Optional import typer +import pydantic + + +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) def get_latest_version_number_from_pypi() -> Optional[str]: @@ -95,7 +169,7 @@ def copy_templates( shutil.copytree( template_directory, destination, - ignore=shutil.ignore_patterns("__init__.py"), + ignore=shutil.ignore_patterns("__init__.py", "__pycache__"), ) return destination diff --git a/rendercv/reader/__init__.py b/rendercv/data/__init__.py similarity index 95% rename from rendercv/reader/__init__.py rename to rendercv/data/__init__.py index f50ad232..25ef9302 100644 --- a/rendercv/reader/__init__.py +++ b/rendercv/data/__init__.py @@ -25,6 +25,7 @@ from .models import ( SocialNetwork, available_theme_options, format_date, + available_social_networks, ) from .reader import ( create_a_sample_data_model, @@ -56,4 +57,5 @@ __all__ = [ "read_input_file", "format_date", "Entry", + "available_social_networks", ] diff --git a/rendercv/reader/reader.py b/rendercv/data/generator.py similarity index 54% rename from rendercv/reader/reader.py rename to rendercv/data/generator.py index 24442f9f..fd408c54 100644 --- a/rendercv/reader/reader.py +++ b/rendercv/data/generator.py @@ -1,9 +1,3 @@ -""" -The `rendercv.data_models.generators` module contains the functions that are used to -generate a sample YAML input file and the JSON schema of RenderCV based on the data -models defined in `rendercv.data_models.models`. -""" - import io import json import pathlib @@ -33,48 +27,6 @@ def dictionary_to_yaml(dictionary: dict[str, Any]): return yaml_string -def read_a_yaml_file(file_path_or_contents: pathlib.Path) -> dict[str, Any]: - """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 (pathlib.Path): 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. - """ - 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[str, Any] = ruamel.yaml.YAML().load(file_content) - - return yaml_as_a_dictionary - - def create_a_sample_data_model( name: str = "John Doe", theme: str = "classic" ) -> models.RenderCVDataModel: @@ -213,97 +165,3 @@ def generate_json_schema_file(json_schema_path: pathlib.Path): schema = generate_json_schema() schema_json = json.dumps(schema, indent=2, ensure_ascii=False) json_schema_path.write_text(schema_json, encoding="utf-8") - - -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) - - -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 (str): The path to the input file or the contents of the - input file as a string. - - Returns: - RenderCVDataModel: The data models with $\\LaTeX$ and Markdown strings. - """ - input_as_dictionary = read_a_yaml_file(file_path_or_contents) - - # Validate the parsed dictionary by creating an instance of RenderCVDataModel: - rendercv_data_model = models.RenderCVDataModel(**input_as_dictionary) - - return rendercv_data_model diff --git a/rendercv/reader/models/__init__.py b/rendercv/data/models/__init__.py similarity index 81% rename from rendercv/reader/models/__init__.py rename to rendercv/data/models/__init__.py index 84bcd644..4271915d 100644 --- a/rendercv/reader/models/__init__.py +++ b/rendercv/data/models/__init__.py @@ -1,5 +1,5 @@ from .computers import format_date -from .curriculum_vitae import CurriculumVitae, SocialNetwork +from .curriculum_vitae import CurriculumVitae, SocialNetwork, available_social_networks from .design import available_theme_options from .entry_types import ( BulletEntry, @@ -26,5 +26,6 @@ __all__ = [ "RenderCVDataModel", "available_theme_options", "format_date", - "Entry" + "Entry", + "available_social_networks", ] diff --git a/rendercv/reader/models/base.py b/rendercv/data/models/base.py similarity index 100% rename from rendercv/reader/models/base.py rename to rendercv/data/models/base.py diff --git a/rendercv/reader/models/computers.py b/rendercv/data/models/computers.py similarity index 100% rename from rendercv/reader/models/computers.py rename to rendercv/data/models/computers.py diff --git a/rendercv/reader/models/curriculum_vitae.py b/rendercv/data/models/curriculum_vitae.py similarity index 100% rename from rendercv/reader/models/curriculum_vitae.py rename to rendercv/data/models/curriculum_vitae.py diff --git a/rendercv/reader/models/design.py b/rendercv/data/models/design.py similarity index 100% rename from rendercv/reader/models/design.py rename to rendercv/data/models/design.py diff --git a/rendercv/reader/models/entry_types.py b/rendercv/data/models/entry_types.py similarity index 100% rename from rendercv/reader/models/entry_types.py rename to rendercv/data/models/entry_types.py diff --git a/rendercv/reader/models/locale_catalog.py b/rendercv/data/models/locale_catalog.py similarity index 100% rename from rendercv/reader/models/locale_catalog.py rename to rendercv/data/models/locale_catalog.py diff --git a/rendercv/reader/models/rendercv_data_model.py b/rendercv/data/models/rendercv_data_model.py similarity index 100% rename from rendercv/reader/models/rendercv_data_model.py rename to rendercv/data/models/rendercv_data_model.py diff --git a/rendercv/data/reader.py b/rendercv/data/reader.py new file mode 100644 index 00000000..b574fd42 --- /dev/null +++ b/rendercv/data/reader.py @@ -0,0 +1,78 @@ +""" +The `rendercv.data_models.generators` module contains the functions that are used to +generate a sample YAML input file and the JSON schema of RenderCV based on the data +models defined in `rendercv.data_models.models`. +""" + +import io +import json +import pathlib +from typing import Any, Optional + +import pydantic +import ruamel.yaml + +from . import models + + +def read_a_yaml_file(file_path_or_contents: pathlib.Path) -> dict[str, Any]: + """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 (pathlib.Path): 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. + """ + 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[str, Any] = ruamel.yaml.YAML().load(file_content) + + return yaml_as_a_dictionary + + +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 (str): The path to the input file or the contents of the + input file as a string. + + Returns: + RenderCVDataModel: The data models with $\\LaTeX$ and Markdown strings. + """ + input_as_dictionary = read_a_yaml_file(file_path_or_contents) + + # Validate the parsed dictionary by creating an instance of RenderCVDataModel: + rendercv_data_model = models.RenderCVDataModel(**input_as_dictionary) + + return rendercv_data_model diff --git a/rendercv/reader/sample_content.yaml b/rendercv/data/sample_content.yaml similarity index 100% rename from rendercv/reader/sample_content.yaml rename to rendercv/data/sample_content.yaml diff --git a/rendercv/renderer/renderer.py b/rendercv/renderer/renderer.py index 5f8703a0..5868fb5b 100644 --- a/rendercv/renderer/renderer.py +++ b/rendercv/renderer/renderer.py @@ -14,8 +14,8 @@ from typing import Optional import fitz import markdown -from .. import reader as dm -from . import templating as tp +from .. import data as dm +from . import templater as tp def copy_theme_files_to_output_directory( diff --git a/rendercv/renderer/templating.py b/rendercv/renderer/templater.py similarity index 99% rename from rendercv/renderer/templating.py rename to rendercv/renderer/templater.py index 44948a2e..2bf649aa 100644 --- a/rendercv/renderer/templating.py +++ b/rendercv/renderer/templater.py @@ -12,7 +12,7 @@ from typing import Any, Optional import jinja2 -from .. import reader as dm +from .. import data as dm class TemplatedFile: diff --git a/rendercv/themes/__init__.py b/rendercv/renderer/themes/__init__.py similarity index 100% rename from rendercv/themes/__init__.py rename to rendercv/renderer/themes/__init__.py diff --git a/rendercv/themes/classic/BulletEntry.j2.tex b/rendercv/renderer/themes/classic/BulletEntry.j2.tex similarity index 100% rename from rendercv/themes/classic/BulletEntry.j2.tex rename to rendercv/renderer/themes/classic/BulletEntry.j2.tex diff --git a/rendercv/themes/classic/EducationEntry.j2.tex b/rendercv/renderer/themes/classic/EducationEntry.j2.tex similarity index 100% rename from rendercv/themes/classic/EducationEntry.j2.tex rename to rendercv/renderer/themes/classic/EducationEntry.j2.tex diff --git a/rendercv/themes/classic/ExperienceEntry.j2.tex b/rendercv/renderer/themes/classic/ExperienceEntry.j2.tex similarity index 100% rename from rendercv/themes/classic/ExperienceEntry.j2.tex rename to rendercv/renderer/themes/classic/ExperienceEntry.j2.tex diff --git a/rendercv/themes/classic/Header.j2.tex b/rendercv/renderer/themes/classic/Header.j2.tex similarity index 100% rename from rendercv/themes/classic/Header.j2.tex rename to rendercv/renderer/themes/classic/Header.j2.tex diff --git a/rendercv/themes/classic/NormalEntry.j2.tex b/rendercv/renderer/themes/classic/NormalEntry.j2.tex similarity index 100% rename from rendercv/themes/classic/NormalEntry.j2.tex rename to rendercv/renderer/themes/classic/NormalEntry.j2.tex diff --git a/rendercv/themes/classic/OneLineEntry.j2.tex b/rendercv/renderer/themes/classic/OneLineEntry.j2.tex similarity index 100% rename from rendercv/themes/classic/OneLineEntry.j2.tex rename to rendercv/renderer/themes/classic/OneLineEntry.j2.tex diff --git a/rendercv/themes/classic/Preamble.j2.tex b/rendercv/renderer/themes/classic/Preamble.j2.tex similarity index 100% rename from rendercv/themes/classic/Preamble.j2.tex rename to rendercv/renderer/themes/classic/Preamble.j2.tex diff --git a/rendercv/themes/classic/PublicationEntry.j2.tex b/rendercv/renderer/themes/classic/PublicationEntry.j2.tex similarity index 100% rename from rendercv/themes/classic/PublicationEntry.j2.tex rename to rendercv/renderer/themes/classic/PublicationEntry.j2.tex diff --git a/rendercv/themes/classic/SectionBeginning.j2.tex b/rendercv/renderer/themes/classic/SectionBeginning.j2.tex similarity index 100% rename from rendercv/themes/classic/SectionBeginning.j2.tex rename to rendercv/renderer/themes/classic/SectionBeginning.j2.tex diff --git a/rendercv/themes/classic/SectionEnding.j2.tex b/rendercv/renderer/themes/classic/SectionEnding.j2.tex similarity index 100% rename from rendercv/themes/classic/SectionEnding.j2.tex rename to rendercv/renderer/themes/classic/SectionEnding.j2.tex diff --git a/rendercv/themes/classic/TextEntry.j2.tex b/rendercv/renderer/themes/classic/TextEntry.j2.tex similarity index 100% rename from rendercv/themes/classic/TextEntry.j2.tex rename to rendercv/renderer/themes/classic/TextEntry.j2.tex diff --git a/rendercv/themes/classic/__init__.py b/rendercv/renderer/themes/classic/__init__.py similarity index 100% rename from rendercv/themes/classic/__init__.py rename to rendercv/renderer/themes/classic/__init__.py diff --git a/rendercv/themes/engineeringresumes/BulletEntry.j2.tex b/rendercv/renderer/themes/engineeringresumes/BulletEntry.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/BulletEntry.j2.tex rename to rendercv/renderer/themes/engineeringresumes/BulletEntry.j2.tex diff --git a/rendercv/themes/engineeringresumes/EducationEntry.j2.tex b/rendercv/renderer/themes/engineeringresumes/EducationEntry.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/EducationEntry.j2.tex rename to rendercv/renderer/themes/engineeringresumes/EducationEntry.j2.tex diff --git a/rendercv/themes/engineeringresumes/ExperienceEntry.j2.tex b/rendercv/renderer/themes/engineeringresumes/ExperienceEntry.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/ExperienceEntry.j2.tex rename to rendercv/renderer/themes/engineeringresumes/ExperienceEntry.j2.tex diff --git a/rendercv/themes/engineeringresumes/Header.j2.tex b/rendercv/renderer/themes/engineeringresumes/Header.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/Header.j2.tex rename to rendercv/renderer/themes/engineeringresumes/Header.j2.tex diff --git a/rendercv/themes/engineeringresumes/NormalEntry.j2.tex b/rendercv/renderer/themes/engineeringresumes/NormalEntry.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/NormalEntry.j2.tex rename to rendercv/renderer/themes/engineeringresumes/NormalEntry.j2.tex diff --git a/rendercv/themes/engineeringresumes/OneLineEntry.j2.tex b/rendercv/renderer/themes/engineeringresumes/OneLineEntry.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/OneLineEntry.j2.tex rename to rendercv/renderer/themes/engineeringresumes/OneLineEntry.j2.tex diff --git a/rendercv/themes/engineeringresumes/Preamble.j2.tex b/rendercv/renderer/themes/engineeringresumes/Preamble.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/Preamble.j2.tex rename to rendercv/renderer/themes/engineeringresumes/Preamble.j2.tex diff --git a/rendercv/themes/engineeringresumes/PublicationEntry.j2.tex b/rendercv/renderer/themes/engineeringresumes/PublicationEntry.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/PublicationEntry.j2.tex rename to rendercv/renderer/themes/engineeringresumes/PublicationEntry.j2.tex diff --git a/rendercv/themes/engineeringresumes/SectionBeginning.j2.tex b/rendercv/renderer/themes/engineeringresumes/SectionBeginning.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/SectionBeginning.j2.tex rename to rendercv/renderer/themes/engineeringresumes/SectionBeginning.j2.tex diff --git a/rendercv/themes/engineeringresumes/SectionEnding.j2.tex b/rendercv/renderer/themes/engineeringresumes/SectionEnding.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/SectionEnding.j2.tex rename to rendercv/renderer/themes/engineeringresumes/SectionEnding.j2.tex diff --git a/rendercv/themes/engineeringresumes/TextEntry.j2.tex b/rendercv/renderer/themes/engineeringresumes/TextEntry.j2.tex similarity index 100% rename from rendercv/themes/engineeringresumes/TextEntry.j2.tex rename to rendercv/renderer/themes/engineeringresumes/TextEntry.j2.tex diff --git a/rendercv/themes/engineeringresumes/__init__.py b/rendercv/renderer/themes/engineeringresumes/__init__.py similarity index 100% rename from rendercv/themes/engineeringresumes/__init__.py rename to rendercv/renderer/themes/engineeringresumes/__init__.py diff --git a/rendercv/themes/main.j2.html b/rendercv/renderer/themes/main.j2.html similarity index 100% rename from rendercv/themes/main.j2.html rename to rendercv/renderer/themes/main.j2.html diff --git a/rendercv/themes/main.j2.md b/rendercv/renderer/themes/main.j2.md similarity index 100% rename from rendercv/themes/main.j2.md rename to rendercv/renderer/themes/main.j2.md diff --git a/rendercv/themes/main.j2.tex b/rendercv/renderer/themes/main.j2.tex similarity index 100% rename from rendercv/themes/main.j2.tex rename to rendercv/renderer/themes/main.j2.tex diff --git a/rendercv/themes/markdown/BulletEntry.j2.md b/rendercv/renderer/themes/markdown/BulletEntry.j2.md similarity index 100% rename from rendercv/themes/markdown/BulletEntry.j2.md rename to rendercv/renderer/themes/markdown/BulletEntry.j2.md diff --git a/rendercv/themes/markdown/EducationEntry.j2.md b/rendercv/renderer/themes/markdown/EducationEntry.j2.md similarity index 100% rename from rendercv/themes/markdown/EducationEntry.j2.md rename to rendercv/renderer/themes/markdown/EducationEntry.j2.md diff --git a/rendercv/themes/markdown/ExperienceEntry.j2.md b/rendercv/renderer/themes/markdown/ExperienceEntry.j2.md similarity index 100% rename from rendercv/themes/markdown/ExperienceEntry.j2.md rename to rendercv/renderer/themes/markdown/ExperienceEntry.j2.md diff --git a/rendercv/themes/markdown/Header.j2.md b/rendercv/renderer/themes/markdown/Header.j2.md similarity index 100% rename from rendercv/themes/markdown/Header.j2.md rename to rendercv/renderer/themes/markdown/Header.j2.md diff --git a/rendercv/themes/markdown/NormalEntry.j2.md b/rendercv/renderer/themes/markdown/NormalEntry.j2.md similarity index 100% rename from rendercv/themes/markdown/NormalEntry.j2.md rename to rendercv/renderer/themes/markdown/NormalEntry.j2.md diff --git a/rendercv/themes/markdown/OneLineEntry.j2.md b/rendercv/renderer/themes/markdown/OneLineEntry.j2.md similarity index 100% rename from rendercv/themes/markdown/OneLineEntry.j2.md rename to rendercv/renderer/themes/markdown/OneLineEntry.j2.md diff --git a/rendercv/themes/markdown/PublicationEntry.j2.md b/rendercv/renderer/themes/markdown/PublicationEntry.j2.md similarity index 100% rename from rendercv/themes/markdown/PublicationEntry.j2.md rename to rendercv/renderer/themes/markdown/PublicationEntry.j2.md diff --git a/rendercv/themes/markdown/SectionBeginning.j2.md b/rendercv/renderer/themes/markdown/SectionBeginning.j2.md similarity index 100% rename from rendercv/themes/markdown/SectionBeginning.j2.md rename to rendercv/renderer/themes/markdown/SectionBeginning.j2.md diff --git a/rendercv/themes/markdown/TextEntry.j2.md b/rendercv/renderer/themes/markdown/TextEntry.j2.md similarity index 100% rename from rendercv/themes/markdown/TextEntry.j2.md rename to rendercv/renderer/themes/markdown/TextEntry.j2.md diff --git a/rendercv/themes/moderncv/BulletEntry.j2.tex b/rendercv/renderer/themes/moderncv/BulletEntry.j2.tex similarity index 100% rename from rendercv/themes/moderncv/BulletEntry.j2.tex rename to rendercv/renderer/themes/moderncv/BulletEntry.j2.tex diff --git a/rendercv/themes/moderncv/EducationEntry.j2.tex b/rendercv/renderer/themes/moderncv/EducationEntry.j2.tex similarity index 100% rename from rendercv/themes/moderncv/EducationEntry.j2.tex rename to rendercv/renderer/themes/moderncv/EducationEntry.j2.tex diff --git a/rendercv/themes/moderncv/ExperienceEntry.j2.tex b/rendercv/renderer/themes/moderncv/ExperienceEntry.j2.tex similarity index 100% rename from rendercv/themes/moderncv/ExperienceEntry.j2.tex rename to rendercv/renderer/themes/moderncv/ExperienceEntry.j2.tex diff --git a/rendercv/themes/moderncv/Header.j2.tex b/rendercv/renderer/themes/moderncv/Header.j2.tex similarity index 100% rename from rendercv/themes/moderncv/Header.j2.tex rename to rendercv/renderer/themes/moderncv/Header.j2.tex diff --git a/rendercv/themes/moderncv/NormalEntry.j2.tex b/rendercv/renderer/themes/moderncv/NormalEntry.j2.tex similarity index 100% rename from rendercv/themes/moderncv/NormalEntry.j2.tex rename to rendercv/renderer/themes/moderncv/NormalEntry.j2.tex diff --git a/rendercv/themes/moderncv/OneLineEntry.j2.tex b/rendercv/renderer/themes/moderncv/OneLineEntry.j2.tex similarity index 100% rename from rendercv/themes/moderncv/OneLineEntry.j2.tex rename to rendercv/renderer/themes/moderncv/OneLineEntry.j2.tex diff --git a/rendercv/themes/moderncv/Preamble.j2.tex b/rendercv/renderer/themes/moderncv/Preamble.j2.tex similarity index 100% rename from rendercv/themes/moderncv/Preamble.j2.tex rename to rendercv/renderer/themes/moderncv/Preamble.j2.tex diff --git a/rendercv/themes/moderncv/PublicationEntry.j2.tex b/rendercv/renderer/themes/moderncv/PublicationEntry.j2.tex similarity index 100% rename from rendercv/themes/moderncv/PublicationEntry.j2.tex rename to rendercv/renderer/themes/moderncv/PublicationEntry.j2.tex diff --git a/rendercv/themes/moderncv/SectionBeginning.j2.tex b/rendercv/renderer/themes/moderncv/SectionBeginning.j2.tex similarity index 100% rename from rendercv/themes/moderncv/SectionBeginning.j2.tex rename to rendercv/renderer/themes/moderncv/SectionBeginning.j2.tex diff --git a/rendercv/themes/moderncv/SectionEnding.j2.tex b/rendercv/renderer/themes/moderncv/SectionEnding.j2.tex similarity index 100% rename from rendercv/themes/moderncv/SectionEnding.j2.tex rename to rendercv/renderer/themes/moderncv/SectionEnding.j2.tex diff --git a/rendercv/themes/moderncv/TextEntry.j2.tex b/rendercv/renderer/themes/moderncv/TextEntry.j2.tex similarity index 100% rename from rendercv/themes/moderncv/TextEntry.j2.tex rename to rendercv/renderer/themes/moderncv/TextEntry.j2.tex diff --git a/rendercv/themes/moderncv/__init__.py b/rendercv/renderer/themes/moderncv/__init__.py similarity index 100% rename from rendercv/themes/moderncv/__init__.py rename to rendercv/renderer/themes/moderncv/__init__.py diff --git a/rendercv/themes/sb2nov/BulletEntry.j2.tex b/rendercv/renderer/themes/sb2nov/BulletEntry.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/BulletEntry.j2.tex rename to rendercv/renderer/themes/sb2nov/BulletEntry.j2.tex diff --git a/rendercv/themes/sb2nov/EducationEntry.j2.tex b/rendercv/renderer/themes/sb2nov/EducationEntry.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/EducationEntry.j2.tex rename to rendercv/renderer/themes/sb2nov/EducationEntry.j2.tex diff --git a/rendercv/themes/sb2nov/ExperienceEntry.j2.tex b/rendercv/renderer/themes/sb2nov/ExperienceEntry.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/ExperienceEntry.j2.tex rename to rendercv/renderer/themes/sb2nov/ExperienceEntry.j2.tex diff --git a/rendercv/themes/sb2nov/Header.j2.tex b/rendercv/renderer/themes/sb2nov/Header.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/Header.j2.tex rename to rendercv/renderer/themes/sb2nov/Header.j2.tex diff --git a/rendercv/themes/sb2nov/NormalEntry.j2.tex b/rendercv/renderer/themes/sb2nov/NormalEntry.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/NormalEntry.j2.tex rename to rendercv/renderer/themes/sb2nov/NormalEntry.j2.tex diff --git a/rendercv/themes/sb2nov/OneLineEntry.j2.tex b/rendercv/renderer/themes/sb2nov/OneLineEntry.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/OneLineEntry.j2.tex rename to rendercv/renderer/themes/sb2nov/OneLineEntry.j2.tex diff --git a/rendercv/themes/sb2nov/Preamble.j2.tex b/rendercv/renderer/themes/sb2nov/Preamble.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/Preamble.j2.tex rename to rendercv/renderer/themes/sb2nov/Preamble.j2.tex diff --git a/rendercv/themes/sb2nov/PublicationEntry.j2.tex b/rendercv/renderer/themes/sb2nov/PublicationEntry.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/PublicationEntry.j2.tex rename to rendercv/renderer/themes/sb2nov/PublicationEntry.j2.tex diff --git a/rendercv/themes/sb2nov/SectionBeginning.j2.tex b/rendercv/renderer/themes/sb2nov/SectionBeginning.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/SectionBeginning.j2.tex rename to rendercv/renderer/themes/sb2nov/SectionBeginning.j2.tex diff --git a/rendercv/themes/sb2nov/SectionEnding.j2.tex b/rendercv/renderer/themes/sb2nov/SectionEnding.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/SectionEnding.j2.tex rename to rendercv/renderer/themes/sb2nov/SectionEnding.j2.tex diff --git a/rendercv/themes/sb2nov/TextEntry.j2.tex b/rendercv/renderer/themes/sb2nov/TextEntry.j2.tex similarity index 100% rename from rendercv/themes/sb2nov/TextEntry.j2.tex rename to rendercv/renderer/themes/sb2nov/TextEntry.j2.tex diff --git a/rendercv/themes/sb2nov/__init__.py b/rendercv/renderer/themes/sb2nov/__init__.py similarity index 100% rename from rendercv/themes/sb2nov/__init__.py rename to rendercv/renderer/themes/sb2nov/__init__.py diff --git a/tests/conftest.py b/tests/conftest.py index 2458c0a4..8f5ffcf5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,8 +16,8 @@ import pypdf import pytest import rendercv.renderer as r -import rendercv.renderer.templating as rt -from rendercv import reader as dm +import rendercv.renderer.templater as rt +from rendercv import data as dm # RenderCV is being tested by comparing the output to reference files. Therefore, # reference files should be updated when RenderCV is updated in a way that changes diff --git a/tests/test_cli.py b/tests/test_cli.py index 3039c117..d4cf3a1d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -12,7 +12,7 @@ import typer.testing import rendercv.cli as cli import rendercv.cli.printer as printer import rendercv.cli.utilities as util -import rendercv.reader as dm +import rendercv.data as dm from rendercv import __version__ @@ -219,6 +219,10 @@ def test_copy_templates(tmp_path, folder_name): ) assert copied_path.exists() + # make sure only j2.tex or j2.md files are copied: + for file in copied_path.iterdir(): + assert file.suffix in [".tex", ".md"] + def test_copy_templates_with_new_folder_name(tmp_path): copied_path = cli.copy_templates( diff --git a/tests/test_reader.py b/tests/test_reader.py index 69351ff3..0f638622 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -10,7 +10,7 @@ import pytest import ruamel.yaml import time_machine -from rendercv import reader as dm +from rendercv import data as dm from .conftest import update_testdata diff --git a/tests/test_renderer.py b/tests/test_renderer.py index 0df1cd10..ce7f4859 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -8,7 +8,7 @@ import jinja2 import pytest import time_machine -from rendercv import reader as dm +from rendercv import data as dm from rendercv import renderer as r folder_name_dictionary = {