refactor static source

This commit is contained in:
mampfes
2023-03-23 20:16:18 +01:00
parent c18c3b61cd
commit 3dec26906c
3 changed files with 120 additions and 83 deletions

View File

@@ -1,61 +1,59 @@
from dateutil.rrule import rrule
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
import datetime
from collections import OrderedDict
import datetime
from dateutil import parser
from dateutil.rrule import FR, MO, SA, SU, TH, TU, WE, rrule
from waste_collection_schedule import Collection # type: ignore[attr-defined]
TITLE = "Static Source"
DESCRIPTION = "Source for static waste collection schedules."
URL = None
TEST_CASES = {
"Dates only": {"type": "Dates only", "dates": {"2022-01-01", "2022-02-28"}},
"Same date twice": {"type": "Dates only", "dates": {"2022-01-01", "2022-01-01"}},
"Recurrence only": {
"type": "Recurrence only",
"Dates only": {"type": "Dates only", "dates": ["2022-01-01", "2022-02-28"]},
"Same date twice": {"type": "Dates only", "dates": ["2022-01-01", "2022-01-01"]},
"Recurrence monthly by date": {
"type": "First day of month",
"frequency": "MONTHLY",
"interval": 1,
"start": "2022-01-01",
"until": "2022-12-31",
},
"Recurrence with exception": {
"type": "Recurrence with exception",
"Recurrence monthly by date with date list": {
"type": "First day of month excluding 01-Jan, including 02-Jan",
"frequency": "MONTHLY",
"interval": 1,
"start": "2022-01-01",
"until": "2022-12-31",
"excludes": {"2022-01-01"},
"dates": {"2022-01-02"},
"excludes": ["2022-01-01"],
"dates": ["2022-01-02"],
},
"Recurrence with Weekday and count": {
"type": "Recurrence with Weekday",
"Recurrence with weekday dict (day + byweekday)": {
"type": "First Monday and second Tuesday of the month",
"frequency": "MONTHLY",
"start": "2022-01-01",
"until": "2022-12-31",
"weekdays": {"MO": 1, 1: 2},
"weekdays": {"MO": 1, "TU": 2},
},
"Recurrence with Weekday without count": {
"type": "Recurrence with Weekday without count",
"Recurrence with first Saturday of the month": {
"type": "First Saturday of the month",
"frequency": "MONTHLY",
"start": "2022-01-01",
"until": "2022-12-31",
"weekdays": {"MO", 5},
"weekdays": "SA",
},
"Recurrence with Weekday with and without count": {
"type": "Recurrence with Weekday with and without count",
"Recurrence with last Saturday of the month": {
"type": "Last Saturday of the month",
"frequency": "MONTHLY",
"start": "2022-01-01",
"until": "2022-12-31",
"weekdays": {"SA": -1, "MO": None, "TU": "Every"},
"weekdays": {"SA": -1},
},
"Recurrence weekly specified by weekday": {
"type": "Every Friday",
"frequency": "WEEKLY",
"weekdays": "FR",
},
}
FREQNAMES = ["YEARLY", "MONTHLY", "WEEKLY", "DAILY"]
WEEKDAYNAME = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"]
WEEKDAYS = [MO, TU, WE, TH, FR, SA, SU]
WEEKDAY_MAP = {"MO": MO, "TU": TU, "WE": WE, "TH": TH, "FR": FR, "SA": SA, "SU": SU}
class Source:
@@ -67,6 +65,7 @@ class Source:
interval: int = 1,
start: datetime.date = None,
until: datetime.date = None,
count: int = None,
excludes: list[str] = None,
weekdays: list[str | int] | dict[str | int, int | str | None] = None,
):
@@ -74,23 +73,16 @@ class Source:
if weekdays is not None:
self._weekdays = []
if isinstance(weekdays, dict | OrderedDict):
[self.add_weekday(weekday, count)
for weekday, count in weekdays.items()]
[
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):
self._weekdays.append(weekday)
elif isinstance(weekday, str):
self._weekdays.append(WEEKDAYNAME.index(weekday))
elif isinstance(weekday, dict | OrderedDict):
[self.add_weekday(weekday, count)
for weekday, count in weekday.items()]
else:
raise Exception("Invalid weekdays format")
elif isinstance(weekdays, str):
self.add_weekday(weekdays, 1)
else:
raise Exception("Invalid weekdays format")
raise Exception(f"Invalid weekdays format: {weekdays}")
if self._weekdays == []:
self._weekdays = None
@@ -98,31 +90,22 @@ class Source:
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
if until:
self._until = parser.isoparse(until).date()
self._count = None
else:
self._until = None
self._count = count if count else 10
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)
def add_weekday(self, weekday, count: int):
if weekday not in WEEKDAY_MAP:
raise Exception(f"invalid weekday: {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))
self._weekdays.append(WEEKDAY_MAP[weekday](count))
def fetch(self):
dates = []
@@ -133,6 +116,7 @@ class Source:
interval=self._interval,
dtstart=self._start,
until=self._until,
count=self._count,
byweekday=self._weekdays,
)

View File

@@ -25,6 +25,8 @@ def main():
parser.add_argument(
"-i", "--icon", action="store_true", help="Show waste type icon"
)
parser.add_argument("--sorted", action="store_true", help="Sort output by date")
parser.add_argument("--weekday", action="store_true", help="Show weekday")
parser.add_argument(
"-t",
"--traceback",
@@ -106,9 +108,15 @@ def main():
)
if args.list:
result = (
sorted(result, key=lambda x: x.date) if args.sorted else result
)
for x in result:
icon_str = f" [{x.icon}]" if args.icon else ""
print(f" {x.date.isoformat()}: {x.type}{icon_str}")
weekday_str = x.date.strftime("%a ") if args.weekday else ""
print(
f" {x.date.isoformat()} {weekday_str}: {x.type}{icon_str}"
)
except KeyboardInterrupt:
exit()
except Exception as exc:

View File

@@ -15,7 +15,9 @@ waste_collection_schedule:
interval: INTERVAL
start: START
until: UNTIL
count: COUNT
excludes: EXCLUDES
weekdays: WEEKDAYS
```
### Configuration Variables
@@ -51,7 +53,11 @@ Required if *FREQUENCY* is set.
*(string) (optional)*
Defines the end of the recurrence in the format "YYYY-MM-DD".
Required if *FREQUENCY* is set.
**COUNT**
*(int) (optional)*
Defines the (maximum) number of returned dates. Only used if `until` is not specified. Defaults to 10.
**EXCLUDES**
*(list) (optional)*
@@ -59,11 +65,33 @@ 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)*
*(weekday | list of weekdays | dictionary of weekday and occurrence) (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 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
Used to define the weekday for weekly or monthly frequencies. A weekday is specified by the following weekday constants: `MO, TU, WE, TH, FR, SA, SU`.
## Example
`WEEKDAYS` can be specified in one of the following 3 formats:
1. Single Weekday:
```yaml
weekdays: MO
```
2. List of Weekdays:
```yaml
weekdays: [MO, TU, SA]
```
3. Dictionary:
```yaml
weekdays: { MO:1, FR:-2 }
```
The additional numerical argument means the nth occurrence of this weekday in the specified frequency (normally only MONTHLY makes sense here). If frequency is set to `MONTHLY`, `MO:1` represents the first Monday of the month. `FR:-2` represents the 2nd last Friday of the month.
## Examples
This example defines a schedule, every 4 weeks starting on Friday, 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.
@@ -72,7 +100,6 @@ Two days are removed from the schedule and two days are added instead, which are
waste_collection_schedule:
sources:
- name: static
calendar_title: Altpapier
args:
type: Altpapier
frequency: WEEKLY
@@ -82,32 +109,50 @@ waste_collection_schedule:
excludes: # Add exception for the recurrence
- '2022-07-29'
- '2022-09-23'
dates: # Manually define dates that are not part of the recurrence
dates: # Manually add dates that are not part of the recurrence
- '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.
---
Defines a weekly schedule on Wednesday.
```yaml
waste_collection_schedule:
sources:
- name: static
args:
type: Altpapier
frequency: WEEKLY
weekdays: WE
```
---
Defines a schedule for the 2nd last Thursday of a month.
```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'
weekdays: {TH:-1}
```
---
Defines a bi-weekly schedule for starting on the 01-Jan-2023.
```yaml
waste_collection_schedule:
sources:
- name: static
args:
type: Altpapier
frequency: WEEKLY
interval: 2
start: 2023-01-01
```