Skip to content

Instantly share code, notes, and snippets.

@ajoh504
Created September 25, 2022 15:33
Show Gist options
  • Save ajoh504/d69a8c7fc1344bf22e21e9c430c46eb1 to your computer and use it in GitHub Desktop.
Save ajoh504/d69a8c7fc1344bf22e21e9c430c46eb1 to your computer and use it in GitHub Desktop.
Random Chore Assignment Emailer - Automate the Boring Stuff With Python - CH 18
#!python3
# emailchores.py - Scan a list of chores and a list of email addresses then
# randomly assign chores to people via email. Track recent
# chores so that the same chore is not assigned the following
# week.
#
# USAGE: Run script with --help or -h to view help information.
# Using Python 3.6 and EZGmail 2022.2.24
#
# SOURCE: https://automatetheboringstuff.com/2e/chapter18/
import random
import json
import argparse
import ezgmail
import time
from pathlib import Path
parser = argparse.ArgumentParser(
description="""
Input emails and chores for weekly scheduling. Arguments are
required for first time setup, but optional otherwise. Emails
and chores will be stored in a text file, and new arguments will
be appended to the previous emails or chores files.\n
example: py emailchores.py -e \"email1\" \"email2\" -c \"chore1\" \"chore2\"""",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("-e", "--emails", nargs="*", help="Input emails to send chores to")
parser.add_argument("-c", "--chores", nargs="*", help="Input chores to send via email")
cli_args = parser.parse_args()
def get_json_data() -> dict:
""":return: the contents of chores.json"""
with open(Path.home() / "chores.json", "r", encoding="utf-8") as f:
return json.load(f)
def update_chores_or_emails(dict_key: str, args: list) -> dict:
"""
Retrieve the current data from chores.json. Store the data temporarily and
update it with the command line arguments for new emails or new chores.
If argument is already in json_dict, then do not add it.
:return: JSON dict updated with command line arguments
"""
json_dict = get_json_data()
new_list = json_dict[dict_key] + [i for i in args if i not in json_dict[dict_key]]
json_dict[dict_key] = new_list
return json_dict
def get_emails_to_assign() -> list:
"""Create a list of dictionaries with all emails as keys, and empty strings as values."""
emails = get_json_data()["emails"]
return [{i: ""} for i in emails]
def write_chores_to_file() -> None:
"""Overwrite JSON file with an updated dict if emails are supplied as command line arguments."""
if cli_args.chores is not None:
data = update_chores_or_emails("chores", cli_args.chores)
with open(Path.home() / "chores.json", "w", encoding="utf-8") as f:
json.dump(data, f, sort_keys=True, indent=4)
def write_emails_to_file() -> None:
"""
Overwrite JSON file with an updated dict if emails are supplied as command line arguments.
Also update "previous_assignments" from the JSON file to contain a new list of available
assignments.
"""
if cli_args.emails is not None:
data = update_chores_or_emails("emails", cli_args.emails)
with open(Path.home() / "chores.json", "w", encoding="utf-8") as f:
json.dump(data, f, sort_keys=True, indent=4)
data = update_chores_or_emails("emails", cli_args.emails)
data["previous_assignments"] = get_emails_to_assign()
with open(Path.home() / "chores.json", "w", encoding="utf-8") as f:
json.dump(data, f, sort_keys=True, indent=4)
def get_new_assignments() -> list:
"""
Loop through all emails and compare their assignments to a randomly
selected chore. If the chore was previously assigned, skip it. Else,
assign the random chore.
:return: A list of new chore assignments.
"""
assignments = get_json_data()["previous_assignments"]
new_assignments = []
for dictionary in assignments:
email, chore = dictionary.popitem()
while True:
random_chore = random.choice(get_json_data()["chores"])
if chore == random_chore:
continue
else:
new_assignments.append({email: random_chore})
break
return new_assignments
def save_weekly_chores(chores: list) -> None:
"""Get updated list of chore assignments and write the list to chores.json."""
weekly_chores = chores
json_dict = get_json_data()
json_dict["previous_assignments"] = weekly_chores
with open(Path.home() / "chores.json", "w", encoding="utf-8") as f:
json.dump(
json_dict,
f,
sort_keys=True,
indent=4,
)
def email_chores() -> None:
for dictionary in get_json_data()["previous_assignments"]:
email, chore = dictionary.popitem()
ezgmail.send(email, "Your chore for this week", f"{chore}\nDon't forget to wash your hands!")
time.sleep(10) # pause ten seconds between emails
def main():
"""
Create JSON file if it does not exist, and write the default data fields.
Run the main program execution.
"""
if not Path(Path.home() / "chores.json").exists():
with open(Path.home() / "chores.json", "a", encoding="utf-8") as f:
json.dump(
{"chores": [], "emails": [], "previous_assignments": []},
f,
sort_keys=True,
indent=4,
)
write_chores_to_file()
write_emails_to_file()
new_assignments = get_new_assignments()
save_weekly_chores(new_assignments)
email_chores()
print("P.S., check your junk mail")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment