update subpackage names and packaging structure

This commit is contained in:
Sina Atalay committed 2024-07-05 00:29:25 +03:00
1 parent 53f5e28821
commit 120b63cc08
85 files changed
+183 -170

No files matched your search

+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -2,7 +2,7 @@
import pathlib
import rendercv.reader as dm
import rendercv.data as dm
repository_root = pathlib.Path(__file__).parent.parent
+4 -3
View File
@@ -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):
+6 -11
View File
@@ -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
+75 -1
View File
@@ -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
@@ -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",
]
@@ -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
@@ -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",
]
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+78
View File
@@ -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
File renamed without changes.
+2 -2
View File
@@ -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(
@@ -12,7 +12,7 @@ from typing import Any, Optional
import jinja2
from .. import reader as dm
from .. import data as dm
class TemplatedFile:
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2 -2
View File
@@ -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
+5 -1
View File
@@ -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(
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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 = {