Compare commits
No commits in common. "2f3f1d9a132928e61486e48881d624afa21b1014" and "0d9f5264d482a11500c2d5554456705202ecaf29" have entirely different histories.
2f3f1d9a13
...
0d9f5264d4
54
src/draw.py
54
src/draw.py
@ -1,51 +1,41 @@
|
|||||||
from random import choice
|
from random import choice
|
||||||
|
|
||||||
def draw_names(current_participants, history_data, draws_per_person, max_attempts=5):
|
def draw_names(previous_draw, draws_per_person):
|
||||||
"""
|
"""
|
||||||
Perform the Secret Santa draw considering past years' draws.
|
Perform the Secret Santa draw considering past draws.
|
||||||
:param current_participants: This year's participant list.
|
:param previous_draw: Last year's draw data (list of participants and recipients).
|
||||||
:param history_data: Historical draw data to avoid repeats.
|
|
||||||
:param draws_per_person: Number of people each participant should give gifts to.
|
:param draws_per_person: Number of people each participant should give gifts to.
|
||||||
:param max_attempts: Maximum number of retry attempts before loosening exclusions. by default : 5.
|
|
||||||
:return: The new draw results.
|
:return: The new draw results.
|
||||||
"""
|
"""
|
||||||
participants = [p[0] for p in current_participants] # Get participant names
|
participants = [a[0] for a in previous_draw] # Get participant names
|
||||||
already_drawn = [] # Track who has been drawn
|
already_drawn = [] # Track who has been drawn
|
||||||
new_draw = [] # Store new draw results
|
new_draw = [] # Store new draw results
|
||||||
|
|
||||||
for attempt in range(max_attempts):
|
for i in range(len(participants)):
|
||||||
new_draw.clear()
|
giver = previous_draw[i][0]
|
||||||
already_drawn.clear()
|
email = previous_draw[i][1]
|
||||||
success = True # Track if draw is successful in this attempt
|
print(email)
|
||||||
|
last_year_r1 = previous_draw[i][2]
|
||||||
|
last_year_r2 = previous_draw[i][3]
|
||||||
|
|
||||||
for i, giver in enumerate(participants):
|
available_participants = participants.copy()
|
||||||
email = current_participants[i][1]
|
try:
|
||||||
# Collect previous recipients to avoid drawing the same person again
|
available_participants.remove(giver)
|
||||||
previous_recipients = {recipient for record in history_data if record[0] == giver for recipient in record[2:]}
|
available_participants.remove(last_year_r1)
|
||||||
|
available_participants.remove(last_year_r2)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
# Create a set of available participants excluding the giver and previous recipients
|
|
||||||
available_participants = set(participants) - {giver} - previous_recipients
|
|
||||||
new_recipients = []
|
new_recipients = []
|
||||||
|
|
||||||
# Ensure there are enough available participants for the draw
|
|
||||||
if len(available_participants) < draws_per_person:
|
|
||||||
success = False
|
|
||||||
break
|
|
||||||
|
|
||||||
# Select recipients for the current giver
|
|
||||||
while len(new_recipients) < draws_per_person:
|
while len(new_recipients) < draws_per_person:
|
||||||
selected = choice(list(available_participants))
|
selected = choice(available_participants)
|
||||||
if already_drawn.count(selected) < draws_per_person:
|
if already_drawn.count(selected) >= draws_per_person:
|
||||||
|
available_participants.remove(selected)
|
||||||
|
else:
|
||||||
new_recipients.append(selected)
|
new_recipients.append(selected)
|
||||||
already_drawn.append(selected)
|
already_drawn.append(selected)
|
||||||
available_participants.discard(selected)
|
available_participants.remove(selected)
|
||||||
|
|
||||||
new_draw.append([giver, email] + new_recipients)
|
new_draw.append([giver, email] + new_recipients)
|
||||||
|
|
||||||
# If the draw was successful, break out of attempts
|
|
||||||
if success:
|
|
||||||
return new_draw
|
return new_draw
|
||||||
print(f"Attempt {attempt + 1} failed, retrying...")
|
|
||||||
|
|
||||||
# If all attempts fail, raise an error
|
|
||||||
raise ValueError("Unable to complete a valid draw after maximum attempts.")
|
|
||||||
|
|||||||
@ -1,57 +1,13 @@
|
|||||||
import csv
|
import csv
|
||||||
from datetime import date
|
|
||||||
from env import CSV_PREFIX, CSV_PATH
|
|
||||||
|
|
||||||
def load_history(years):
|
def open_csv(file_name):
|
||||||
"""
|
"""Open the CSV file and return its contents as a list of rows"""
|
||||||
Load participant data from multiple CSV files based on the specified history years.
|
|
||||||
:param years: Number of years of history to load.
|
|
||||||
:return: A list of all historical draw data.
|
|
||||||
"""
|
|
||||||
current_year = date.today().year
|
|
||||||
history_data = []
|
|
||||||
|
|
||||||
# Load data for each of the past specified years
|
|
||||||
for i in range(1, years + 1):
|
|
||||||
|
|
||||||
try:
|
|
||||||
year = current_year - i
|
|
||||||
file_name = f"{CSV_PATH}/{CSV_PREFIX}_{year}.csv"
|
|
||||||
with open(file_name, "r", encoding='utf-8') as file:
|
with open(file_name, "r", encoding='utf-8') as file:
|
||||||
reader = csv.reader(file)
|
reader = csv.reader(file)
|
||||||
history_data.extend(list(reader)) # Add each year's data
|
return list(reader)
|
||||||
except FileNotFoundError:
|
|
||||||
print(f"No historical file found for year {year}, skipping.")
|
|
||||||
continue
|
|
||||||
|
|
||||||
return history_data
|
def save_csv(data, file_name):
|
||||||
|
"""Save the updated draw results to the CSV file"""
|
||||||
def load_participants():
|
|
||||||
"""
|
|
||||||
Load participant data from the current year CSV file.
|
|
||||||
:return: A list of all historical draw data.
|
|
||||||
"""
|
|
||||||
current_year = date.today().year
|
|
||||||
participants_data = []
|
|
||||||
try:
|
|
||||||
file_name = f"{CSV_PATH}/{CSV_PREFIX}_{current_year}.csv"
|
|
||||||
print(file_name)
|
|
||||||
with open(file_name, "r", encoding='utf-8') as file:
|
|
||||||
reader = csv.reader(file)
|
|
||||||
participants_data.extend(list(reader)) # Add each year's data
|
|
||||||
except FileNotFoundError:
|
|
||||||
print(f"No file found for year {current_year}, skipping.")
|
|
||||||
|
|
||||||
|
|
||||||
return participants_data
|
|
||||||
|
|
||||||
def save_csv(data, year):
|
|
||||||
"""
|
|
||||||
Save the new draw results to a CSV file named with the current year.
|
|
||||||
:param data: New draw data.
|
|
||||||
:param year: The current year for naming the file.
|
|
||||||
"""
|
|
||||||
file_name = f"{CSV_PATH}/{CSV_PREFIX}_{year}.csv"
|
|
||||||
with open(file_name, 'w', newline='', encoding='utf-8') as file:
|
with open(file_name, 'w', newline='', encoding='utf-8') as file:
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
writer.writerows(data)
|
writer.writerows(data)
|
||||||
22
src/main.py
22
src/main.py
@ -1,5 +1,5 @@
|
|||||||
from env import DRAW_PER_PERSON, HISTORY_YEARS, EMAIL_SUBJECT, EMAIL_BODY
|
from env import CSV_FILE_PATH, DRAW_PER_PERSON, EMAIL_SUBJECT, EMAIL_BODY
|
||||||
from file_io import load_history, save_csv, load_participants
|
from file_io import open_csv, save_csv
|
||||||
from draw import draw_names
|
from draw import draw_names
|
||||||
from emailer import send_email
|
from emailer import send_email
|
||||||
from utils import get_current_time
|
from utils import get_current_time
|
||||||
@ -11,29 +11,29 @@ def send_all_emails(new_draw):
|
|||||||
for participant in new_draw:
|
for participant in new_draw:
|
||||||
name = participant[0]
|
name = participant[0]
|
||||||
receiver_email = participant[1]
|
receiver_email = participant[1]
|
||||||
draws = ", ".join(participant[2:])
|
draws = ", ".join(participant[2:]) # List of recipients
|
||||||
message = EMAIL_BODY.format(name=name, draws=draws)
|
message = EMAIL_BODY.format(name=name, draws=draws)
|
||||||
subject = EMAIL_SUBJECT.format(year=current_year)
|
subject = EMAIL_SUBJECT.format(year=current_year)
|
||||||
send_email(receiver_email, subject, message)
|
send_email(receiver_email, subject, message) # Send the email
|
||||||
print(f"Email sent to {name} ({receiver_email})")
|
print(f"Email sent to {name} ({receiver_email})")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
# Load data from historical CSVs and this year's participants
|
# Load previous draw data
|
||||||
history_data = load_history(HISTORY_YEARS)
|
old_draw = open_csv(CSV_FILE_PATH)
|
||||||
|
|
||||||
current_year = date.today().year
|
# Perform new draw
|
||||||
current_participants = load_participants() # Load participants data
|
new_draw = draw_names(old_draw, DRAW_PER_PERSON)
|
||||||
|
|
||||||
# Perform the draw
|
|
||||||
new_draw = draw_names(current_participants, history_data, DRAW_PER_PERSON)
|
|
||||||
# Send emails to participants
|
# Send emails to participants
|
||||||
send_all_emails(new_draw)
|
send_all_emails(new_draw)
|
||||||
|
|
||||||
# Save new draw results
|
# Save new draw results
|
||||||
save_csv(new_draw, current_year)
|
save_csv(new_draw, CSV_FILE_PATH)
|
||||||
|
|
||||||
|
# Output completion time
|
||||||
print(f"Process completed at {get_current_time()[1]} on {get_current_time()[0]}")
|
print(f"Process completed at {get_current_time()[1]} on {get_current_time()[0]}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error occurred: {e}")
|
print(f"Error occurred: {e}")
|
||||||
|
# Retry or handle errors
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user