diff --git a/rendercv/data_model.py b/rendercv/data_model.py index 1f20440..386c05c 100644 --- a/rendercv/data_model.py +++ b/rendercv/data_model.py @@ -439,7 +439,7 @@ class Event(BaseModel): ), examples=["2020-09-24", "present"], ) - date: Optional[str] = Field( + date: Optional[str | PastDate] = Field( default=None, title="Date", description=( @@ -450,7 +450,7 @@ class Event(BaseModel): ), examples=["2020-09-24"], ) - highlights: list[SpellCheckedString] = Field( + highlights: Optional[list[SpellCheckedString]] = Field( default=[], title="Highlights", description=( @@ -515,6 +515,17 @@ class Event(BaseModel): ) model.end_date = "present" + if model.start_date is not None and model.end_date is not None: + if model.end_date == "present": + end_date = Date.today() + else: + end_date = model.end_date + + if model.start_date > end_date: + raise ValueError( + '"start_date" is after "end_date". Please check the dates!' + ) + return model @computed_field @@ -578,8 +589,8 @@ class Event(BaseModel): @cached_property def highlight_strings(self) -> list[SpellCheckedString]: highlight_strings = [] - - highlight_strings.extend(self.highlights) + if self.highlights is not None: + highlight_strings.extend(self.highlights) return highlight_strings @@ -614,7 +625,7 @@ class Event(BaseModel): try: # If this runs, it means the date is an ISO format string, and it can be # parsed - month_and_year = format_date(Date.fromisoformat(self.date)) + month_and_year = format_date(self.date) except: month_and_year = self.date else: @@ -709,7 +720,8 @@ class EducationEntry(Event): gpaString += f" ([Transcript]({self.transcript_url}))" highlight_strings.append(gpaString) - highlight_strings.extend(self.highlights) + if self.highlights is not None: + highlight_strings.extend(self.highlights) return highlight_strings @@ -784,7 +796,9 @@ class Connection(BaseModel): the $\LaTeX$ templating easier. """ - name: Literal["LinkedIn", "GitHub", "Instagram", "phone", "email", "website", "location"] + name: Literal[ + "LinkedIn", "GitHub", "Instagram", "phone", "email", "website", "location" + ] value: str @computed_field diff --git a/tests/test_rendercv.py b/tests/test_rendercv.py index 9ef4dbd..4dd901d 100644 --- a/tests/test_rendercv.py +++ b/tests/test_rendercv.py @@ -15,50 +15,58 @@ class TestRendercv(unittest.TestCase): ] for sentence in sentences: - data_model.check_spelling(sentence) + with self.subTest(sentence=sentence): + data_model.check_spelling(sentence) def test_compute_time_span_string(self): start_date = Date(year=2020, month=1, day=1) end_date = Date(year=2021, month=1, day=1) expected = "1 year 1 month" result = data_model.compute_time_span_string(start_date, end_date) - self.assertEqual(result, expected) + with self.subTest(expected=expected): + self.assertEqual(result, expected) start_date = Date(year=2020, month=1, day=1) end_date = Date(year=2020, month=2, day=1) expected = "1 month" result = data_model.compute_time_span_string(start_date, end_date) - self.assertEqual(result, expected) + with self.subTest(expected=expected): + self.assertEqual(result, expected) start_date = Date(year=2020, month=1, day=1) end_date = Date(year=2023, month=3, day=2) expected = "3 years 2 months" result = data_model.compute_time_span_string(start_date, end_date) - self.assertEqual(result, expected) + with self.subTest(expected=expected): + self.assertEqual(result, expected) start_date = Date(year=2020, month=1, day=1) end_date = Date(year=1982, month=1, day=1) - with self.assertRaises(ValueError): - data_model.compute_time_span_string(start_date, end_date) + with self.subTest(msg="start_date > end_date"): + with self.assertRaises(ValueError): + data_model.compute_time_span_string(start_date, end_date) def test_format_date(self): date = Date(year=2020, month=1, day=1) expected = "Jan. 2020" result = data_model.format_date(date) - self.assertEqual(result, expected) + with self.subTest(expected=expected): + self.assertEqual(result, expected) date = Date(year=1983, month=12, day=1) expected = "Dec. 1983" result = data_model.format_date(date) - self.assertEqual(result, expected) + with self.subTest(expected=expected): + self.assertEqual(result, expected) date = Date(year=2045, month=6, day=1) expected = "June 2045" result = data_model.format_date(date) - self.assertEqual(result, expected) + with self.subTest(expected=expected): + self.assertEqual(result, expected) - def test_data_Event_check_dates(self): - # Inputs with correct dates: + def test_data_event_check_dates(self): + # Inputs with valid dates: inputs = [ { "start_date": Date(year=2020, month=1, day=1), @@ -76,24 +84,25 @@ class TestRendercv(unittest.TestCase): ] for input in inputs: - with self.subTest(msg="start_date < end_date"): + with self.subTest(msg="valid dates"): data_model.Event(**input) - # Inputs with incorrect dates: - inputs = [ - { - "start_date": Date(year=2020, month=1, day=1), - "end_date": Date(year=2019, month=1, day=1), - }, - { - "start_date": Date(year=2020, month=1, day=1), - "end_date": Date(year=2400, month=1, day=1), - }, - ] - for input in inputs: - with self.subTest(msg="start_date > end_date"): - with self.assertRaises(ValidationError): - data_model.Event(**input) + # Inputs with invalid dates: + input = { + "start_date": Date(year=2020, month=1, day=1), + "end_date": Date(year=2019, month=1, day=1), + } + with self.subTest(msg="start_date > end_date"): + with self.assertRaises(ValidationError): + data_model.Event(**input) + + input = { + "start_date": Date(year=2020, month=1, day=1), + "end_date": Date(year=2900, month=1, day=1), + } + with self.subTest(msg="end_date > present"): + with self.assertRaises(ValidationError): + data_model.Event(**input) # Other inputs: input = { @@ -140,6 +149,156 @@ class TestRendercv(unittest.TestCase): self.assertEqual(event.end_date, None) self.assertEqual(event.date, input["date"]) + def test_data_event_date_and_location_strings_with_timespan(self): + input = { + "start_date": Date(year=2020, month=1, day=1), + "end_date": Date(year=2021, month=1, day=16), + "location": "My Location", + } + expected = [ + "My Location", + "Jan. 2020 to Jan. 2021", + "1 year 1 month", + ] + event = data_model.Event(**input) + result = event.date_and_location_strings_with_timespan + with self.subTest(expected=expected): + self.assertEqual(result, expected) + + input = { + "date": "My Birthday", + "location": "My Location", + } + expected = [ + "My Location", + "My Birthday", + ] + event = data_model.Event(**input) + result = event.date_and_location_strings_with_timespan + with self.subTest(expected=expected): + self.assertEqual(result, expected) + + def test_data_event_date_and_location_strings_without_timespan(self): + input = { + "start_date": Date(year=2020, month=1, day=1), + "end_date": Date(year=2021, month=1, day=16), + "location": "My Location", + } + expected = [ + "My Location", + "Jan. 2020 to Jan. 2021", + ] + event = data_model.Event(**input) + result = event.date_and_location_strings_without_timespan + with self.subTest(expected=expected): + self.assertEqual(result, expected) + + input = { + "date": "My Birthday", + "location": "My Location", + } + expected = [ + "My Location", + "My Birthday", + ] + event = data_model.Event(**input) + result = event.date_and_location_strings_without_timespan + with self.subTest(expected=expected): + self.assertEqual(result, expected) + + def test_data_event_highlight_strings(self): + input = { + "highlights": [ + "My Highlight 1", + "My Highlight 2", + ], + } + expected = [ + "My Highlight 1", + "My Highlight 2", + ] + event = data_model.Event(**input) + result = event.highlight_strings + with self.subTest(expected=expected): + self.assertEqual(result, expected) + + input = {} + expected = [] + event = data_model.Event(**input) + result = event.highlight_strings + with self.subTest(msg="no highlights"): + self.assertEqual(result, expected) + + def test_data_event_markdown_url(self): + # Github link: + input = {"url": "https://github.com/sinaatalay"} + expected = "[view on GitHub](https://github.com/sinaatalay)" + event = data_model.Event(**input) + result = event.markdown_url + with self.subTest(msg="Github link"): + self.assertEqual(result, expected) + + # LinkedIn link: + input = {"url": "https://www.linkedin.com/"} + expected = "[view on LinkedIn](https://www.linkedin.com/)" + event = data_model.Event(**input) + result = event.markdown_url + with self.subTest(msg="LinkedIn link"): + self.assertEqual(result, expected) + + # Instagram link: + input = {"url": "https://www.instagram.com/"} + expected = "[view on Instagram](https://www.instagram.com/)" + event = data_model.Event(**input) + result = event.markdown_url + with self.subTest(msg="Instagram link"): + self.assertEqual(result, expected) + + # Youtube link: + input = {"url": "https://www.youtube.com/"} + expected = "[view on YouTube](https://www.youtube.com/)" + event = data_model.Event(**input) + result = event.markdown_url + with self.subTest(msg="Youtube link"): + self.assertEqual(result, expected) + + # Other links: + input = {"url": "https://www.google.com/"} + expected = "[view on my website](https://www.google.com/)" + event = data_model.Event(**input) + result = event.markdown_url + with self.subTest(msg="Other links"): + self.assertEqual(result, expected) + + def test_data_event_month_and_year(self): + input = { + "start_date": Date(year=2020, month=1, day=1), + "end_date": Date(year=2021, month=1, day=16), + } + expected = None + event = data_model.Event(**input) + result = event.month_and_year + with self.subTest(msg="start_date and end_date are provided"): + self.assertEqual(result, expected) + + input = { + "date": "My Birthday", + } + expected = "My Birthday" + event = data_model.Event(**input) + result = event.month_and_year + with self.subTest(msg="custom date is provided"): + self.assertEqual(result, expected) + + input = { + "date": Date(year=2020, month=1, day=1), + } + expected = "Jan. 2020" + event = data_model.Event(**input) + result = event.month_and_year + with self.subTest(msg="date is provided"): + self.assertEqual(result, expected) + if __name__ == "__main__": unittest.main()