@@ -48,6 +48,20 @@ def find_donor(name):
4848 return donor_db .get (key )
4949
5050
51+ def add_donor (name ):
52+ """
53+ add a new donor to the donr db
54+
55+ :param: the name of the donor
56+
57+ :returns: the new Donor data structure
58+ """
59+ name = name .strip ()
60+ donor = (name , [])
61+ donor_db [name .lower ()] = donor
62+ return donor
63+
64+
5165def main_menu_selection ():
5266 """
5367 Print out the main application menu and then read the user input.
@@ -96,56 +110,65 @@ def send_thank_you():
96110 else :
97111 break
98112
99- # Now prompt the user for a donation amount to apply. Since this is also an exit
100- # point to the main menu, we want to make sure this is done before mutating the db
101- # list object .
113+ # Now prompt the user for a donation amount to apply. Since this is
114+ # also an exit point to the main menu, we want to make sure this is
115+ # done before mutating the db .
102116 while True :
103117 amount_str = raw_input ("Enter a donation amount (or 'menu' to exit)> " ).strip ()
104118 if amount_str == "menu" :
105119 return
106120 # Make sure amount is a valid amount before leaving the input loop
107- amount = float (amount_str )
108- # extra check here -- unliley that someone will type "NaN", but
109- # it IS possible, and it is a valid floating point number:
110- # http://en.wikipedia.org/wiki/NaN
111- if math .isnan (amount ) or math .isinf (amount ) or round (amount , 2 ) == 0.00 :
121+ try :
122+ amount = float (amount_str )
123+ # extra check here -- unlikely that someone will type "NaN", but
124+ # it IS possible, and it is a valid floating point number:
125+ # http://en.wikipedia.org/wiki/NaN
126+ if math .isnan (amount ) or math .isinf (amount ) or round (amount , 2 ) == 0.00 :
127+ raise ValueError
128+ # in this case, the ValueError could be raised by the float() call, or by the NaN-check
129+ except ValueError :
112130 print "error: donation amount is invalid\n "
113131 else :
114132 break
115133
116- # If this is a new user, ensure that the database has the necessary data structure.
134+ # If this is a new user, ensure that the database has the necessary
135+ # data structure.
117136 donor = find_donor (name )
118137 if donor is None :
119- donor = (name , [])
120- donor_db .append ( donor )
138+ donor = add_donor (name )
121139
122140 # Record the donation
123141 donor [1 ].append (amount )
124142 print gen_letter (donor )
125143
126144
127145def sort_key (item ):
146+ ## used to sort on name in donor_db
128147 return item [1 ]
129148
130149
131- def print_donor_report ():
150+ def generate_donor_report ():
132151 """
133152 Generate the report of the donors and amounts donated.
153+
154+ :returns: the donor report as a string.
134155 """
135156 # First, reduce the raw data into a summary list view
136157 report_rows = []
137- for (name , gifts ) in donor_db :
158+ for (name , gifts ) in donor_db . values () :
138159 total_gifts = sum (gifts )
139160 num_gifts = len (gifts )
140161 avg_gift = total_gifts / num_gifts
141162 report_rows .append ( (name , total_gifts , num_gifts , avg_gift ) )
142163
143164 #sort the report data
144165 report_rows .sort (key = sort_key )
145- print "%25s | %11s | %9s | %12s" % ("Donor Name" ,"Total Given" ,"Num Gifts" ,"Average Gift" )
146- print "-" * 66
166+ report = []
167+ report .append ("%25s | %11s | %9s | %12s" % ("Donor Name" ,"Total Given" ,"Num Gifts" ,"Average Gift" ) )
168+ report .append ("-" * 66 )
147169 for row in report_rows :
148- print "%25s %11.2f %9i %12.2f" % row
170+ report .append ("%25s %11.2f %9i %12.2f" % row )
171+ return "\n " .join (report )
149172
150173if __name__ == "__main__" :
151174 running = True
@@ -154,7 +177,7 @@ def print_donor_report():
154177 if selection is "1" :
155178 send_thank_you ()
156179 elif selection is "2" :
157- print_donor_report ()
180+ print generate_donor_report ()
158181 elif selection is "3" :
159182 running = False
160183 else :
0 commit comments