mirror of https://github.com/eyhc1/rendercv.git
data_models: add a new function `set_or_update_a_value`
This commit is contained in:
parent
6864bb8508
commit
70d9589d9a
|
@ -25,6 +25,7 @@ import json
|
|||
import re
|
||||
import ssl
|
||||
import pathlib
|
||||
import warnings
|
||||
|
||||
import pydantic
|
||||
import pydantic_extra_types.phone_numbers as pydantic_phone_numbers
|
||||
|
@ -35,6 +36,9 @@ from .themes.moderncv import ModerncvThemeOptions
|
|||
from .themes.sb2nov import Sb2novThemeOptions
|
||||
from .themes.engineeringresumes import EngineeringresumesThemeOptions
|
||||
|
||||
# disable Pydantic warnings:
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
# Create a custom type called RenderCVDate that accepts only strings in YYYY-MM-DD or
|
||||
# YYYY-MM format:
|
||||
# This type is used to validate the date fields in the data.
|
||||
|
@ -1126,6 +1130,69 @@ class RenderCVDataModel(RenderCVBaseModel):
|
|||
return theme_data_model
|
||||
|
||||
|
||||
def set_or_update_a_value(
|
||||
data_model: pydantic.BaseModel | dict | list,
|
||||
key: str,
|
||||
value: Any,
|
||||
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 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.model_validate(data_model.model_dump(by_alias=True))
|
||||
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: pathlib.Path,
|
||||
) -> RenderCVDataModel:
|
||||
|
|
|
@ -2,6 +2,7 @@ from datetime import date as Date
|
|||
import json
|
||||
import pathlib
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
||||
import pydantic
|
||||
|
@ -59,6 +60,52 @@ def test_format_date(date, expected_date_string):
|
|||
assert dm.format_date(date) == expected_date_string
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"key, value",
|
||||
[
|
||||
("cv.phone", "+905555555555"),
|
||||
("cv.email", "test@example.com"),
|
||||
("cv.sections.education.0.degree", "PhD"),
|
||||
("design.page_size", "a4paper"),
|
||||
],
|
||||
)
|
||||
def test_set_or_update_a_value(rendercv_data_model, key, value):
|
||||
dm.set_or_update_a_value(rendercv_data_model, key, value)
|
||||
|
||||
# replace with regex pattern:
|
||||
key = re.sub(r"sections\.([^\.]*?)\.(\d+)", 'sections_input["\\1"][\\2]', key)
|
||||
|
||||
assert eval(f"rendercv_data_model.{key}") == value
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"key, value",
|
||||
[
|
||||
("cv.phones", "+905555555555"),
|
||||
("cv.emssdsail", ""),
|
||||
("cv.sections.education.99.degree", "PhD"),
|
||||
("dessssign.page_size", "a4paper"),
|
||||
],
|
||||
)
|
||||
def test_set_or_update_a_value_invalid_keys(rendercv_data_model, key, value):
|
||||
with pytest.raises((ValueError, KeyError, IndexError, AttributeError)):
|
||||
dm.set_or_update_a_value(rendercv_data_model, key, value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"key, value",
|
||||
[
|
||||
("cv.phone", "+9999995555555555"),
|
||||
("cv.email", "notanemail***"),
|
||||
("cv.sections.education.0.highlights", "this is not a list"),
|
||||
("design.page_size", "invalid_page_size"),
|
||||
],
|
||||
)
|
||||
def test_set_or_update_a_value_invalid_values(rendercv_data_model, key, value):
|
||||
with pytest.raises(pydantic.ValidationError):
|
||||
dm.set_or_update_a_value(rendercv_data_model, key, value)
|
||||
|
||||
|
||||
def test_read_input_file(input_file_path):
|
||||
# Update the auxiliary files if update_testdata is True
|
||||
if update_testdata:
|
||||
|
|
Loading…
Reference in New Issue