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 re
|
||||||
import ssl
|
import ssl
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import warnings
|
||||||
|
|
||||||
import pydantic
|
import pydantic
|
||||||
import pydantic_extra_types.phone_numbers as pydantic_phone_numbers
|
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.sb2nov import Sb2novThemeOptions
|
||||||
from .themes.engineeringresumes import EngineeringresumesThemeOptions
|
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
|
# Create a custom type called RenderCVDate that accepts only strings in YYYY-MM-DD or
|
||||||
# YYYY-MM format:
|
# YYYY-MM format:
|
||||||
# This type is used to validate the date fields in the data.
|
# This type is used to validate the date fields in the data.
|
||||||
|
@ -1126,6 +1130,69 @@ class RenderCVDataModel(RenderCVBaseModel):
|
||||||
return theme_data_model
|
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(
|
def read_input_file(
|
||||||
file_path: pathlib.Path,
|
file_path: pathlib.Path,
|
||||||
) -> RenderCVDataModel:
|
) -> RenderCVDataModel:
|
||||||
|
|
|
@ -2,6 +2,7 @@ from datetime import date as Date
|
||||||
import json
|
import json
|
||||||
import pathlib
|
import pathlib
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import pydantic
|
import pydantic
|
||||||
|
@ -59,6 +60,52 @@ def test_format_date(date, expected_date_string):
|
||||||
assert dm.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):
|
def test_read_input_file(input_file_path):
|
||||||
# Update the auxiliary files if update_testdata is True
|
# Update the auxiliary files if update_testdata is True
|
||||||
if update_testdata:
|
if update_testdata:
|
||||||
|
|
Loading…
Reference in New Issue