diff --git a/rendercv/data/models/entry_types.py b/rendercv/data/models/entry_types.py index c3ea3108..f56f3b67 100644 --- a/rendercv/data/models/entry_types.py +++ b/rendercv/data/models/entry_types.py @@ -579,6 +579,11 @@ class EducationEntryBase(RenderCVBaseModelWithExtraKeys): description="The type of the degree, such as BS, BA, PhD, MS.", examples=["BS", "BA", "PhD", "MS"], ) + grade: str | None = pydantic.Field( + default=None, + title="Grade", + examples=["GPA: 3.00/4.00"], + ) class EducationEntry(EntryBase, EducationEntryBase, EntryType): diff --git a/rendercv/themes/components/grade.j2.typ b/rendercv/themes/components/grade.j2.typ new file mode 100644 index 00000000..57418ca4 --- /dev/null +++ b/rendercv/themes/components/grade.j2.typ @@ -0,0 +1 @@ +<> diff --git a/schema.json b/schema.json index 830af77f..22295ac4 100644 --- a/schema.json +++ b/schema.json @@ -372,6 +372,21 @@ } ] }, + "grade": { + "default": null, + "examples": [ + "GPA: 3.00/4.00" + ], + "title": "Grade", + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, "date": { "default": null, "description": "The date can be written in the formats YYYY-MM-DD, YYYY-MM, or YYYY, or as an arbitrary string such as \"Fall 2023.\"", diff --git a/tests/conftest.py b/tests/conftest.py index b62cd196..d6f8c335 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -290,6 +290,7 @@ def return_a_value_for_a_field_type( def create_combinations_of_a_model( model: type[data.Entry], + ignore_fields: set[str] | None = None, ) -> list[data.Entry]: """Look at the required fields and optional fields of a model and create all possible combinations of them. @@ -305,7 +306,11 @@ def create_combinations_of_a_model( required_fields = {} optional_fields = {} + ignore_fields = ignore_fields or set() + for field, field_type in fields.items(): + if field in ignore_fields: + continue value = return_a_value_for_a_field_type(field, field_type) if type(None) in typing.get_args(field_type): # check if a field is optional optional_fields[field] = value @@ -368,7 +373,10 @@ def rendercv_filled_curriculum_vitae_data_model( data.PublicationEntry ), "Experience Entries": create_combinations_of_a_model(data.ExperienceEntry), - "Education Entries": create_combinations_of_a_model(data.EducationEntry), + "Education Entries": create_combinations_of_a_model( + data.EducationEntry, + ignore_fields={"grade"}, + ), "Normal Entries": create_combinations_of_a_model(data.NormalEntry), "One Line Entries": create_combinations_of_a_model(data.OneLineEntry), "Numbered Entries": create_combinations_of_a_model(data.NumberedEntry), diff --git a/tests/test_data.py b/tests/test_data.py index af70eb20..a5f9ec51 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -349,6 +349,12 @@ def test_invalid_publication_dates(publication_entry, date): data.PublicationEntry(**publication_entry) +def test_education_entry_grade_field(education_entry): + education_entry["grade"] = "GPA: 3.00/4.00" + entry = data.EducationEntry(**education_entry) + assert entry.grade == "GPA: 3.00/4.00" + + @pytest.mark.parametrize( ("start_date", "end_date", "date"), [ diff --git a/tests/test_renderer.py b/tests/test_renderer.py index 9dd01130..d44a8c40 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -710,6 +710,11 @@ def test_are_all_the_theme_files_the_same(theme_name): {}, '#link("https://myurl.com")[#strong[#emph[My]]]', ), + ( + "**GRADE**", + {"GRADE": "GPA: 3.00/4.00"}, + '#strong[GPA: 3.00/4.00]' + ), ], ) def test_input_template_to_typst(