use day occurance counter instead of week counter
This commit is contained in:
parent
4e571b1b41
commit
12f096c56d
118
main.py
118
main.py
@ -6,31 +6,11 @@ CHURCH CALENDAR CSV GENERATOR
|
|||||||
import calendar
|
import calendar
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from pprint import pprint
|
|
||||||
import sys
|
import sys
|
||||||
import click
|
import click
|
||||||
from dataclass_csv import DataclassWriter
|
from dataclass_csv import DataclassWriter
|
||||||
from events import EVENT_LIST
|
from events import EVENT_LIST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
build a list of months / weeks / day of the month in those weeks
|
|
||||||
months 1-12, weeks 0-5 days of week 5 6 are the 1st and 2nd of month
|
|
||||||
MONTHS[1] [0] [ 0 0 0 0 0 1 2 ]
|
|
||||||
|
|
||||||
due to how months work
|
|
||||||
week 0 can have null days (represented by 0's)
|
|
||||||
weeks 1 - 4 will have all 7 days present
|
|
||||||
week 5 may have 7 days or nulls
|
|
||||||
week 6 can have a monday and/or tuesday in them if the 1st falls on a
|
|
||||||
saturday or sunday in week 0
|
|
||||||
|
|
||||||
EVENT_LIST has weeks as 1-6 while MONTHS has weeks as 0-5, offsetting will
|
|
||||||
be necessary
|
|
||||||
"""
|
|
||||||
|
|
||||||
def initalize_events(event_list):
|
def initalize_events(event_list):
|
||||||
""" convert EVENT_LIST into monthly_events """
|
""" convert EVENT_LIST into monthly_events """
|
||||||
monthly_events = [[] for _ in range(7)]
|
monthly_events = [[] for _ in range(7)]
|
||||||
@ -38,14 +18,8 @@ def initalize_events(event_list):
|
|||||||
monthly_events[event[0]].append(event[1:])
|
monthly_events[event[0]].append(event[1:])
|
||||||
return monthly_events
|
return monthly_events
|
||||||
|
|
||||||
|
|
||||||
def debug_print(data, condition=True, end="\n"):
|
def debug_print(data, condition=True, end="\n"):
|
||||||
"""Conditionally print data using pprint.
|
"""Conditionally print data."""
|
||||||
|
|
||||||
Args:
|
|
||||||
data: The data to be printed.
|
|
||||||
condition: A boolean value. If True, the data will be printed.
|
|
||||||
"""
|
|
||||||
if condition:
|
if condition:
|
||||||
print(data, end=end)
|
print(data, end=end)
|
||||||
|
|
||||||
@ -58,7 +32,6 @@ def initalize_year(year: int) -> dict[int, list[list[int]]]:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class Event():
|
class Event():
|
||||||
"""Event for CSV export"""
|
"""Event for CSV export"""
|
||||||
# pylint: disable=too-many-instance-attributes
|
|
||||||
event_name: str
|
event_name: str
|
||||||
venue_name: str
|
venue_name: str
|
||||||
organizer_name: str
|
organizer_name: str
|
||||||
@ -86,20 +59,13 @@ def suffix(day: int) -> str:
|
|||||||
result = 'rd'
|
result = 'rd'
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def sort_events(events: list[Event]) -> list[Event]:
|
|
||||||
"""sort events"""
|
|
||||||
events = sorted(events, key=lambda k: (k.start_date, k.start_time))
|
|
||||||
return events
|
|
||||||
|
|
||||||
def create_event(name: str,
|
def create_event(name: str,
|
||||||
location: str,
|
location: str,
|
||||||
categories: str,
|
categories: str,
|
||||||
description: str,
|
description: str,
|
||||||
start,
|
start,
|
||||||
finish) -> None:
|
finish) -> Event:
|
||||||
"""create event"""
|
"""create event object"""
|
||||||
# pylint: disable=too-many-arguments
|
|
||||||
event = Event(name,
|
event = Event(name,
|
||||||
location,
|
location,
|
||||||
"",
|
"",
|
||||||
@ -116,13 +82,11 @@ def create_event(name: str,
|
|||||||
"",
|
"",
|
||||||
description)
|
description)
|
||||||
return event
|
return event
|
||||||
# events.append(event)
|
|
||||||
|
|
||||||
|
|
||||||
def write_calendar(events: list[Event], filename) -> None:
|
def write_calendar(events: list[Event], filename) -> None:
|
||||||
"""write calendar to csv file"""
|
"""write calendar to csv file"""
|
||||||
with open(filename, "w", encoding="utf-8", newline="") as handle:
|
with open(filename, "w", encoding="utf-8", newline="") as handle:
|
||||||
writer =DataclassWriter(handle, events, Event)
|
writer = DataclassWriter(handle, events, Event)
|
||||||
writer.map("event_name").to("EVENT NAME")
|
writer.map("event_name").to("EVENT NAME")
|
||||||
writer.map("venue_name").to("VENUE NAME")
|
writer.map("venue_name").to("VENUE NAME")
|
||||||
writer.map("organizer_name").to("ORGANIZER NAME")
|
writer.map("organizer_name").to("ORGANIZER NAME")
|
||||||
@ -140,7 +104,6 @@ def write_calendar(events: list[Event], filename) -> None:
|
|||||||
writer.map("event_description").to("EVENT DESCRIPTION")
|
writer.map("event_description").to("EVENT DESCRIPTION")
|
||||||
writer.write()
|
writer.write()
|
||||||
|
|
||||||
|
|
||||||
def process_day(events, year, month, day, day_events):
|
def process_day(events, year, month, day, day_events):
|
||||||
"""process all events for one day"""
|
"""process all events for one day"""
|
||||||
for event_item in day_events:
|
for event_item in day_events:
|
||||||
@ -151,87 +114,78 @@ def process_day(events, year, month, day, day_events):
|
|||||||
events.append(event)
|
events.append(event)
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def process_month(months, monthly_events, year, month, week_of_month, week, events):
|
def process_month(monthly_events, year, month, week, events, weekday_counters):
|
||||||
"""process one months of events"""
|
"""process one week of events using weekday occurrence counters"""
|
||||||
for day_of_week, day in enumerate(week):
|
for day_of_week, day in enumerate(week):
|
||||||
if day > 0:
|
if day > 0:
|
||||||
"""
|
# Increment the occurrence count for this specific weekday (0=Mon, 6=Sun)
|
||||||
month, week_of_month, day_of_week, day
|
weekday_counters[day_of_week] += 1
|
||||||
use monthly_events[day_of_week]
|
current_occurrence = weekday_counters[day_of_week]
|
||||||
"""
|
|
||||||
debug_print(f" {day_of_week}-{day:02d}", DEBUG)
|
debug_print(f" {day_of_week}-{day:02d} (Occurrence: {current_occurrence})", DEBUG)
|
||||||
day_events = [x[1:] for x in monthly_events[day_of_week] if week_of_month + 1 in x[0]]
|
|
||||||
|
# Filter events matching this day of week and this specific occurrence (e.g., 2nd Monday)
|
||||||
|
day_events = [x[1:] for x in monthly_events[day_of_week] if current_occurrence in x[0]]
|
||||||
events = process_day(events, year, month, day, day_events)
|
events = process_day(events, year, month, day, day_events)
|
||||||
debug_print("", DEBUG)
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def process_months(months, monthly_events, year, month_range):
|
def process_months(months_dict, monthly_events, year, month_range):
|
||||||
"""process full year of months and return list of events"""
|
"""process selected months and return list of events"""
|
||||||
events = []
|
events = []
|
||||||
for month in range(1, 13):
|
for month in range(1, 13):
|
||||||
if month not in month_range:
|
if month not in month_range:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
debug_print(f"MONTH: {month}", DEBUG)
|
debug_print(f"MONTH: {month}", DEBUG)
|
||||||
for week_of_month, week in enumerate(months[month]):
|
|
||||||
|
# Initialize counters for the month to track 1st, 2nd, etc. occurrence of each weekday
|
||||||
|
weekday_counters = [0] * 7
|
||||||
|
|
||||||
|
for week_of_month, week in enumerate(months_dict[month]):
|
||||||
debug_print(f"{week_of_month} {week}", DEBUG)
|
debug_print(f"{week_of_month} {week}", DEBUG)
|
||||||
events = process_month(months, monthly_events, year, month, week_of_month, week, events)
|
events = process_month(monthly_events, year, month, week, events, weekday_counters)
|
||||||
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def validate_months(ctx, param, value):
|
def validate_months(ctx, param, value):
|
||||||
"""
|
"""Validates and processes the --months option."""
|
||||||
Validates and processes the --months option.
|
|
||||||
Accepts a single number (1-12) or a range (1-3).
|
|
||||||
Defaults to 1-12 if no value is provided.
|
|
||||||
"""
|
|
||||||
if value is None:
|
if value is None:
|
||||||
return list(range(1, 13)) # Default behavior
|
return list(range(1, 13))
|
||||||
|
|
||||||
parts = value.split('-')
|
parts = value.split('-')
|
||||||
|
|
||||||
if len(parts) == 1:
|
if len(parts) == 1:
|
||||||
# Handle single month input
|
|
||||||
try:
|
try:
|
||||||
month = int(parts[0])
|
month = int(parts[0])
|
||||||
if 1 <= month <= 12:
|
if 1 <= month <= 12:
|
||||||
return [month]
|
return [month]
|
||||||
else:
|
raise click.BadParameter("Month must be between 1 and 12.")
|
||||||
raise click.BadParameter("Month must be between 1 and 12.", param=param)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadParameter("Invalid month format. Please use an integer between 1 and 12.", param=param)
|
raise click.BadParameter("Invalid month format.")
|
||||||
|
|
||||||
elif len(parts) == 2:
|
elif len(parts) == 2:
|
||||||
# Handle range input
|
|
||||||
try:
|
try:
|
||||||
start, end = int(parts[0]), int(parts[1])
|
start, end = int(parts[0]), int(parts[1])
|
||||||
if 1 <= start <= 12 and 1 <= end <= 12 and start <= end:
|
if 1 <= start <= 12 and 1 <= end <= 12 and start <= end:
|
||||||
return list(range(start, end + 1))
|
return list(range(start, end + 1))
|
||||||
else:
|
raise click.BadParameter("Invalid month range.")
|
||||||
raise click.BadParameter("Invalid month range. Both months must be between 1 and 12, and the start month must be less than or equal to the end month.", param=param)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadParameter("Invalid range format. Please use two integers separated by a hyphen (e.g., 1-3).", param=param)
|
raise click.BadParameter("Invalid range format.")
|
||||||
|
raise click.BadParameter("Use a single number or a range (e.g., 1-3).")
|
||||||
else:
|
|
||||||
# Handle invalid format
|
|
||||||
raise click.BadParameter("Invalid format. Use a single number (e.g., 3) or a range (e.g., 1-3).", param=param)
|
|
||||||
|
|
||||||
# @click.argument('filename', type=click.File('w'), default="calendar.csv", required=False)
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--debug", "-d", is_flag=True, default=False, help="Print debug output")
|
@click.option("--debug", "-d", is_flag=True, default=False, help="Print debug output")
|
||||||
@click.option('--year', "-y", type=int, default=date.today().year, help='Specify the year.')
|
@click.option('--year', "-y", type=int, default=date.today().year, help='Specify the year.')
|
||||||
@click.option('--months', '-m', 'month_range', callback=validate_months, default=None,
|
@click.option('--months', '-m', 'month_range', callback=validate_months, default=None,
|
||||||
help='A single month (1-12) or a range (e.g., 1-3). Defaults to all months (1-12).')
|
help='A single month (1-12) or a range (e.g., 1-3).')
|
||||||
@click.argument('filename', default="calendar.csv", required=False)
|
@click.argument('filename', default="calendar.csv", required=False)
|
||||||
def main(debug, year, month_range, filename):
|
def main(debug, year, month_range, filename):
|
||||||
"""Create a .csv file of church events for the year. Modify events.py to change events"""
|
"""Create a .csv file of church events for the year."""
|
||||||
global DEBUG
|
global DEBUG
|
||||||
DEBUG = debug
|
DEBUG = debug
|
||||||
months = initalize_year(year)
|
months_dict = initalize_year(year)
|
||||||
monthly_events = initalize_events(EVENT_LIST)
|
monthly_events = initalize_events(EVENT_LIST)
|
||||||
events = process_months(months, monthly_events, year, month_range)
|
events = process_months(months_dict, monthly_events, year, month_range)
|
||||||
# events = sort_events(events)
|
|
||||||
write_calendar(events, filename)
|
write_calendar(events, filename)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main() # pylint: disable=E1120
|
main()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user