Build a Budget App - Build a Budget App

Tell us what’s happening:

My code works but I’m stuck on step 4. where it asks to filter the output. How do I edit my code to make it work like the example output ?

Thank you for your time.

Your code so far

class Category:
    def __init__(self, name):
        self.name = name
        self.ledger = []
    
    def __str__(self):
        return f'***************{self.name}***************\n{self.ledger[0]}'

    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
        else:
            return False

    def get_balance(self):
        balance = 0
        for transaction in self.ledger:
            balance += transaction['amount']    
        return balance

    def transfer(self, amount, destination_category):
        self.withdraw(amount, f"Transfer to {destination_category.name}")
        destination_category.deposit(amount, f"Transfer from {self.name}")
        if amount <= self.get_balance():
            return True
        else:
            return False


        

    def check_funds(self, amount):
        if amount <= self.get_balance():
            return True
        else:
            return False
        

def create_spend_chart(categories):
    pass

food = Category('Food')
    
food.deposit(900, 'deposit')
food.withdraw(45.67, 'milk, cereal, eggs, bacon, bread')

print(food)

Your browser information:

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

Challenge Information:

Build a Budget App - Build a Budget App

Hi there,

Please take it a step at a time.

The first thing you need to do is center the category name within asterisks so there are exactly 30 characters altogether.

So, you will need to research f-string formatting.

Happy coding!

I updated my code. I can’t seem to get passed 16. Printing a Category instance should give a different string representation of the object.

from itertools import zip_longest
import math

class Category:
    def __init__(self, name):
        self.name = name
        self.ledger = []
    
    
    
    def __str__(self):
        length = len(self.name)
        stars = int((30 - length) / 2)
        title_1 = ("*" * stars) + self.name + ("*" * (30-length-stars))
        descriptions = [self.ledger[i]['description'] for i in range(len(self.ledger))]
        amount_1 = 0
        amount_2 = 0
        amount_3 = 0
        amount_4 = 0
        for index, l in enumerate(self.ledger):
            if index == 0:
                amount_1 += self.ledger[0]['amount']
                amount_2 += self.ledger[1]['amount']
                amount_3 += self.ledger[2]['amount']
                amount_4 += self.ledger[3]['amount']
        
        initial_deposit = descriptions[0]
        category_1 = descriptions[1]
        descrip_1 = descriptions[2]
        transfers = descriptions[3]
        for i in range(len(self.ledger)):
            descrip = self.ledger[i]['description']
        #    transfers = t
       #     break
        balance = self.get_balance()
        return f'*************{title_1}*************\n{initial_deposit:<23} {amount_1:>7.2f}\n{category_1:<23} {amount_2:>7.2f}\n{descrip_1:<23} {amount_3:>7.2f}\n{transfers:<23} {amount_4:>7.2f}\nTotal: {balance:>7.2f}'

    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
        else:
            return False

    def get_balance(self):
        balance = 0
        for transaction in self.ledger:
            balance += transaction['amount']    
        return balance

    def transfer(self, amount, destination_category):
        self.withdraw(amount, f"Transfer to {destination_category.name}")
        destination_category.deposit(amount, f"Transfer from {self.name}")
        if amount <= self.get_balance():
            return True
        else:
            return False


        

    def check_funds(self, amount):
        if amount <= self.get_balance():
            return True
        else:
            return False
        

def create_spend_chart(categories):
    pass

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)
print(food)

In your __str__ method, there’s actually an easier way of getting the descriptions and amounts. Try an enumerated for loop with ‘i’ and an additional term to get descriptions and amounts in the ledger. From there, you need only two variables – one for description, one for amount, and you can use a key to get what you need from the term you specified in the for loop header.

As for the title for the categories — there’s an easier way using string formatting as well.

Best of luck!

1 Like

Thank you for the tip. It helped me out a lot.

I still can’t get pass the AssertionError in my code.

from itertools import zip_longest
import math
import re

class Category:
    def __init__(self, name):
        self.name = name
        self.ledger = []
    
    
    
    def __str__(self):
        length = len(self.name)
        stars = int((4 - length) / 2)
        title_1 = ("*" * stars) + self.name + ("*" * (4-length-stars))

        for i, description in enumerate(self.ledger):
            amounts = [self.ledger[i]['amount'] for i in range(len(self.ledger))]
            descriptions = [self.ledger[i]['description'] for i in range(len(self.ledger))]
        initial_deposit = descriptions[0][:23]
        category_1 = descriptions[1][:23]
        descrip_1 = descriptions[2][:23]
        transfers = descriptions[3][:23]
        for i in range(len(self.ledger)):
            descrip = self.ledger[i]['description']
        balance = self.get_balance()
        return f'*************{title_1}*************\n{initial_deposit:<23}{amounts[0]:>7.2f}\n{category_1:<23}{amounts[1]:>7.2f}\n{descrip_1:<23}{amounts[2]:>7.2f}\n{transfers:<23}{amounts[3]:>7.2f}\nTotal: {balance}'

    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
        else:
            return False

    def get_balance(self):
        balance = 0
        for transaction in self.ledger:
            balance += transaction['amount']    
        return balance

    def transfer(self, amount, destination_category):
        self.withdraw(amount, f"Transfer to {destination_category.name}")
        destination_category.deposit(amount, f"Transfer from {self.name}")
        if amount <= self.get_balance():
            return True
        else:
            return False

    def check_funds(self, amount):
        if amount <= self.get_balance():
            return True
        else:
            return False
        

def create_spend_chart(categories):
    pass

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)
print(food)

One reason my code might not be working I think is because of this:

food.deposit(1000, ‘initial deposit’)

if I set the deposit amount to 0 I get an index error. Could that be the reason that my code is not being validated?

Does it make sense to set a deposit amount to 0?

Your code looks like this in the console:

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

That should tell you something.

And here’s a resource that might be helpful:
Python String Formatting

@dhess
0 was just an example. I tried several numbers and they all gave an index error, it seems to have fixed itself though. Could you look at my code now and see if I missed anything?

Thanks.

class Category:
    def __init__(self, name):
        self.name = name
        self.ledger = []  
    
    def __str__(self):
        length = len(self.name)
        stars = int((4 - length) / 2)
        title_1 = ("*" * stars) + self.name + ("*" * (4-length-stars))

        for i, description in enumerate(self.ledger):
            amounts = [self.ledger[i]['amount'] for i in range(len(self.ledger))]
            descriptions = [self.ledger[i]['description'] for i in range(len(self.ledger))]
        initial_deposit = descriptions[0][:23]
        category_1 = descriptions[1][:23]
        descrip_1 = descriptions[2][:23]
        transfers = descriptions[3][:23]
        balance = self.get_balance()
        return f'*************{title_1}*************\n{initial_deposit:<23}{amounts[0]:>7.2f}\n{category_1:<23}{amounts[1]:>7.2f}\n{descrip_1:<23}{amounts[2]:>7.2f}\n{transfers:<23}{amounts[3]:>7.2f}\nTotal: {balance:.2f}'

    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
        else:
            return False

    def get_balance(self):
        balance = 0
        for transaction in self.ledger:
            balance += transaction['amount']    
        return balance

    def transfer(self, amount, destination_category):
        self.withdraw(amount, f"Transfer to {destination_category.name}")
        destination_category.deposit(amount, f"Transfer from {self.name}")
        if amount <= self.get_balance():
            return True
        else:
            return False

    def check_funds(self, amount):
        if amount <= self.get_balance():
            return True
        else:
            return False
        

def create_spend_chart(categories):
    pass

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)
print(food)

It looks like you are forcing values in your str method. Try adding a deposit and withdraw for clothing and printing it. What do you see in the console?

I don’t know if it’s related to the issue you’re having, but you appear to be hardcoding amounts and descriptions in your str method’s return section. You don’t need to do that. You can return a single string with the title variable and the lists you made – amounts and descriptions.

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