diff --git a/rendercv/cli/utilities.py b/rendercv/cli/utilities.py index b8aeeeae..cc12471a 100644 --- a/rendercv/cli/utilities.py +++ b/rendercv/cli/utilities.py @@ -307,6 +307,38 @@ def update_render_command_settings_of_the_input_file( return input_file_as_a_dict +def make_given_keywords_bold_in_a_dictionary( + dictionary: dict, keywords: list[str] +) -> dict: + """Iterate over the dictionary recursively and make the given keywords bold. + + Args: + dictionary: The dictionary to make the keywords bold. + keywords: The keywords to make bold. + + Returns: + The dictionary with the given keywords bold. + """ + new_dictionary = dictionary.copy() + for keyword in keywords: + for key, value in dictionary.items(): + if isinstance(value, str): + new_dictionary[key] = value.replace(keyword, f"**{keyword}**") + elif isinstance(value, dict): + new_dictionary[key] = make_given_keywords_bold_in_a_dictionary( + value, keywords + ) + elif isinstance(value, list): + for i, item in enumerate(value): + if isinstance(item, str): + new_dictionary[key][i] = item.replace(keyword, f"**{keyword}**") + elif isinstance(item, dict): + new_dictionary[key][i] = ( + make_given_keywords_bold_in_a_dictionary(item, keywords) + ) + return dictionary + + def run_rendercv_with_printer( input_file_as_a_dict: dict, working_directory: pathlib.Path, @@ -350,6 +382,17 @@ def run_rendercv_with_printer( context={"input_file_directory": input_file_path.parent}, ) + # If the `bold_keywords` field is provided in the `rendercv_settings`, make the + # given keywords bold in the `cv.sections` field: + if data_model.rendercv_settings and data_model.rendercv_settings.bold_keywords: + cv_field_as_dictionary = data_model.cv.model_dump(by_alias=True) + new_sections_field = make_given_keywords_bold_in_a_dictionary( + cv_field_as_dictionary["sections"], + data_model.rendercv_settings.bold_keywords, + ) + cv_field_as_dictionary["sections"] = new_sections_field + data_model.cv = data.models.CurriculumVitae(**cv_field_as_dictionary) + # Change the current working directory to the input file's directory (because # the template overrides are looked up in the current working directory). The # output files will be in the original working directory. It should be done diff --git a/rendercv/data/models/computers.py b/rendercv/data/models/computers.py index 8efd524e..6bbcd3e5 100644 --- a/rendercv/data/models/computers.py +++ b/rendercv/data/models/computers.py @@ -90,7 +90,7 @@ def format_date(date: Date, date_style: Optional[str] = None) -> str: def replace_placeholders(value: str) -> str: """Replaces the placeholders in a string with the corresponding values.""" - name = curriculum_vitae["name"] # Curriculum Vitae owner's name + name = curriculum_vitae.get("name", "None") full_month_names = LOCALE_CATALOG["full_names_of_months"] short_month_names = LOCALE_CATALOG["abbreviations_for_months"] diff --git a/rendercv/data/models/rendercv_settings.py b/rendercv/data/models/rendercv_settings.py index 3d8a7792..7a737d1c 100644 --- a/rendercv/data/models/rendercv_settings.py +++ b/rendercv/data/models/rendercv_settings.py @@ -207,3 +207,11 @@ class RenderCVSettings(RenderCVBaseModelWithoutExtraKeys): " the input file." ), ) + bold_keywords: list[str] = pydantic.Field( + default=[], + title="Bold Keywords", + description=( + "The keywords that will be bold in the output. The default value is an" + " empty list." + ), + ) diff --git a/tests/test_cli.py b/tests/test_cli.py index 63290d1e..09bdd616 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1025,3 +1025,35 @@ def test_read_and_construct_the_input( assert (field in input_dict) == locals()[ field ], f"{field} is in dict: {field in input_dict}, expected: {locals()[field]}" + + +def test_make_given_keywords_bold_in_a_dictionary(): + dictionary = { + "name": "John Doe", + "email": ["John Doe"], + "test": { + "test": "John Doe", + }, + } + keywords = ["John"] + bolded_dictionary = utilities.make_given_keywords_bold_in_a_dictionary( + dictionary, keywords + ) + assert bolded_dictionary["name"] == "**John** Doe" + assert bolded_dictionary["email"] == ["**John** Doe"] + assert bolded_dictionary["test"]["test"] == "**John** Doe" + + +def test_bold_keywords(input_file_path, tmp_path): + input_file_path.write_text( + "cv:\n sections:\n education:\n - test\nrendercv_settings:\n " + " bold_keywords:\n - test" + ) + run_render_command( + input_file_path, + tmp_path, + ) + latex_file_path = tmp_path / "rendercv_output" / "None_CV.tex" + latex_content = latex_file_path.read_text() + + assert "\\textbf{test}" in latex_content diff --git a/tests/test_data.py b/tests/test_data.py index cfe17ce3..7e1373a2 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -564,6 +564,24 @@ def test_sections( assert len(section.entries) == 2 +def test_section_with_different_entry_types( + education_entry, + experience_entry, +): + input = { + "name": "John Doe", + "sections": { + "arbitrary_title": [ + education_entry, + experience_entry, + ], + }, + } + + with pytest.raises(pydantic.ValidationError): + data.CurriculumVitae(**input) + + def test_sections_with_invalid_entries(): input = {"name": "John Doe", "sections": {}} input["sections"]["section_title"] = [