mirror of
https://github.com/rendercv/rendercv.git
synced 2026-10-24 13:18:50 -04:00
update subpackage names and packaging structure
This commit is contained in:
1 parent
53f5e28821
commit
120b63cc08
85 files changed
+183
-170
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import pathlib
|
||||
|
||||
import rendercv.reader as dm
|
||||
import rendercv.data as dm
|
||||
|
||||
repository_root = pathlib.Path(__file__).parent.parent
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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.
@@ -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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
-2
@@ -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
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in new issue
Block a user