From 35b15bec87b732e909186b59415abd45c7a009ef Mon Sep 17 00:00:00 2001 From: Nicco Kunzmann Date: Fri, 11 Oct 2024 13:03:19 +0100 Subject: [PATCH] py38 compatibility, ruff adjustment, better error messages tested --- pyproject.toml | 1 + src/icalendar/cal.py | 15 +++++++-------- .../tests/test_issue_662_component_properties.py | 12 ++++++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9730e465..c2cae8b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -157,6 +157,7 @@ ignore = [ "PERF401", # Use a list comprehension to create a transformed list "ARG002", # Unused method argument: ... "ARG001", # Unused function argument: ... + "UP007", # Optional -> X | None remove when migrated to py39+ ] extend-safe-fixes = [ "PT006", # Wrong type passed to first argument of @pytest.mark.parametrize; expected {expected_string} diff --git a/src/icalendar/cal.py b/src/icalendar/cal.py index 281c6988..84214c2c 100644 --- a/src/icalendar/cal.py +++ b/src/icalendar/cal.py @@ -7,7 +7,7 @@ import os from datetime import date, datetime, timedelta -from typing import List, Tuple +from typing import List, Optional, Tuple import dateutil.rrule import dateutil.tz @@ -511,7 +511,6 @@ def p_get(self : Component): if not isinstance(value, value_type): raise InvalidCalendar(f"{prop} must be either a date or a datetime, not {value}.") return value - def p_set(self:Component, value) -> None: if value is None: @@ -524,13 +523,13 @@ def p_set(self:Component, value) -> None: for other_prop in self.exclusive: if other_prop != prop: self.pop(other_prop, None) - p_set.__annotations__["value"] = p_get.__annotations__["return"] = type_def | None + p_set.__annotations__["value"] = p_get.__annotations__["return"] = Optional[type_def] def p_del(self:Component): self.pop(prop) - + p_doc = f"""The {prop} property. - + {doc} Accepted values: {', '.join(t.__name__ for t in value_type)}. @@ -595,7 +594,7 @@ def _get_start_end_duration(self): return start, end, duration @property - def DURATION(self) -> timedelta | None: # noqa: N802 + def DURATION(self) -> Optional[timedelta]: # noqa: N802 """The DURATION of the component. The "DTSTART" property for a "VEVENT" specifies the inclusive start of the event. @@ -617,7 +616,7 @@ def DURATION(self) -> timedelta | None: # noqa: N802 return None @DURATION.setter - def DURATION(self, value: timedelta | None): # noqa: N802 + def DURATION(self, value: Optional[timedelta]): # noqa: N802 if value is None: self.pop("duration", None) return @@ -663,7 +662,7 @@ def start(self) -> date | datetime: return start @start.setter - def start(self, start: date | datetime| None): + def start(self, start: Optional[date | datetime]): """Set the start.""" self.DTSTART = start diff --git a/src/icalendar/tests/test_issue_662_component_properties.py b/src/icalendar/tests/test_issue_662_component_properties.py index 4df60006..fb71d601 100644 --- a/src/icalendar/tests/test_issue_662_component_properties.py +++ b/src/icalendar/tests/test_issue_662_component_properties.py @@ -2,7 +2,11 @@ from datetime import date, datetime, timedelta import pytest -from zoneinfo import ZoneInfo + +try: + from zoneinfo import ZoneInfo +except ImportError: + from backports.zoneinfo import ZoneInfo # type: ignore from icalendar import ( Event, @@ -201,9 +205,9 @@ def test_start_and_duration(event, dtstart, duration): @pytest.mark.parametrize( ("invalid_event", "message"), [ - (invalid_event_end_1, "DTSTART and DTEND must have the same type."), - (invalid_event_end_2, "DTSTART and DTEND must have the same type."), - (invalid_event_end_3, "DTEND and DURATION cannot be there at the same time."), + (invalid_event_end_1, "DTSTART and DTEND must be of the same type, either date or datetime."), + (invalid_event_end_2, "DTSTART and DTEND must be of the same type, either date or datetime."), + (invalid_event_end_3, "Only one of DTEND and DURATION may be in a VEVENT, not both."), (invalid_event_end_4, "When DTSTART is a date, DURATION must be of days or weeks."), ] )