Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions students/aaron/homework_lesson6/mailroom_v4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#!/usr/bin/env python3

#-------------------------------------
# Assignment: mailroom (version 4, from lesson 6)
# Changelog:
# 2019-02-19,Aaron Devey,Created
#-------------------------------------

import re

donors = {'bob barker': {'donations': 2, 'total': 24456.24, 'name': 'Bob Barker'},
'roger rabbit': {'donations': 1, 'total': 4930.26, 'name': 'Roger Rabbit'},
'bruce lee': {'donations': 3, 'total': 52246.75, 'name': 'Bruce Lee'},
'frodo baggins': {'donations': 1, 'total': 1249.44, 'name': 'Frodo Baggins'},
'kermit the frog': {'donations': 2, 'total': 23475.20, 'name': 'Kermit the Frogg'}}

# prints a main menu
def show_main_menu():
print(generate_main_menu())

# moving the actual menu text into a testable def
def generate_main_menu():
menu = ("-" * 70) + "\n"
for number, func in sorted(menu_opts.items()):
menu += "{}. {}\n".format(number, menu_opts_text[func])
return menu

# gets a menu selection
def get_main_selection():
user_in = ""
while user_in == "":
show_main_menu()
user_in = input("Enter a menu number: ")
if user_in not in menu_opts.keys():
print("Invalid selection. Enter a menu selection:", list(menu_opts.keys()))
user_in = ""
return user_in

# used for testing, returns the entire donors dict
def get_donors():
return donors

# logic for user-interaction of a new donation
# moved testable pieces into different defs
def send_thankyou():
user_in = ""
names = [n.lower() for n in list(donors.keys())]
while user_in == "":
print("----------------------------------------------------------------")
user_in = input("Enter a full name or type 'list' for a list of names: ")
user_lower = user_in.lower()
if user_lower == 'list':
print("Donors: ")
for name in names:
print(" " + name)
user_in = ""
amount = 0
while amount == 0:
try:
amount = float(input("Enter a donation amount: "))
except:
amount = 0
print("-> ERROR: Please enter a valid floating point number.")
add_donation(user_in, amount)
output_thankyou(user_in, amount)

# adds a new donor
def new_donor(donor_name):
donors[donor_name.lower()] = {'donations': 0, 'total': 0, 'name': donor_name}
return donors[donor_name.lower()]

# adds a new donation for a donor
def add_donation(donor_name, amount):
lower_donor_name = donor_name.lower()
if lower_donor_name not in list(donors.keys()):
new_donor(donor_name)
donors[donor_name.lower()]['donations'] += 1
donors[donor_name.lower()]['total'] += amount
return donors[donor_name.lower()]

# print a report
def output_report():
print(generate_report())

def generate_report():
table_headerfmt = "{:<19s}|{:>15s} |{:>14s} |{:>15s}\n"
table_formatter = "{:<19s} ${:13.2f} {:14d} ${:13.2f}\n"
table_seperator = "-" * 68 + "\n"
generated_text = ""

generated_text += table_headerfmt.format("Donor Name", "Total Given", "Num Gifts", "Average Gift")
generated_text += table_seperator

# unpack to a list of lists
donor_list = [[donors[donor]['name'], donors[donor]['donations'], donors[donor]['total']] for donor in donors]

# sort the list
donor_list = sorted(donor_list, key = lambda x: x[2] * -1)

# add the list to the generated text
for donor in donor_list:
generated_text += table_formatter.format(donor[0], donor[2], donor[1], donor[2] / donor[1])

# return the generated report
return generated_text

# print a thank you for a recent donation
def output_thankyou(donor_name, latest_amount):
print(generate_thankyou(donor_name, latest_amount, True))

# moved the writing logic to a separate def, just printing in this one.
def write_letters():
for donor, file in write_letter_files().items():
print('>>> Wrote thank you note for {} to {}'.format(donor, file))

# write a thank you note to disk for a donor
# return a dict of {donor_name: donor_file}
def write_letter_files():
files_written = {}
for donor_name in donors.keys():
# convert any non-alphanumeric characters to _ for the filename
donor_file = re.sub(r"[^a-zA-Z0-9_-]+", "_", donor_name) + ".txt"

note = generate_thankyou(donor_name)
f = open(donor_file, 'w')
f.write(note)
f.close()
files_written[donor_name] = donor_file
return files_written

# generate a thank you note for a donor
def generate_thankyou(donor_name, latest_amount=0, recent=False):
lower_donor_name = donor_name.lower()
donations_total = donors[lower_donor_name]["total"]
donations_count = donors[lower_donor_name]["donations"]
cased_donor_name = donors[lower_donor_name]["name"]
format_values = {'donations_total': donations_total,
'donations_count': donations_count,
'donor_name': cased_donor_name,
'latest_amount': latest_amount}
if recent:
template = '''----------------------------------------------------------------------
Dear {donor_name},
Thank you for your generous donation of {latest_amount:.2f}!
That brings your total of {donations_count} donation(s) to ${donations_total:.2f}
Sincerely,
-Me
'''
else:
template = '''----------------------------------------------------------------------
Dear {donor_name},
Thank you for all {donations_count} of your generous donations for a total of {donations_total:.2f}!
We will put the money to good use.
Sincerely,
-Me
'''
letter = template.format(**format_values)
return(letter)

# the main loop
def main():
selection = "2"
while menu_opts[selection] != quit:
selection = get_main_selection()
menu_opts[selection]()

# a dict for mapping user selection to functions
menu_opts = {'1': send_thankyou,
'2': output_report,
'3': write_letters,
'4': quit}
menu_opts_text = {send_thankyou: "Send a Thank You to a single donor.",
output_report: "Create a report.",
write_letters: "Send letters to all donors.",
quit: "Quit."}

if __name__ == '__main__':
main()
123 changes: 123 additions & 0 deletions students/aaron/homework_lesson6/mailroom_v4_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
#
#-------------------------------------
# Assignment: mailroom tests (mailroom version 4, from lesson 6)
# Description: This file contains tests for mailroom_v4.py
# Changelog:
# 2019-02-19,Aaron Devey,Created
#-------------------------------------
#
#

import pytest
import glob
from mailroom_v4 import generate_main_menu, generate_report, generate_thankyou, write_letter_files, new_donor, add_donation, get_donors


def test_generate_main_menu_text():
test_text = '''----------------------------------------------------------------------
1. Send a Thank You to a single donor.
2. Create a report.
3. Send letters to all donors.
4. Quit.
'''
assert(generate_main_menu() == test_text)

def test_generate_report_text():
test_text = '''Donor Name | Total Given | Num Gifts | Average Gift
--------------------------------------------------------------------
Bruce Lee $ 52246.75 3 $ 17415.58
Bob Barker $ 24456.24 2 $ 12228.12
Kermit the Frogg $ 23475.20 2 $ 11737.60
Roger Rabbit $ 4930.26 1 $ 4930.26
Frodo Baggins $ 1249.44 1 $ 1249.44
'''
assert(generate_report() == test_text)

def test_generate_thankyou_report_text():
test_text = '''----------------------------------------------------------------------
Dear Bruce Lee,
Thank you for all 3 of your generous donations for a total of 52246.75!
We will put the money to good use.
Sincerely,
-Me
'''
assert(generate_thankyou("Bruce Lee") == test_text)

def test_generate_thankyou_new_donation():
test_text = '''----------------------------------------------------------------------
Dear Bruce Lee,
Thank you for your generous donation of 232.12!
That brings your total of 3 donation(s) to $52246.75
Sincerely,
-Me
'''
assert(generate_thankyou("Bruce Lee", 232.12, True) == test_text)

def test_generate_thankyou_unknown_donor():
with pytest.raises(KeyError):
generate_thankyou("Adam West")
with pytest.raises(KeyError):
generate_thankyou("Adam West", 1232.12, True)

def test_write_letter_files():
test_written = {'bob barker': 'bob_barker.txt',
'bruce lee': 'bruce_lee.txt',
'frodo baggins': 'frodo_baggins.txt',
'kermit the frog': 'kermit_the_frog.txt',
'roger rabbit': 'roger_rabbit.txt'}
assert(write_letter_files() == test_written)

def test_new_donor():
test_donor = {'name': 'Adam West', 'total': 0, 'donations': 0}
test_all_donors = {'adam west': {'donations': 0, 'name': 'Adam West', 'total': 0},
'bob barker': {'donations': 2, 'name': 'Bob Barker', 'total': 24456.24},
'bruce lee': {'donations': 3, 'name': 'Bruce Lee', 'total': 52246.75},
'frodo baggins': {'donations': 1, 'name': 'Frodo Baggins', 'total': 1249.44},
'kermit the frog': {'donations': 2, 'name': 'Kermit the Frogg', 'total': 23475.2},
'roger rabbit': {'donations': 1, 'name': 'Roger Rabbit', 'total': 4930.26}}
assert(new_donor('Adam West') == test_donor)
assert(get_donors() == test_all_donors)

def test_add_donation():
test_donor = {'donations': 1, 'name': 'Adam West', 'total': 1122.33}
test_all_donors = {'adam west': {'donations': 1, 'name': 'Adam West', 'total': 1122.33},
'bob barker': {'donations': 2, 'name': 'Bob Barker', 'total': 24456.24},
'bruce lee': {'donations': 3, 'name': 'Bruce Lee', 'total': 52246.75},
'frodo baggins': {'donations': 1, 'name': 'Frodo Baggins', 'total': 1249.44},
'kermit the frog': {'donations': 2, 'name': 'Kermit the Frogg', 'total': 23475.2},
'roger rabbit': {'donations': 1, 'name': 'Roger Rabbit', 'total': 4930.26}}
assert(add_donation('Adam West', 1122.33) == test_donor)
assert(get_donors() == test_all_donors)

def test_add_donation_new_donor():
test_donor = {'donations': 1, 'name': 'Han Solo', 'total': 3322.11}
test_all_donors = {'adam west': {'donations': 1, 'name': 'Adam West', 'total': 1122.33},
'bob barker': {'donations': 2, 'name': 'Bob Barker', 'total': 24456.24},
'bruce lee': {'donations': 3, 'name': 'Bruce Lee', 'total': 52246.75},
'frodo baggins': {'donations': 1, 'name': 'Frodo Baggins', 'total': 1249.44},
'kermit the frog': {'donations': 2, 'name': 'Kermit the Frogg', 'total': 23475.2},
'roger rabbit': {'donations': 1, 'name': 'Roger Rabbit', 'total': 4930.26},
'han solo': test_donor}

assert(add_donation('Han Solo', 3322.11) == test_donor)
assert(get_donors() == test_all_donors)

def test_written_file_outputs():
test_written = {'adam west': 'adam_west.txt',
'bob barker': 'bob_barker.txt',
'bruce lee': 'bruce_lee.txt',
'frodo baggins': 'frodo_baggins.txt',
'han solo': 'han_solo.txt',
'kermit the frog': 'kermit_the_frog.txt',
'roger rabbit': 'roger_rabbit.txt'}
assert(write_letter_files() == test_written)

def test_written_file_contents():
test_first_line = "-" * 70 + "\n"
test_second_line = "Dear Adam West,\n"
f = open("adam_west.txt", "r")
actual_first_line = f.readline()
actual_second_line = f.readline()
assert(actual_first_line == test_first_line)
assert(actual_second_line == test_second_line)