def print_spender_data(): """Reports out the current spending data.""" print('\nSPENDER DATA\n==============') print('Total spending: ${:,.2f} across {} transactions'.format( Spender.get_total_spending(), Spender.get_num_transactions())) print('Average spending across {} spenders: ${:,.2f}'.format( Spender.get_num_spenders(), Spender.get_avg_spending()), end='\n') for name in spenders.keys(): print('') print(spenders[name])
def print_payback_instructions(): """The below prints out instructions for all Spender members who were added to the 'owers' set of names - those with negative deviations from the average spending. This function iterates through each Spender member whose name was added to the owers list, gets their deviation, and divides it by the number of Spender members whose names were added to the 'owed' set of names. Thus, each ower is to pay an equal amount of what they owe to each Spender member who is owed. The conditions in the function govern proper syntax depending on how many are in each list.""" num_owed = len(Spender.get_owed_spenders()) print('\nPAYBACK INSTRUCTIONS\n======================') if num_owed > 0: for ower_name in Spender.get_owing_spenders(): print(ower_name, end=': pay ') for index, owed_name in enumerate(Spender.get_owed_spenders()): pay_to_each = ( abs(spenders[ower_name].get_spender_deviation()) / num_owed) if num_owed == 1: print(owed_name + ' ${:,.2f}'.format(pay_to_each)) elif num_owed == 2: if not index == num_owed - 1: print(owed_name, end=' ') else: print('and ' + owed_name + ' ${:,.2f} each'.format(pay_to_each)) elif num_owed > 2: if not index == num_owed - 1: print(owed_name, end=', ') else: print('and ' + owed_name + ' ${:,.2f} each'.format(pay_to_each)) else: print('Nobody owes anyone anything! Even Steven!')
def update_spender_records(expenses_df): """Each time this runs, it has been passed a new dataframe of expenses to add to the spenders' records. It iterates over the new spending records, looking for Spender names and expenses. When it finds a record with a new spender name, it instantiates them as a new member of the Spender class, and saves them into the dictionary of spenders by their name as a key, with the corresponding first found transaction as the initializing balance. For any records for existing spenders, it calls an increment method to add the found value for the transaction to the corresponding spender object's balance attribute. This is implemented via pandas, which handles the excel spreadsheet as an iterable dataframe.""" for index, row in expenses_df.iterrows(): name = row['Spender'] amount = row['Amount'] # check the keylist for spender name. If found name not already # in dictionary, instantiate new Spender member with starting # balance of their first transaction # also, track number of transactions found for recordkeeping if name not in spenders.keys(): spenders.update({name: Spender(name, s_bal=amount)}) Spender.increment_num_spenders() Spender.increment_num_transactions() # if the name in this row's spender column is already there, process # that line's data instead, and increment that Spender's balance # also, count number of transactions for recordkeeping elif name in spenders.keys(): Spender.increment_spender_balance(spenders[name], amount) Spender.increment_num_transactions() # finally, add the amount found on this line to the total spending # for all spenders in the class-level attribute total_spending Spender.increment_total_spending(amount) # get average spending (total transactions / number of spenders) Spender.set_avg_spending() # in case run before, reset the names of who owes and who is owed # before re-populating based on the latest spending data Spender.clear_owed_spenders() Spender.clear_owing_spenders() # iterate through each Spender member, and set its deviation (distance # from the average). If positive deviation, they are owed that money; # if negative, they owe that money to others. for name in spenders.keys(): spenders[name].set_spender_deviation() # if deviation positive, add to set of 'owed' names if spenders[name].get_spender_deviation() > 0: Spender.add_owed_spender(name) # if negative, add to set of 'owers' names elif spenders[name].get_spender_deviation() < 0: Spender.add_owing_spender(name)
# badvalues_df = pd.read_excel(file) # # assert validate_data(badvalues_df) is ValueError, 'Erroneously allowing non-floats' file = 'test_record.xlsx' df = pd.read_excel(file) assert not validate_data(df) is False, 'Erroneously disallowing good data' try: update_spender_records(df) except NameError: raise AssertionError('Dataframe not found.') # total in spreadsheet is 100 + 10 + 100 + 10 + 80 = 300.0; test for that assert Spender.get_total_spending() == 300.0 # test that class is reading names from file correctly assert spenders['Ladybug'].get_spender_name() == 'Ladybug' # test member balances: assert spenders['Ladybug'].get_spender_balance() == 20.0 assert spenders['Parrot'].get_spender_balance() == 200.0 assert spenders['Octopus'].get_spender_balance() == 80.0 # test number of spenders assert Spender.get_num_spenders() == 3 # test number of transactions assert Spender.get_num_transactions() == 5