Build a Budget App Project, can't pass the test

Hello, I can’t pass through two instructions. Can anybody help?
Project title: Build a Budget App
Course: Scientific Computing with Python

Instructions:
23. create_spend_chart chart should have each category name written vertically below the bar. Each line should have the same length, each category should be separated by two spaces, with additional two spaces after the final category.
24. create_spend_chart should print a different chart representation. Check that all spacing is exact. Open your browser console with F12 for more details.

import math

class Category():
    def __init__(self, name):
        self.name = 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):
            self.ledger.append({'amount': -amount, 'description': description})
            return True
        return False
    
    def get_balance(self):
        return sum(item['amount'] for item in self.ledger)

    def transfer(self, amount, category):
        if self.check_funds(amount):
            self.withdraw(amount, f'Transfer to {category.name}')
            category.deposit(amount, f'Transfer from {self.name}')
            return True
        return False

    def check_funds(self, amount):
        return self.get_balance() >= amount

    def __str__(self):
        title = f'{self.name:*^30}\n'
        table = ''
        for item in self.ledger:
            table += f'{item["description"][:23]:23}{item["amount"]:>7.2f}\n'
        total = f'Total: {self.get_balance():.2f}'
        return title + table + total


def create_spend_chart(categories):
    # total spending - all categories
    total_spent = sum(sum(-item['amount'] for item in category.ledger if item['amount'] < 0) for category in categories)
    
    # percentage spent by each category
    percentages = [
        math.floor(sum(-item['amount'] for item in category.ledger if item['amount'] < 0) / total_spent * 10) * 10 for category in categories]
    
    chart = 'Percentage spent by category\n'
    
    # percentage column
    for i in range(100, -1, -10):
        line = f'{i:>3}| '
        for percent in percentages:
            line += 'o  ' if percent >= i else '   '
        chart += line + '\n'
    
    # horizontal line
    chart += '    ' + '-' * (len(categories) * 3 + 1) + '\n'
    
    # category names vertically
    max_len = max(len(category.name) for category in categories)
    for i in range(max_len):
        line = '     '  
        for category in categories:
            line += (category.name[i] + '  ') if i < len(category.name) else '   '
        chart += line.rstrip() + '\n'
    
    return chart.rstrip()


# Testing
food = Category('Food')
clothing = Category('Clothing')
entertainment = Category('Entertainment')
categories = [food, clothing, entertainment]

food.deposit(500, 'my first deposit')
food.withdraw(250, 'groceries')
food.transfer(50, entertainment)
food.withdraw(50, 'eating out')
clothing.deposit(500, 'deposit')
clothing.withdraw(250, 'new dress')
clothing.withdraw(50, 'hiking shoes')

print(food)
chart = create_spend_chart(categories)
print(chart)

1 Like

After going through the code, it seems there need to be two spaces when using \n , following line.rstrip(), before the return. Try modifying that and let us know if it works.

1 Like

Thank you very much for your answer. I did not expect such a quick response! I believe this is what you meant:

chart += line.rstrip() + '  \n'

I tried this, but it did not solve the issue.


Plus, I don’t know what to do with the next problem. I looked at developers’ tools. The printed output looks good, and everything is in its place. However, it prints all lines of food and then a chart as it is supposed to do, but then it is printed again. I don’t understand why.
Lastly, the word “business” appears in the error lines, which I have no idea where it came from. My categories are [food, clothing, and entertainment] in that order, but the output shows [business, food, entertainment]. I’m not sure what to do with this.





1 Like

The assertion error and diff 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

This is called a diff, and it shows you the differences between two files or blocks of code:

- 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

No worries. I’d suggest a few more changes in the methods:

  1. Deposit method: Use the or operator to simplify the handling of None for the description. This can be simplified to:
    'description': description or ''})
  2. Withdraw method: Apply a similar change as in the deposit method to improve readability.
  3. Balance method: Looks good as is.
  4. String method: I’d suggest using list comprehension to generate strings for each item. It’s a simpler approach.
  5. Create spend chart method: Try using dictionary comprehension here instead of loops. You can create the three dictionaries—spent_dict, total_spent, and percent_dict using this approach. It will be more concise.
  6. Chart output method: I’d suggest using list comprehension inside string concatenation to generate the bars for the chart. This is a simpler approach.
  7. Category name alignment: Try calculating max_len_category once, and then iterate over each index of category names. This will help eliminate duplicate code.
    Let us know if this works. Thanks.
1 Like

Finally, I did it! :tada: I rewrote some code as suggested (thank you, guys!).

After hours of frustration trying to figure out how to remove the " ’ " (that seemingly invisible apostrophe/string symbol I noticed in the developer tools), I finally understood that it was just marking where each line ended, showing me the empty spaces. :woman_facepalming:

I tried several approaches to remove those extra spaces, and after some experimentation, I ended up using the following solution:

chart += line + '  \n'
chart.rstrip()

return chart.rstrip() + '  '

It worked perfectly! Thanks again for all the help! :blush:

2 Likes