From 33453807ddc36f28d00c1f0641b76c0d8695adb3 Mon Sep 17 00:00:00 2001 From: 5ila5 <5ila5@users.noreply.github.com> Date: Sat, 18 Mar 2023 14:29:00 +0100 Subject: [PATCH 1/2] updated static source to support weekdays --- .../source/static.py | 62 ++++++++++++++++++- doc/source/static.md | 30 +++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py index 51d88aa5..0e312664 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py @@ -1,6 +1,9 @@ from dateutil.rrule import rrule +from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU + import datetime from dateutil import parser +from typing import Dict from waste_collection_schedule import Collection # type: ignore[attr-defined] @@ -26,10 +29,32 @@ TEST_CASES = { "excludes": {"2022-01-01"}, "dates": {"2022-01-02"}, }, + "Recurrence with Weekday and count": { + "type": "Recurrence with Weekday", + "frequency": "MONTHLY", + "start": "2022-01-01", + "until": "2022-12-31", + "weekdays": {"MO": 1, 1: 2}, + }, + "Recurrence with Weekday without count": { + "type": "Recurrence with Weekday without count", + "frequency": "MONTHLY", + "start": "2022-01-01", + "until": "2022-12-31", + "weekdays": {"MO",5}, + }, + "Recurrence with Weekday with and without count": { + "type": "Recurrence with Weekday with and without count", + "frequency": "MONTHLY", + "start": "2022-01-01", + "until": "2022-12-31", + "weekdays": {"SA":-1,"MO":None,"TU":"Every"}, + }, } FREQNAMES = ["YEARLY", "MONTHLY", "WEEKLY", "DAILY"] - +WEEKDAYNAME = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"] +WEEKDAYS = [MO, TU, WE, TH, FR, SA, SU] class Source: def __init__( @@ -41,7 +66,40 @@ class Source: start: datetime.date = None, until: datetime.date = None, excludes: list[str] = None, + weekdays: list[str|int] | dict[str|int,int|str|None] = None, ): + self._weekdays = None + if (weekdays is not None): + self._weekdays = [] + if (isinstance(weekdays, dict)): + for weekday, count in weekdays.items(): + print(weekday, count) + weekday_index = None + if (isinstance(weekday, int)): + weekday_index = weekday + elif (isinstance(weekday, str)): + weekday_index = WEEKDAYNAME.index(weekday) + + if (weekday_index>6 or weekday_index<0): + continue + + if (isinstance(count, str)): + count = int(count) if count.isdigit() else "every" + + if (count is None or count == "every" ): + [self._weekdays.append(WEEKDAYS[weekday_index](x)) for x in range(1,7)] + continue + + self._weekdays.append(WEEKDAYS[weekday_index](count)) + + else: + for weekday in weekdays or []: + if (isinstance(weekday, int)): + self._weekdays.append(weekday) + if (isinstance(weekday, str)): + self._weekdays.append(WEEKDAYNAME.index(weekday)) + if self._weekdays == []: self._weekdays = None + self._type = type self._dates = [parser.isoparse(d).date() for d in dates or []] @@ -54,12 +112,14 @@ class Source: def fetch(self): dates = [] + print(self._weekdays) if self._recurrence is not None: ruledates = rrule( freq=self._recurrence, interval=self._interval, dtstart=self._start, until=self._until, + byweekday=self._weekdays, ) for ruleentry in ruledates: diff --git a/doc/source/static.md b/doc/source/static.md index 557f4bb2..94b5b774 100644 --- a/doc/source/static.md +++ b/doc/source/static.md @@ -58,6 +58,11 @@ Required if *FREQUENCY* is set. A list of dates in format "YYYY-MM-DD" which should be excluded from the recurrence. +**WEEKDAYS** +*(list | dictionary) (optional)* + +Can either be used to define the week day for weekly frequency (can also be done by setting the start date and leaving this empty). Or to specify weekday events in Monthly frequency. Should in format MO, TU, WE, TH, FR, SA, SU or numbers 0-6. in Montly you may want to give additional parameters like 1 for first 2 for second -1 for last -2 for second to last or every for all + ## Example This example defines a schedule, every 4 weeks starting on Friday, January 14, 2022 until the end of the year. @@ -81,3 +86,28 @@ waste_collection_schedule: - '2022-07-28' - '2022-09-22' ``` + +This example defines a schedule, last Friday of the month and every second Monday of the month, and every Tuesday of the month. From January 14, 2022 until the end of the year. +Two days are removed from the schedule and two days are added instead, which are outside of the recurrence. + +```yaml +waste_collection_schedule: + sources: + - name: static + calendar_title: Altpapier + args: + type: Altpapier + frequency: MONTHLY + weekdays: # add the weekdays + - FR: -1 + - MO: 2 + - TU: Every + start: '2022-01-14' + until: '2022-12-31' + excludes: # Add exception for the recurrence + - '2022-07-29' + - '2022-09-23' + dates: # Manually define dates that are not part of the recurrence + - '2022-07-28' + - '2022-09-22' +``` From 231865ac5124e2537feef7479aca7a35cc8cc937 Mon Sep 17 00:00:00 2001 From: 5ila5 <5ila5@users.noreply.github.com> Date: Sun, 19 Mar 2023 14:07:40 +0100 Subject: [PATCH 2/2] fixed type errors --- .../source/static.py | 80 +++++++++++-------- doc/source/static.md | 2 +- 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py index 0e312664..ab80e0de 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/static.py @@ -1,9 +1,10 @@ from dateutil.rrule import rrule from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU +from collections import OrderedDict + import datetime from dateutil import parser -from typing import Dict from waste_collection_schedule import Collection # type: ignore[attr-defined] @@ -41,14 +42,14 @@ TEST_CASES = { "frequency": "MONTHLY", "start": "2022-01-01", "until": "2022-12-31", - "weekdays": {"MO",5}, + "weekdays": {"MO", 5}, }, "Recurrence with Weekday with and without count": { "type": "Recurrence with Weekday with and without count", "frequency": "MONTHLY", "start": "2022-01-01", "until": "2022-12-31", - "weekdays": {"SA":-1,"MO":None,"TU":"Every"}, + "weekdays": {"SA": -1, "MO": None, "TU": "Every"}, }, } @@ -56,6 +57,7 @@ FREQNAMES = ["YEARLY", "MONTHLY", "WEEKLY", "DAILY"] WEEKDAYNAME = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"] WEEKDAYS = [MO, TU, WE, TH, FR, SA, SU] + class Source: def __init__( self, @@ -66,53 +68,65 @@ class Source: start: datetime.date = None, until: datetime.date = None, excludes: list[str] = None, - weekdays: list[str|int] | dict[str|int,int|str|None] = None, + weekdays: list[str | int] | dict[str | int, int | str | None] = None, ): self._weekdays = None - if (weekdays is not None): + if weekdays is not None: self._weekdays = [] - if (isinstance(weekdays, dict)): - for weekday, count in weekdays.items(): - print(weekday, count) - weekday_index = None - if (isinstance(weekday, int)): - weekday_index = weekday - elif (isinstance(weekday, str)): - weekday_index = WEEKDAYNAME.index(weekday) - - if (weekday_index>6 or weekday_index<0): - continue - - if (isinstance(count, str)): - count = int(count) if count.isdigit() else "every" - - if (count is None or count == "every" ): - [self._weekdays.append(WEEKDAYS[weekday_index](x)) for x in range(1,7)] - continue - - self._weekdays.append(WEEKDAYS[weekday_index](count)) - - else: + if isinstance(weekdays, dict | OrderedDict): + [self.add_weekday(weekday, count) + for weekday, count in weekdays.items()] + + elif isinstance(weekdays, list | set): for weekday in weekdays or []: - if (isinstance(weekday, int)): + if isinstance(weekday, int): self._weekdays.append(weekday) - if (isinstance(weekday, str)): + elif isinstance(weekday, str): self._weekdays.append(WEEKDAYNAME.index(weekday)) - if self._weekdays == []: self._weekdays = None - + elif isinstance(weekday, dict | OrderedDict): + [self.add_weekday(weekday, count) + for weekday, count in weekday.items()] + else: + raise Exception("Invalid weekdays format") + + else: + raise Exception("Invalid weekdays format") + + if self._weekdays == []: + self._weekdays = None + self._type = type self._dates = [parser.isoparse(d).date() for d in dates or []] - self._recurrence = FREQNAMES.index(frequency) if frequency is not None else None + self._recurrence = FREQNAMES.index( + frequency) if frequency is not None else None self._interval = interval self._start = parser.isoparse(start).date() if start else None self._until = parser.isoparse(until).date() if until else None self._excludes = [parser.isoparse(d).date() for d in excludes or []] + def add_weekday(self, weekday, count=None): + weekday_index = None + if isinstance(weekday, int): + weekday_index = weekday + elif isinstance(weekday, str): + weekday_index = WEEKDAYNAME.index(weekday) + + if weekday_index > 6 or weekday_index < 0: + return + + if isinstance(count, str): + count = int(count) if count.isdigit() else "every" + + if count is None or count == "every": + [self._weekdays.append(WEEKDAYS[weekday_index](x)) + for x in range(1, 7)] + return + self._weekdays.append(WEEKDAYS[weekday_index](count)) + def fetch(self): dates = [] - print(self._weekdays) if self._recurrence is not None: ruledates = rrule( freq=self._recurrence, diff --git a/doc/source/static.md b/doc/source/static.md index 94b5b774..cb7eb4e9 100644 --- a/doc/source/static.md +++ b/doc/source/static.md @@ -61,7 +61,7 @@ A list of dates in format "YYYY-MM-DD" which should be excluded from the recurre **WEEKDAYS** *(list | dictionary) (optional)* -Can either be used to define the week day for weekly frequency (can also be done by setting the start date and leaving this empty). Or to specify weekday events in Monthly frequency. Should in format MO, TU, WE, TH, FR, SA, SU or numbers 0-6. in Montly you may want to give additional parameters like 1 for first 2 for second -1 for last -2 for second to last or every for all +Can either be used to define the week day for weekly frequency (can also be done by setting the start date and leaving this field empty). Or to specify weekday events in Monthly frequency. Should be in format MO, TU, WE, TH, FR, SA, SU or numbers 0-6. in Monthly frequency you may want to give additional parameters like 1 for first 2 for second -1 for last -2 for second to last or "every"(or any String) for all ## Example