Scientific Computing with Python Projects - Budget App

Tell us what’s happening:

I don’t understand what is wrong with my output. Everything looks exactly the same, maybe it’s some trailing whitespace?

This is the FAIL output

Percentage spent by category
100|          
 90|          
 80|          
 70|          
 60| o        
 50| o        
 40| o        
 30| o        
 20| o  o     
 10| o  o  o  
  0| o  o  o  
    ----------
     F  C  A  
     o  l  u  
     o  o  t  
     d  t  o  
        h     
        i     
        n     
        g     

.F.........
======================================================================
FAIL: test_create_spend_chart (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-budget-app/test_module.py", line 102, in test_create_spend_chart
    self.assertEqual(actual, expected, 'Expected different chart representation. Check that all spacing is exact.')
AssertionError: 'Perc[364 chars]         m  \n           e  \n           n  \n           t  \n' != 'Perc[364 chars]         m  \n           e  \n           n  \n           t  '
  Percentage spent by category
  100|          
   90|          
   80|          
   70|    o     
   60|    o     
   50|    o     
   40|    o     
   30|    o     
   20|    o  o  
   10|    o  o  
    0| o  o  o  
      ----------
       B  F  E  
       u  o  n  
       s  o  t  
       i  d  e  
       n     r  
       e     t  
       s     a  
       s     i  
             n  
             m  
             e  
             n  
-            t  
?               -
+            t   : Expected different chart representation. Check that all spacing is exact.

----------------------------------------------------------------------
Ran 11 tests in 0.002s

FAILED (failures=1)

This is my code:

class Category:
    def __init__(self, category_name):
        self.category = category_name 
        self.ledger = []
    
    def deposit(self, amount, description=""):
        self.ledger.append({"amount": amount, "description": description})

    def withdraw(self, amount, description=""):
        if self.check_funds(amount) == True:
            self.ledger.append({"amount": -amount, "description": description})
            return True
        else:
            return False
        
    def get_balance(self):
        balance = 0
        for box_values in self.ledger:
            balance += box_values['amount']
        return balance
    
    def transfer(self, amount, amount_to_object): 
        if self.check_funds(amount) == True: 
            self.withdraw(amount, f"Transfer to {amount_to_object.category}")
            amount_to_object.ledger.append({"amount": amount, "description": f"Transfer from {self.category}"})
            return True
        else:
            return False
    def check_funds(self, amount): #if/el could be replaced with: return self.get.balance()-amount < 0
        if self.get_balance() -amount < 0: #eller return self.get_balance() >= amount //True om balance är större eller lika som amount!
            return False 
        else:
            return True

    def __str__(self):
        output = self.category.center(30, '*') + '\n'

        for item in self.ledger:
            desc = item['description'][:23]
            amt = "{:.2f}".format(item['amount']).rjust(30 - len(desc))
            output += desc + amt + '\n'

        output += "Total: {:.2f}".format(self.get_balance())
        return output


def create_spend_chart(list_of_category_objects):
    list_of_total_withdraw_per_category = []
    for the_number_of_instances in list_of_category_objects: #For the amount objects in list
        total_category_expenditure = 0
        for one_line_dicts in the_number_of_instances.ledger: #For the length of the ledger in the object
            if one_line_dicts['amount'] < 0:
                total_category_expenditure += -one_line_dicts['amount'] #it's a negative amount so - before it will make  - - = +
        #Saved as a list of dictionaries of 
        list_of_total_withdraw_per_category.append({"category": the_number_of_instances.category, "total" : total_category_expenditure})
    grand_total = sum(d["total"] for d in list_of_total_withdraw_per_category) #d is a box, can be called anything, iterates over each (d)ictionary
    #*** Look below to find a shorter more python-esque way of writing this code

    #add a new key value pair to each dictionary in the list, percentage of total spending/withdraws
    for the_number_of_dictionaries in list_of_total_withdraw_per_category:
        pct_of_total = (the_number_of_dictionaries['total'] / grand_total) * 100
        the_number_of_dictionaries['pct_of_total'] = pct_of_total

    #Now for the printing!
    output = "Percentage spent by category\n"
    to_zero = 100  # Assuming to_zero starts at 100
    max_padding = len(str(to_zero))
    while to_zero >= 0:
        current_padding = max_padding -len(str(to_zero))
        output += " " * current_padding + f"{to_zero}| "  # Print the current value of to_zero followed by a vertical bar
        for x in range(len(list_of_total_withdraw_per_category)):  # Iterate over the indices of the categories list
            if list_of_total_withdraw_per_category[x]['pct_of_total'] >= to_zero:
                output += "o  "  # Print 'o' with spaces, without a newline
            else:
                output += "   "  # Print spaces only, without a newline
        output += "\n"  # Print a newline character after the inner loop completes
        to_zero -= 10  # Decrement to_zero by 10
    #now print the "------" line
    output += "    -" #The start of it
    for x in range(len(list_of_total_withdraw_per_category)): 
        output += "---" #The length based on the list length
    output += "\n"
    #Now we find which category name is the longest
    longest_length = 0
    for dictionaries in list_of_total_withdraw_per_category:
        string_value = dictionaries['category']
        longest_length = max(longest_length, len(string_value))
    #and print!
    for y in range(longest_length):
        output += "     "
        for x in range(len(list_of_total_withdraw_per_category)):
            try: 
                char = list_of_total_withdraw_per_category[x]['category'][y]
            except IndexError: 
                char = " "
            output += f"{char}  "
        output += "\n"

    return output




























#***Så här kan man också lösa det, föredras, faktiskt. Men skillz osv.
    #def create_spend_chart(categories):
    #    totals_per_category = [
    #        {
    #            "category": category.category, 
    #            "total": sum(-item['amount'] for item in category.ledger if item['amount'] < 0)
    #        } 
    #        for category in categories
    #    ]
    #   grand_total = sum(d["total"] for d in totals_per_category)


Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36

Challenge Information:

Scientific Computing with Python Projects - Budget App

You’re correct: it’s 1 trailing whitespace

The last 3 lines in the error show a diff:
the line starting with a- shows your output line "t "
the line starting with a ? shows the difference, the _ indicating a space
the line starting with + shows the correct output

This part is also useful:

'Perc[364 chars]         m  \n           e  \n           n  \n           t  \n' != 
'Perc[364 chars]         m  \n           e  \n           n  \n           t  '

Your output is first, and the expected output is second. You can see an extra newline character at the end.