Build a Budget App - Build a Budget App

Tell us what’s happening:

All testcases pass except testcase 19. The error I get is:
“The height of each bar on the create_spend_chart chart should be rounded down to the nearest 10.”
I think I calculated the percenteges correctly, so I don’t know where the problem is.
In the console I get the following error:

{message: ‘Unspecified AssertionError’, showDiff: false, actual: null, expected: undefined, stack: ‘AssertionError: Unspecified AssertionError\n at …t-runner/9.0.1/python-test-evaluator.js:2:157407)’}

Need hlp

Your code so far

class Category():

total_spendings = 0

def \__init_\_(self, name):
    self.name = name
    self.ledger = \[\]
    self.balance = 0
    self.spendings = 0

def check_funds(self, amount):
    if amount <= self.balance:
        return True
    else:
        return False
        
def deposit(self, amount, description=''):
    transaction = {'amount': amount, 'description': description}
    
    #if not description:
    \#    transaction.'description' = ''
    #else:
    \#    transaction.'description' = description
    
    self.balance += amount
    self.ledger.append(transaction)

def withdraw(self, amount, description=''):
    if not self.check_funds(amount):
        return False
    transaction = {'amount': -amount, 'description': description}
    
    #if not description:
    \#    transaction.'description' = ''
    #else:
    \#    transaction.'description' = description
    self.ledger.append(transaction)
    self.balance -= amount
    self.spendings += amount
    Category.total_spendings += amount
    
    return True

def get_balance(self):
    return self.balance

def transfer(self, amount, category):
    descr_source = f'Transfer to {category.name}'
    descr_dest = f'Transfer from {self.name}'
    
    #if not check_funds(amount)
    \#    return False
        
    if self.withdraw(amount, descr_source):
        category.deposit(amount, descr_dest)
        #self.spendings += amount
        return True        
    return False
    
def \__str_\_(self):
    title = self.name.center(30,'\*')
    output = f'{title}'        
    for trans in self.ledger:
        length_descr = min(len(trans\['description'\]), 23)
        
        output += f"\\n{trans\['description'\]\[:length_descr\]:<23}{trans\['amount'\]:>7.2f}"
    output += f'\\nTotal: {self.balance}'
    return output

def create_spend_chart(categories):
print("total spendings ", Category.total_spendings)
percentage_each = {}
for category in categories:
percentage_each[category] = category.spendings / Category.total_spendings * 100 if Category.total_spendings >0 else 0
print(f’{category.name}: {percentage_each[category]} %‘)
#create vertical string:
string = “Percentage spent by category”
for percentage in range(100,-1,-10):
string += f’\n{str(percentage):>3}| ’
for category in categories:
if percentage_each[category] >= percentage:
string += "o "
else:
string += " "
#make underscore line
string += f’\n ’ + ‘—’ * len(categories) + ‘-’

#make vertical category names
maxCategoryNameLength = max(len(category.name) for category in categories)
for i in range(maxCategoryNameLength):
    string += '\\n     '
    for category in categories:
        if i < len(category.name):
            string += f'{category.name\[i\]}  '
        else:
            string += '   '
    
return string    

def main():
food = Category(‘Food’)
food.deposit(1000, ‘initial deposit’)
food.withdraw(10.15, ‘groceries’)
food.withdraw(15.89, ‘restaurant and more food for dessert’)
clothing = Category(‘Clothing’)
food.transfer(50, clothing)
clothing.deposit(20, ‘toale’)
clothing.deposit(500, ‘toale multe’)
clothing.withdraw(30,‘pulover’)
clothing.withdraw(100, ‘geaca’)
clothing.withdraw(300, ‘ski’)
auto = Category(‘Auto’)
auto.deposit(2000, ‘intretinere’)
auto.withdraw(100, ‘bec far’)
auto.withdraw(200, ‘cauciuc’)
auto.transfer(100,food)
print(food)
print(clothing)
print(auto)
print(create_spend_chart([food, clothing, auto]))

if _name_ == ‘_main_’:
main()

Your browser information:

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

Challenge Information:

Build a Budget App - Build a Budget App

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-budget-app/5e44413e903586ffb414c94e.md at main · freeCodeCamp/freeCodeCamp · GitHub

Your code was too long to be automatically inserted by the help button.

Please update the message, or reply to this one, to include your code, formatted as follows:

There are two ways you can format your code to make it easier to read and test:

  1. After you copy/paste your code into the editor, select it by dragging your cursor over it then click the (</>) button in the toolbar to automatically wrap your code in backticks. (You can click on the animated demo image below to enlarge it.)

  1. Manually add three backticks on a new line above your code and on a new line after your code. Note that a backtick is NOT the same as a single quote('). To find the backtick key on your keyboard, see this post.

To see changes to your post as you make them, you can click the (M+) button on the toolbar to bring up the rich text editor:

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

    def check_funds(self, amount):
        if amount <= self.balance:
            return True
        else:
            return False
            
    def deposit(self, amount, description=''):
        transaction = {'amount': amount, 'description': description}
        
        #if not description:
        #    transaction.'description' = ''
        #else:
        #    transaction.'description' = description
        
        self.balance += amount
        self.ledger.append(transaction)

    def withdraw(self, amount, description=''):
        if not self.check_funds(amount):
            return False
        transaction = {'amount': -amount, 'description': description}
        
        #if not description:
        #    transaction.'description' = ''
        #else:
        #    transaction.'description' = description
        self.ledger.append(transaction)
        self.balance -= amount
        self.spendings += amount
        Category.total_spendings += amount
        
        return True
    
    def get_balance(self):
        return self.balance
    
    def transfer(self, amount, category):
        descr_source = f'Transfer to {category.name}'
        descr_dest = f'Transfer from {self.name}'
        
        #if not check_funds(amount)
        #    return False
            
        if self.withdraw(amount, descr_source):
            category.deposit(amount, descr_dest)
            #self.spendings += amount
            return True        
        return False
        
    def __str__(self):
        title = self.name.center(30,'*')
        output = f'{title}'        
        for trans in self.ledger:
            length_descr = min(len(trans['description']), 23)
            
            output += f"\n{trans['description'][:length_descr]:<23}{trans['amount']:>7.2f}"
        output += f'\nTotal: {self.balance}'
        return output

def create_spend_chart(categories):
    print("total spendings ", Category.total_spendings)
    percentage_each = {}
    for category in categories:
        percentage_each[category] = category.spendings / Category.total_spendings * 100 if Category.total_spendings >0 else 0
        print(f'{category.name}: {percentage_each[category]} %')
    #create vertical string:
    string = "Percentage spent by category"
    for percentage in range(100,-1,-10):
        string += f'\n{str(percentage):>3}| '
        for category in categories:
            if percentage_each[category] >= percentage:
                string += "o  "
            else:
                string += "   "
    #make underscore line    
    string += f'\n    ' + '---' * len(categories) + '-'
    
    #make vertical category names
    maxCategoryNameLength = max(len(category.name) for category in categories)
    for i in range(maxCategoryNameLength):
        string += '\n     '
        for category in categories:
            if i < len(category.name):
                string += f'{category.name[i]}  '
            else:
                string += '   '
        
    return string    
    
def main():
    food = Category('Food')
    food.deposit(1000, 'initial deposit')
    food.withdraw(10.15, 'groceries')
    food.withdraw(15.89, 'restaurant and more food for dessert')
    clothing = Category('Clothing')
    food.transfer(50, clothing)
    clothing.deposit(20, 'toale')
    clothing.deposit(500, 'toale multe')
    clothing.withdraw(30,'pulover')
    clothing.withdraw(100, 'geaca')
    clothing.withdraw(300, 'ski')
    auto = Category('Auto')
    auto.deposit(2000, 'intretinere')
    auto.withdraw(100, 'bec far')
    auto.withdraw(200, 'cauciuc')
    auto.transfer(100,food)
    print(food)
    print(clothing)
    print(auto)
    print(create_spend_chart([food, clothing, auto]))
        
if __name__ == '__main__':
    main()

Please try again to post your formatted code. See the above post to find the backtick on your keyboard.

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

    def check_funds(self, amount):
        if amount <= self.balance:
            return True
        else:
            return False
            
    def deposit(self, amount, description=''):
        transaction = {'amount': amount, 'description': description}
        
        #if not description:
        #    transaction.'description' = ''
        #else:
        #    transaction.'description' = description
        
        self.balance += amount
        self.ledger.append(transaction)

    def withdraw(self, amount, description=''):
        if not self.check_funds(amount):
            return False
        transaction = {'amount': -amount, 'description': description}
        
        #if not description:
        #    transaction.'description' = ''
        #else:
        #    transaction.'description' = description
        self.ledger.append(transaction)
        self.balance -= amount
        self.spendings += amount
        Category.total_spendings += amount
        
        return True
    
    def get_balance(self):
        return self.balance
    
    def transfer(self, amount, category):
        descr_source = f'Transfer to {category.name}'
        descr_dest = f'Transfer from {self.name}'
        
        #if not check_funds(amount)
        #    return False
            
        if self.withdraw(amount, descr_source):
            category.deposit(amount, descr_dest)
            #self.spendings += amount
            return True        
        return False
        
    def __str__(self):
        title = self.name.center(30,'*')
        output = f'{title}'        
        for trans in self.ledger:
            length_descr = min(len(trans['description']), 23)
            
            output += f"\n{trans['description'][:length_descr]:<23}{trans['amount']:>7.2f}"
        output += f'\nTotal: {self.balance}'
        return output

def create_spend_chart(categories):
    print("total spendings ", Category.total_spendings)
    percentage_each = {}
    for category in categories:
        percentage_each[category] = category.spendings / Category.total_spendings * 100 if Category.total_spendings >0 else 0
        print(f'{category.name}: {percentage_each[category]} %')
    #create vertical string:
    string = "Percentage spent by category"
    for percentage in range(100,-1,-10):
        string += f'\n{str(percentage):>3}| '
        for category in categories:
            if percentage_each[category] >= percentage:
                string += "o  "
            else:
                string += "   "
    #make underscore line    
    string += f'\n    ' + '---' * len(categories) + '-'
    
    #make vertical category names
    maxCategoryNameLength = max(len(category.name) for category in categories)
    for i in range(maxCategoryNameLength):
        string += '\n     '
        for category in categories:
            if i < len(category.name):
                string += f'{category.name[i]}  '
            else:
                string += '   '
        
    return string    
    
def main():
    food = Category('Food')
    food.deposit(1000, 'initial deposit')
    food.withdraw(10.15, 'groceries')
    food.withdraw(15.89, 'restaurant and more food for dessert')
    clothing = Category('Clothing')
    food.transfer(50, clothing)
    clothing.deposit(20, 'toale')
    clothing.deposit(500, 'toale multe')
    clothing.withdraw(30,'pulover')
    clothing.withdraw(100, 'geaca')
    clothing.withdraw(300, 'ski')
    auto = Category('Auto')
    auto.deposit(2000, 'intretinere')
    auto.withdraw(100, 'bec far')
    auto.withdraw(200, 'cauciuc')
    auto.transfer(100,food)
    print(food)
    print(clothing)
    print(auto)
    print(create_spend_chart([food, clothing, auto]))
        
if __name__ == '__main__':
    main()

Hi, I uploaded the formatted code a couple of hours ago.

ok, I reformatted the code. it’s ok now?

if I change your code to add a second use of create_spend_chart, like this

    print(create_spend_chart([food, clothing, auto]))
    print(create_spend_chart([food, auto]))

the second one looks like

Percentage spent by category
100|       
 90|       
 80|       
 70|       
 60|       
 50|       
 40|    o  
 30|    o  
 20|    o  
 10|    o  
  0| o  o  
    -------
     F  A  
     o  u  
     o  t  
     d  o  

if food has 0% of spending when comparing each category with the total spent between the two, then auto should be 100%, so what changes here?

if you did not comment the statements regarding clothing in main(), the withdrawals from the clothing object are still counted through the class variable total_spendings, so that’s why the percentages don’t add up to 100. So even though you changed the code to use

print(create_spend_chart([food, auto]))

the transactions from the clothing object are still counted. If you comment those statements you will get the right result

so I can’t call create_spend_chart multiple times to create different charts? that seems not really that useful

I did not take into consideration some safety checks because I don’t know the manner in which the tests are conducted. Is this the problem? The automated tests call create_spend_chart repeatedly for different scenarios? In this case using a class variable fails.

One other thing I saw in console (F12) is an error which I don’t know if it is related or not:

{message: ‘Unspecified AssertionError’, showDiff: false, actual: null, expected: undefined, stack: ‘AssertionError: Unspecified AssertionError\n at …t-runner/9.0.1/python-test-evaluator.js:2:157407)’}

that’s the actual failure, the stuff in yellow is the human readable part, the red is the error from the tests

you need to figure out how to always show the correct column height, and make your function actually reusable

other example

    food = Category('Food')
    food.deposit(1000, 'initial deposit')
    food.withdraw(10.15, 'groceries')
    food.withdraw(15.89, 'restaurant and more food for dessert')
    clothing = Category('Clothing')
    food.transfer(50, clothing)
    clothing.deposit(20, 'toale')
    clothing.deposit(500, 'toale multe')
    clothing.withdraw(30,'pulover')
    clothing.withdraw(100, 'geaca')
    clothing.withdraw(300, 'ski')
    auto = Category('Auto')
    auto.deposit(2000, 'intretinere')
    auto.withdraw(100, 'bec far')
    auto.withdraw(200, 'cauciuc')
    auto.transfer(100,food)
    fun = Category('Fun')
    fun.withdraw(20, "ticket")

    print(create_spend_chart([clothing, auto]))
    print(create_spend_chart([food, fun]))

I fixed the internal logic to skip using a class atribute for all spendings and now it works. Thanks