Build a Budget App Project - Help with errors from freecodecamp

Tell us what’s happening:

The code works perfectly fine and the outputs match exactly (from what I can tell) what it’s asking for, yet no matter what, I’m still getting the same two failures from freecodecamp saying:
“Failed: Printing a Category instance should give a different string representation of the object.
Failed: create_spend_chart should print a different chart representation. Check that all spacing is exact.”
Anyone have any ideas on how to fix it? I have also tried calling and not calling the functions. Many thanks!

Your code so far

class Category:
    def __init__(self,name):
        self.name = name # Name, so like 'food'
        self.ledger = [] # List of all expenses
        self.withdrawls = []

    def __str__(self):
         # Writes the title
        budget = '' 
        star_length = 30 - len(self.name)
        left_side = (star_length // 2) + (star_length % 2) # Finds one length, and adds the remainder so that the length of the title adds to 30 characters
        right_side = star_length - left_side

        # Adds the stars to the string
        for star in range(left_side):
            budget += '*'
        budget += self.name
        for star in range(right_side):
            budget += '*'
        
        for expense in self.ledger:
            spaces = ''
            description = expense['description']
            amount = round(expense['amount'],2)

            # Truncates the strings
            new_desc = self.truncate_string(description,23)
            new_amnt = self.truncate_string(str(amount),7)

            space_length = 30 - (len(new_desc) + len(new_amnt))

            # Adds spaces 
            for space in range(space_length):
                spaces += ' '

            # Adds line to the string
            budget += f'\n{new_desc}{spaces}{new_amnt}'
        
        # Repeats previous steps except for the total line
        spaces = ''
        total_amnt = str(round(self.get_balance(),2))
        space_length = 30 - (len('Total: ') + len(total_amnt))

        for space in range(space_length):
            spaces += ' '
            
        total = f'\nTotal: {spaces}{total_amnt}'
        budget += total
        
        return budget

    # Truncates strings over a certain length
    def truncate_string(self,string,length):
        return string[:length]

    def get_balance(self):
        total_budget = 0 # Resets the total budget
        for expenses in self.ledger:
            total_budget += expenses['amount']
        return total_budget
        
    # Checks if there are enough funds 
    def check_funds(self,amount):
        if amount > self.get_balance():
            return False
        else:
            return True

    def deposit(self,amount,description=''):
        expense = {'amount': amount, 'description': description} # Formats it into a dictionary
        self.ledger.append(expense) # Adds the expense to the ledger list

    def withdraw(self,amount,description=''):
        if self.check_funds(amount): # If there is enough money
            expense = {'amount': -amount, 'description': description} # Formats it into a dictionary 
            self.ledger.append(expense) # Adds the expense to the ledger list
            self.withdrawls.append(expense)
            return True
        else:
            return False
    
    def transfer(self,amount,category):
        if self.check_funds(amount): # If there is enough money for transfer
            self.withdraw(amount, f'Transfer to {category.name}')
            category.deposit(amount, f'Transfer from {self.name}')
            return True
        else:
            return False

def create_spend_chart(categories):

    total_spent = 0
    spent_by_category = {}
    percentage_by_category = {}
    categories_list = []

    line1 = '100|'
    line2 = ' 90|'
    line3 = ' 80|'
    line4 = ' 70|'
    line5 = ' 60|'
    line6 = ' 50|'
    line7 = ' 40|'
    line8 = ' 30|'
    line9 = ' 20|'
    line10 = ' 10|'
    line11 = '  0|'
    line12 = '    '

    for category in categories:
        categories_list.append(category.name)

    # Finds the total and individual expendature
        category_spent = 0
        for withdrawl in category.withdrawls: # For each withdrawl in the list
            category_spent += withdrawl['amount'] # Totals it 
        total_spent += category_spent # Adds the total the the total_spent
        spent_by_category[category.name] = category_spent # Assings the category and amount spent to a dictionary for later use

    max_length = len(max(categories_list, key=len)) # Finds the category with the longest name length
    name_lines = ['   ' for _ in range(max_length)] # Lines for the names of the categories

    for category in categories: # Must let the previous code run for all categories before this

        # Adds the names into a list per each line and adds spaces
        for i in range(max_length):
            if i < len(category.name):
                name_lines[i] += f'  {category.name[i]}'
            else:
                name_lines[i] += '   '

        # Finds the percentage of each category, and rounds it down to the nearest 10 using integer division
        percentage = ((((spent_by_category[category.name] / total_spent) * 100) // 10) *10)
        percentage_by_category[category.name] = percentage

        # Creates the bar chart
        if category == categories[0]:
            spaces = ' '
        else:
            spaces = '  '
        if percentage_by_category[category.name] == 100:
            line1 += f'{spaces}o'
        if percentage_by_category[category.name] >= 90:
            line2 += f'{spaces}o'
        if percentage_by_category[category.name] >= 80:
            line3 += f'{spaces}o'
        if percentage_by_category[category.name] >= 70:
            line4 += f'{spaces}o'
        if percentage_by_category[category.name] >= 60:
            line5 += f'{spaces}o'
        if percentage_by_category[category.name] >= 50:
            line6 += f'{spaces}o'
        if percentage_by_category[category.name] >= 40:
            line7 += f'{spaces}o'
        if percentage_by_category[category.name] >= 30:
            line8 += f'{spaces}o'
        if percentage_by_category[category.name] >= 20:
            line9 += f'{spaces}o'
        if percentage_by_category[category.name] >= 10:
            line10 += f'{spaces}o'
        if percentage_by_category[category.name] >= 0:
            line11 += f'{spaces}o'

        line12 += '---'
    line0 = 'Percentage spent by category'
    line12 = f'{line12}-'
    name_lines = '\n'.join(name_lines)

    return f'{line0}\n{line1}\n{line2}\n{line3}\n{line4}\n{line5}\n{line6}\n{line7}\n{line8}\n{line9}\n{line10}\n{line11}\n{line12}\n{name_lines}'

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6.1 Safari/605.1.15

Challenge Information:

Build a Budget App Project - Build a Budget App Project

Did you try printing your output and seeing if it’s exactly the same? For the chart make sure the spacing is exactly the same, you can highlight the chart example to see the spacing.

Also, you can press F12 and check the dev tools console in the browser for a more detailed error that wil tell you exactly what’s different.

[Warning] F (pyodide.asm.js, line 9)
[Warning] ====================================================================== (pyodide.asm.js, line 9)
[Warning] FAIL: test_create_spend_chart (test_module.UnitTests.test_create_spend_chart) (pyodide.asm.js, line 9)
[Warning] ---------------------------------------------------------------------- (pyodide.asm.js, line 9)
[Warning] Traceback (most recent call last): (pyodide.asm.js, line 9)
[Warning]   File "/home/pyodide/test_module.py", line 23, in test_create_spend_chart (pyodide.asm.js, line 9)
[Warning]     self.assertEqual(actual, expected, 'Expected different chart representation. Check that all spacing is exact.') (pyodide.asm.js, line 9)
[Warning] AssertionError: 'Perc[33 chars]     \n 90|        \n 80|        \n 70|    o  [293 chars]   t' != 'Perc[33 chars]       \n 90|          \n 80|          \n 70| [341 chars] t  ' (pyodide.asm.js, line 9)
[Warning]   Percentage spent by category (pyodide.asm.js, line 9)
[Warning] - 100|         (pyodide.asm.js, line 9)
[Warning] + 100|           (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  90|         (pyodide.asm.js, line 9)
[Warning] +  90|           (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  80|         (pyodide.asm.js, line 9)
[Warning] +  80|           (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  70|    o    (pyodide.asm.js, line 9)
[Warning] +  70|    o      (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  60|    o    (pyodide.asm.js, line 9)
[Warning] +  60|    o      (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  50|    o    (pyodide.asm.js, line 9)
[Warning] +  50|    o      (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  40|    o    (pyodide.asm.js, line 9)
[Warning] +  40|    o      (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  30|    o    (pyodide.asm.js, line 9)
[Warning] +  30|    o      (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  20|    o  o (pyodide.asm.js, line 9)
[Warning] +  20|    o  o   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -  10|    o  o (pyodide.asm.js, line 9)
[Warning] +  10|    o  o   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -   0| o  o  o (pyodide.asm.js, line 9)
[Warning] +   0| o  o  o   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning]       ---------- (pyodide.asm.js, line 9)
[Warning] -      B  F  E (pyodide.asm.js, line 9)
[Warning] +      B  F  E   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -      u  o  n (pyodide.asm.js, line 9)
[Warning] +      u  o  n   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -      s  o  t (pyodide.asm.js, line 9)
[Warning] +      s  o  t   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -      i  d  e (pyodide.asm.js, line 9)
[Warning] +      i  d  e   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -      n     r (pyodide.asm.js, line 9)
[Warning] +      n     r   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -      e     t (pyodide.asm.js, line 9)
[Warning] +      e     t   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -      s     a (pyodide.asm.js, line 9)
[Warning] +      s     a   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -      s     i (pyodide.asm.js, line 9)
[Warning] +      s     i   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -            n (pyodide.asm.js, line 9)
[Warning] +            n   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -            m (pyodide.asm.js, line 9)
[Warning] +            m   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -            e (pyodide.asm.js, line 9)
[Warning] +            e   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -            n (pyodide.asm.js, line 9)
[Warning] +            n   (pyodide.asm.js, line 9)
[Warning] ?             ++ (pyodide.asm.js, line 9)
[Warning] -            t+            t  ?             ++ (pyodide.asm.js, line 9)
[Warning]  : Expected different chart representation. Check that all spacing is exact. (pyodide.asm.js, line 9)
[Warning]  (pyodide.asm.js, line 9)
[Warning] ---------------------------------------------------------------------- (pyodide.asm.js, line 9)
[Warning] Ran 1 test in 0.020s (pyodide.asm.js, line 9)
[Warning]  (pyodide.asm.js, line 9)
[Warning] FAILED (failures=1) (pyodide.asm.js, line 9)

This is what the console is saying, however if I input this:

food = Category('Food')
food.deposit(1000, 'deposit')
food.withdraw(100.15, 'groceries')
food.withdraw(150.89, 'restaurant and more food for dessert')
clothing = Category('Clothing')
food.transfer(500, clothing)
clothing.withdraw(300,'idk')
auto = Category('Auto')
food.transfer(200,auto)
auto.deposit(1000,'idk')
auto.withdraw(400,'idk')
idk = Category('idk')
auto.transfer(500,idk)
idk.withdraw(450,'help')
print(create_spend_chart([food,clothing,auto,idk]))

I get this output: (the ‘by’ is not bold in the terminal)

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

And nothing appears to be wrong?? I’m still unsure of the issue with the create_spend_chart function, as well as this fail: " Failed:Printing a Category instance should give a different string representation of the object."

With the " Failed: Printing a Category instance should give a different string representation of the object.", this is my output, and nothing appears to be wrong either…

*************Food*************
deposit                1000.00
groceries               -10.15
restaurant and more foo -15.89
Transfer to Clothing    -50.00
Total:                  923.96

I’ve just changed the total to make it not right aligned as is shown in the example, however I am still receiving the same failure messages

Work on one problem at a time.

If you highlight the chart, you can see differences in the spaces at the end of the line.
Screenshot 2024-08-16 073237
Screenshot 2024-03-10 211440

See how the example chart is consistent and squared off?

1 Like

An assertion error gives you a lot of information to track down a problem. For example:

AssertionError: 'Year' != 'Years'
- Year
+ Years
?     +

Your output comes first, and the output that the test expects is second.

AssertionError: ‘Year’ != ‘Years’

Your output: Year does not equal what’s expected: Years

- Year
+ Years
?     +

- Dash indicates the incorrect output
+ Plus shows what it should be
? The Question mark line indicates the place of the character that’s different between the two lines. Here a + is placed under the missing s .

Here’s another example:

E       AssertionError: Expected different output when calling "arithmetic_arranger()" with ["3801 - 2", "123 + 49"]
E       assert '  3801      123    \n   - 2     + 49    \n------    -----    \n' == '  3801      123\n-    2    +  49\n------    -----'
E         -   3801      123
E         +   3801      123    
E         ?                ++++
E         - -    2    +  49
E         +    - 2     + 49    
E         - ------    -----
E         + ------    -----    
E         ?                +++++

The first line is long, and it helps to view it as 2 lines in fixed width characters, so you can compare it character by character:

'  3801      123    \n   - 2     + 49    \n------    -----    \n'
'  3801      123\n-    2    +  49\n------    -----'

Again, your output is first and the expected output is second. Here it’s easy to see extra spaces or \n characters.

E         -   3801      123
E         +   3801      123    
E         ?                ++++

Here the ? line indicates 4 extra spaces at the end of a line using four + symbols. Spaces are a little difficult to see this way, so it’s useful to use both formats together.

I hope this helps interpret your error!

1 Like

Formatting needs to be exactly the same:

*************Food*************
initial deposit        1000.00
groceries               -10.15
restaurant and more foo -15.89
Transfer to Clothing    -50.00
Total: 923.96
1 Like

Your output vs expected:

'Perc[33 chars] \n 90| \n 80| \n 70| o [293 chars] t' !=
'Perc[33 chars] \n 90| \n 80| \n 70| [341 chars] t '

Where is says “[33 chars]” means the next 33 characters are the same.

1 Like

Thank you so much!! This has cleared it all up for me.

1 Like

May I ask how you managed to highlight it like this?

I just selected it with the mouse.

Screenshot 2024-08-17 071549

1 Like