diff --git a/CHANGES.rst b/CHANGES.rst index 65a7f666..a8d91e68 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,7 +6,10 @@ Changelog Minor changes: -- ... +- Calendar.from_ical no longer throws long errors + Ref: #473 + Fixes: #472 + [jacadzaca] Breaking changes: diff --git a/src/icalendar/cal.py b/src/icalendar/cal.py index e2e364ca..cf7dc9cd 100644 --- a/src/icalendar/cal.py +++ b/src/icalendar/cal.py @@ -390,14 +390,22 @@ def from_ical(cls, st, multiple=False): if multiple: return comps if len(comps) > 1: - raise ValueError(f'Found multiple components where ' - f'only one is allowed: {st!r}') + raise ValueError(cls._format_error( + 'Found multiple components where only one is allowed', st)) if len(comps) < 1: - raise ValueError(f'Found no components where ' - f'exactly one is required: ' - f'{st!r}') + raise ValueError(cls._format_error( + 'Found no components where exactly one is required', st)) return comps[0] + def _format_error(error_description, bad_input, elipsis='[...]'): + # there's three character more in the error, ie. ' ' x2 and a ':' + max_error_length = 100 - 3 + if len(error_description) + len(bad_input) + len(elipsis) > max_error_length: + truncate_to = max_error_length - len(error_description) - len(elipsis) + return f'{error_description}: {bad_input[:truncate_to]} {elipsis}' + else: + return f'{error_description}: {bad_input}' + def content_line(self, name, value, sorted=True): """Returns property as content line. """ diff --git a/src/icalendar/tests/calendars/big_bad_calendar.ics b/src/icalendar/tests/calendars/big_bad_calendar.ics new file mode 100644 index 00000000..88fbc6f8 --- /dev/null +++ b/src/icalendar/tests/calendars/big_bad_calendar.ics @@ -0,0 +1,41 @@ +BEGIN:VCALENDAR +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT +BEGIN:VEVENT +END:VEVENT diff --git a/src/icalendar/tests/calendars/small_bad_calendar.ics b/src/icalendar/tests/calendars/small_bad_calendar.ics new file mode 100644 index 00000000..94228f1b --- /dev/null +++ b/src/icalendar/tests/calendars/small_bad_calendar.ics @@ -0,0 +1,3 @@ +BEGIN:VCALENDAR +BEGIN:VEVENT +END:VEVENT diff --git a/src/icalendar/tests/test_components_break_on_bad_ics.py b/src/icalendar/tests/test_components_break_on_bad_ics.py index 27ddc95e..3bf7d1d5 100644 --- a/src/icalendar/tests/test_components_break_on_bad_ics.py +++ b/src/icalendar/tests/test_components_break_on_bad_ics.py @@ -26,3 +26,14 @@ def test_rdate_dosent_become_none_on_invalid_input_issue_464(events): assert events.issue_464_invalid_rdate.is_broken assert ('RDATE', 'Expected period format, got: 199709T180000Z/PT5H30M') in events.issue_464_invalid_rdate.errors assert not b'RDATE:None' in events.issue_464_invalid_rdate.to_ical() + +@pytest.mark.parametrize('calendar_name', [ + 'big_bad_calendar', + 'small_bad_calendar', + 'multiple_calendar_components', +]) +def test_error_message_doesnt_get_too_big(calendars, calendar_name): + with pytest.raises(ValueError) as exception: + calendars[calendar_name] + assert len(str(exception).split(': ')[1]) <= 100 +