Build a Budget App - Build a Budget App

Tell us what’s happening:

I couldn’t get past tests 17-24. These tests are constantly failing due to some attribute errors. My code gives the correct output in the terminal. I tried using the browser console (F12). It seems that there is no spacing error. The console shows some attribute errors that I don’t fully understand. These errors are all associated with the function named create_spend_chart(). So, Someone please help me out.

Your code so far

class Category:
    def __init__(self, name):
        self.name = name
        self.ledger = []
        self.current_balance = 0

    def deposit(self, amount, description=''):
        self.current_balance += amount
        self.ledger.append({'amount': amount, 'description': description})
    
    def withdraw(self, amount, description=''):
        if self.check_funds(amount):
            self.current_balance -= amount
            self.ledger.append({'amount': - amount, 'description': description})
            return True
        else:
            return False
    
    def get_balance(self):
        return self.current_balance
    
    def transfer(self, amount, destination):
        if self.check_funds(amount):
            self.withdraw(amount, f"Transfer to {destination.name}")
            destination.deposit(amount, f'Transfer from {self.name}')
            return True
        else:
            return False
    
    def check_funds(self, amount):
        if amount > self.current_balance:
            return False
        else:
            return True
        
    def __str__(self):
        ledger_view = self.name.title().center(30, '*')
        for entry in self.ledger:
            ledger_view += f"\n{entry['description'][:23].ljust(23)}" + str(format(entry['amount'], '.2f').rjust(7))
        ledger_view += f"\nTotal: {self.current_balance}"
        return ledger_view

def create_spend_chart(*categories):
    bar_chart_str = 'Percentage spent by category'
    categories_num = len(categories) # Total no. of categories
    col_length = 12
    total_spending = 0

    category_names = [] # list of category names
    for cat in categories:
        category_names.append(cat.name)
        for entry in cat.ledger:
            for value in entry.values():
                if isinstance(value, (int, float)) and value < 0:
                    total_spending -= value
    
    #calculate Total Spending
    length = 0
    for name in category_names: # figuring what should be the length of our columns
        if len(name) > length:
            length = len(name)
    col_length += length


    # Creates the scale column
    scale = []
    for i in range(100, -1, -10):
        scale.append(f"{i}|".rjust(4))
    scale.append('    ')
    for i in range(col_length):
        scale.append('    ')

    # Creates other columns
    columns = []
    for category in range(categories_num):
        temp = []
        association = {100: 0, 90: 1, 80: 2, 70: 3, 60: 4, 50: 5, 40: 6, 30: 7, 20: 8, 10: 9, 0: 10}

        category_spending = 0
        for entry in categories[category].ledger:
            for value in entry.values():
                if isinstance(value, (int, float)) and value < 0:
                    category_spending -= value

        category_percent = (category_spending/total_spending) * 100
        
        import math
        rounded_cat_percent = math.floor(category_percent/10) * 10

        for val in range(association[rounded_cat_percent]):
            if category == categories_num - 1:
                temp.append('    ')
            else:
                temp.append('   ')

        # it creates the list of graph dots.
        for val in range((11-len(temp))):
            if category == categories_num - 1: # Conditional to add two spaces after the last column
                temp.append(' o  ')
            else:
                temp.append(' o ')
        if category == categories_num - 1:
            temp.append('----')
        else:
            temp.append('---')


        # adds name of category to the columns list
        category_name = list(category_names[category])
        for ch in category_name:
            if category == categories_num - 1:
                temp.append(' ' + ch + '  ')
            else:
                temp.append(' ' + ch + ' ')

        # makes sure that all columns are of same length
        if len(temp) == col_length:
            columns.append(temp)
        else:
            for i in range((col_length - len(temp))):
                temp.append('   ')
            columns.append(temp)

    # Conatinates all columns to the final string
    for i, col in enumerate(zip(*columns)):
        bar_chart_str += f"\n{scale[i]}{''.join(col)}"
    
    return bar_chart_str

food = Category('Food')
food.deposit(1000, 'deposit')
food.withdraw(10.15, 'groceries')
food.withdraw(15.89, 'restaurant and more food for dessert')
clothing = Category('Clothing')
food.transfer(50, clothing)
clothing.withdraw(25, 'clothes')
print(food)
print(create_spend_chart(food, clothing))

Your browser information:

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

Challenge Information:

Build a Budget App - Build a Budget App

If you have an error please share the exact text of the error.

Errors are extremely useful and often contain the precise information that you need to resolve a problem.

Try sending the category arguments to create_spend_chart as a list rather than using the asterisk operator.

1 Like
  1. You should have a function outside the Category class named create_spend_chart(categories)

Your implementation is a bit different than the instructions:

create_spend_chart(*categories)
  File "/home/pyodide/budget.py", line 51, in create_spend_chart python-test-evaluator.js:2:12859
08:29:55.030     category_names.append(cat.name) python-test-evaluator.js:2:12859
08:29:55.031                           ^^^^^^^^ python-test-evaluator.js:2:12859
08:29:55.031 AttributeError: 'list' object has no attribute 'name'

The last line of this error should give you a clue to what’s causing the problem.

1 Like

Thank you very much. I removed the asterisk operator * and tried passing categories as a list to the function, and it worked!

create_spend_chart(categories) function was already outside the Category Class. The issue was me using * to get multiple arguments into funtion call instead of just using a list. Thanks anyway.

Again, the parameter didn’t match the instructions.

Now it matches.

Updated Code:

create_spend_chart(categories)
    ...
print(create_spend_chart(['food', 'clothing']))
1 Like

you are passing strings here, not categories, you will want to update that to check if your function works properly

1 Like

Ugh. The asterisk as a unary operator in a function call is legitimate syntax in Python, which makes this one of those gotchas that’s unlikely produce a useful error message. Personally, I have a bad habit of using == instead of = in assignment statements and then wondering why values are wrong later.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.