Last active
December 11, 2020 22:07
-
-
Save marknca/7621937 to your computer and use it in GitHub Desktop.
A quick Secret Santa generator. You can specify restrictions (e.g., don't let Larry draw Jen's name). Set the three TODO sections (line 14, line 17, and line 74) before running the script.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
# Usage | |
# =============================== | |
# test run | |
# ./santa.py --test | |
# | |
# game time | |
# ./santa.py --password EMAIL | |
# | |
import argparse | |
import datetime | |
import random | |
import smtplib | |
import string | |
import sys | |
# set this with the --password switch at the command line | |
OUTBOUND_EMAIL_PASSWORD = "" | |
# TODO: configure these for your environment | |
FROM_ADDRESS = 'santa@' | |
FROM_ADDRESS_NAME = 'Santa' | |
# TODO: set your exchange participants and any restrictions | |
ppl = { | |
# people in draw: [ 'cant', 'get' ] | |
# e.g., | |
# mark: { 'email': 'mark@some.org', 'dont_match_with': [ 'mark's wife', 'whomever mark had for the last exchange' ] }, | |
'p1': { 'email': 'p1@some.org', 'dont_match_with': [ 'p2', 'p3' ] }, | |
'p2': { 'email': 'p2@some.org', 'dont_match_with': [ 'p1', 'p3' ] }, | |
'p3': { 'email': 'p3@some.org', 'dont_match_with': [ 'p4' ] }, | |
'p4': { 'email': 'p4@some.org', 'dont_match_with': [ ] }, | |
'p5': { 'email': 'p5@some.org', 'dont_match_with': [ ] }, | |
} | |
# Global functions | |
def create_argument_parser(script_description, arguments): | |
""" | |
Configure an ArgumentParser object to handle command line options | |
and arguments | |
Arguments: | |
========== | |
script_description (str) | |
The friendly description of the script | |
arguments (dict) | |
A dict setup as { 'arg': { 'help': '', 'required': '', } } | |
describing the accepted arguments | |
Output: | |
======== | |
(argparse.ArgumentParser) Fully configured parser for command line | |
arguments | |
""" | |
parser = argparse.ArgumentParser(description=script_description) | |
for arg, vals in arguments.items(): | |
parser.add_argument('--%s' % arg, | |
action='store' if not vals.has_key('action') else vals['action'], | |
required=False if not vals.has_key('required') else vals['required'], | |
default=None if not vals.has_key('default') else vals['default'], | |
help=vals['help'] if vals.has_key('help') else '', | |
) | |
return parser | |
def send_msg(to_name, to_email_address, match_name): | |
# Cribbed from http://segfault.in/2010/12/sending-gmail-from-python/ | |
session = smtplib.SMTP('smtp.gmail.com', 587) | |
session.ehlo() | |
session.starttls() | |
session.ehlo | |
session.login(FROM_ADDRESS, OUTBOUND_EMAIL_PASSWORD) | |
headers = ["from: " + FROM_ADDRESS, | |
"subject: " + '*** Secret Santa pick for %s ***' & datetime.datetime.now().strftime('%Y'), | |
"to: " + to_email_address, | |
"mime-version: 1.0", | |
"content-type: text/html"] | |
headers = "\r\n".join(headers) | |
# TODO: customize this message for your gift exchange | |
body = (""" | |
<p> | |
Merry Christmas %s! | |
</p> | |
<p> | |
Your pick for this year's Secret Santa is <b>%s</b>. | |
</p> | |
<p> | |
As with other years, the kids from the Secret Santa exchange. | |
</p> | |
<p> | |
This year the limit is $___--not including shipping. Remember if you're sending something across the country, the last day for shipping is ___. | |
</p> | |
<p> | |
Happy holidays, | |
<br /> | |
Santa | |
</p> | |
""" % (to_name.capitalize(), match.capitalize())).replace('\t', '') | |
session.sendmail('%s <%s>' % (FROM_ADDRESS_NAME, FROM_ADDRESS), '%s' % to, headers + "\r\n\r\n" + body) | |
def generate_matches(): | |
matches = {} | |
remaining = ppl.keys() | |
for p, data in ppl.items(): | |
match = random.choice(remaining) | |
matched = True | |
if match == p: matched = False | |
if match in data['dont_match_with']: matched = False | |
if matched: | |
matches[p] = match | |
for i, r in enumerate(remaining): | |
if r == match: del(remaining[i]) | |
return matches if len(matches) == len(ppl.keys()) else None | |
def get_valid_run(test_only=False): | |
# trying to solve this elegantly is actually a waste of time | |
# it's much simpler and faster to re-run the matches if we | |
# don't have a valid set (e.g., p1 is matched with someone they | |
# shouldn't be) | |
num_of_matches = 0 | |
total_run = 100000 | |
final_selection = None | |
for i in range(total_run): | |
matches = generate_matches() | |
if matches: | |
num_of_matches += 1 | |
final_selection = matches | |
# let the user know how many runs we went through | |
print '%s %% (%s/%s)' % (num_of_matches / (total_run * 1.0) * 100, num_of_matches, total_run) | |
# create an anonymous mask to display the results | |
anon = {} | |
for i, k in enumerate(ppl.keys()): | |
anon[k] = string.letters[i] | |
# print out a final select key (it's anonymous) | |
for k, v in final_selection.items(): | |
print '%s\t%s' % (anon[k], anon[v]) | |
if not test_only: | |
send_msg(k, ppl[k]['email'], v) | |
if __name__ == "__main__": | |
arg_parser = create_argument_parser("Simple Secret Santa generator", { | |
'password': { 'help': 'The password for the outbound email account' }, | |
'test': { 'help': 'Create a test run for the generator. This will NOT send out emails', 'action': 'store_true' }, | |
}) | |
args, potential_ips = arg_parser.parse_known_args() | |
args = vars(args) | |
if args['password'] and len(args['password']) > 0: | |
# set the password for the email account | |
OUTBOUND_EMAIL_PASSWORD = args['password'] | |
if args['test']: | |
print "*** TEST RUN ***" | |
get_valid_run(test_only=True) | |
else: | |
get_valid_run() |
some errors:
Line 105: to
should read to_email_address
Line 103: match.capitalize()
should read match_name.capitalize()
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
FYI, this is queued up to use a Gmail account. Change line 72 if you want to use another provider