Budget App project food.balance

My code is failing 5 of the tests, but I am getting the expected output for those tests. Specifically, it doesn’t seem to like my food.balance for three of the tests dealing with balance and transfer. Here is my full code with the examples I am trying:

from itertools import zip_longest
import math

class Category:
    def __init__(self, title):
        self.title = title
        self.ledger = []
        self.balance = 0.00
        self.expense = 0.00
        
    def __str__(self):
        header = '\n' + self.title.center(30, "*") + '\n'
        transactions = ''
        total = self.balance
        
        for item in range(len(self.ledger)):
            trans_amount = "{0:>7.2f}".format(self.ledger[item]['amount'])
            trans_desc = self.ledger[item]["description"][:23]
            transactions += f'{trans_desc}{trans_amount.rjust(30 - len(trans_desc))}\n'
        
        return f'{header}{transactions}Total: {total}'
    
    def deposit(self, amount, description=''):
        self.ledger.append({'amount': round(amount, 2), 'description': description})
        self.balance += amount

    def withdraw(self, amount, description=''):
        if self.check_funds(amount):
            self.ledger.append({'amount': (amount * -1), 'description': description})
            self.balance -= amount 
            self.expense += amount
            return True
        else:
            return False

    def get_balance(self, amount):
        return self.balance

    def transfer(self, amount, destination):
        if self.check_funds(amount):
            self.withdraw(amount, f"Transfer to {destination.title}")
            destination.deposit(amount, f"Transfer from {self.title}")
            self.expense -= amount # so xfers don't count toward expenses
            return True
        else:
            return False
    
    def check_funds(self, amount):
        if amount > self.balance:
            return False
        else:
            return True

# the bar chart part
def create_spend_chart(categories):
    
    # get percent spends
    cat_spends = []
    for cat in range(len(categories)):
        cat_spends.append(categories[cat].expense)
    denom = 0.0
    for spend in range(len(cat_spends)):
        denom += cat_spends[spend]
    percent_expenses = []
    for numerator in range(len(cat_spends)):
        percent_expenses.append((int((cat_spends[numerator] / denom) * 100) // 10) * 10)
    
    print("Percentage spent by category")
    
    row_num = 100
    def bars(percent_list):
        row_bar = ''
        nonlocal row_num
        for part in range(len(percent_list)):
            if (row_num == 0):
                row_bar += 'o  '
            if (percent_expenses[part]) >= row_num and row_num > 0:
                row_bar += 'o  '
        row_num -= 10
        return row_bar
    
    # print by y-axis
    for i in range(100, -10, -10):
        print(f"{str(i).rjust(3)}| {bars(percent_expenses)}")
        
    # print bottom divider
    print("    -" +  "".rjust(len(categories * 3), "-"))
    
    # vertically print categories
    cat_titles = []
    for item in range(len(categories)):
        cat_titles.append(categories[item].title)
    cats_flat = ' '.join(cat_titles)
    for x in zip_longest(*cats_flat.split(), fillvalue=' '):
        print ('     ' + '  '.join(x))
    return ''

food = Category("Food")
beans = Category("Beans")
food.deposit(900, "deposit")
food.withdraw(45.67, "milk, cereal, eggs, bacon, bread")
beans.deposit(100, "something")
beans.withdraw(100, "gone")
rocks = Category("Rocks")
rocks.deposit(500, "iadfjsdf")
rocks.withdraw(200, "bye")
print(food)

create_spend_chart([food, beans, rocks])

specific tests I am failing:

  • Failed:Calling food.deposit(900, "deposit") and food.withdraw(45.67, "milk, cereal, eggs, bacon, bread") should return a balance of 854.33.

  • Failed:Calling transfer on a category object should reduce the balance in the category object.

  • Failed:The transfer method should increase the balance of the category object passed as its argument.

  • 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.

1 Like

issues

call these two and then print food.balance, you get 923.96, there is something wrong with your logic

you need to remove the starting \n of the string rapresentation

the function should return a string with the bar chart, not print it only

regarding the first issue: I am printing food.balance now and I am getting 854.33

to be sure: I am entering this:

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

at the end of my code to test

you are right, I am getting this error tho:

TypeError: Category.get_balance() missing 1 required positional argument: 'amount'

(open the browser console with F12 to see the errors)

1 Like

Thank you. I just erased the “amount” argument from the definition of get_balance(). Good to know about F12 as well. I was really stumbling around in the dark. All tests pass now except for the last one, but I think I know what to do there… it will just take some time. Thanks again!

Hello again,
I am still working at this. I’ve been trying to learn how to read the devtools while running the tests, but I can’t seem to figure out the exact problem. I have adjusted the code so that create_spend_chart() is returning a string. I am still failing the last test, but I cannot see any difference in spacing or format from the given example:

from itertools import zip_longest
import math

class Category:
    def __init__(self, title):
        self.title = title
        self.ledger = []
        self.balance = 0.00
        self.expense = 0.00
        
    def __str__(self):
        header = self.title.center(30, "*") + '\n'
        transactions = ''
        total = self.balance
        
        for item in range(len(self.ledger)):
            trans_amount = "{0:>7.2f}".format(self.ledger[item]['amount'])
            trans_desc = self.ledger[item]["description"][:23]
            transactions += f'{trans_desc}{trans_amount.rjust(30 - len(trans_desc))}\n'
        
        return f'{header}{transactions}Total: {total}'
    
    def deposit(self, amount, description=''):
        self.ledger.append({'amount': round(amount, 2), 'description': description})
        self.balance += amount

    def withdraw(self, amount, description=''):
        if self.check_funds(amount):
            self.ledger.append({'amount': (amount * -1), 'description': description})
            self.balance -= amount 
            self.expense += amount
            return True
        else:
            return False

    def get_balance(self):
        return self.balance

    def transfer(self, amount, destination):
        if self.check_funds(amount):
            self.withdraw(amount, f"Transfer to {destination.title}")
            destination.deposit(amount, f"Transfer from {self.title}")
            self.expense -= amount # so xfers don't count toward expenses
            return True
        else:
            return False
    
    def check_funds(self, amount):
        if amount > self.balance:
            return False
        else:
            return True

# the bar chart part
def create_spend_chart(categories):
    
    # get percent spends
    cat_spends = []
    for cat in range(len(categories)):
        cat_spends.append(categories[cat].expense)
    denom = 0.0
    for spend in range(len(cat_spends)):
        denom += cat_spends[spend]
    percent_expenses = []
    for numerator in range(len(cat_spends)):
        percent_expenses.append((int((cat_spends[numerator] / denom) * 100) // 10) * 10)
    
    chart_title = "Percentage spent by category"
    
    row_num = 100
    def bars(percent_list):
        row_bar = ''
        nonlocal row_num
        for part in range(len(percent_list)):
            if (row_num == 0):
                row_bar += 'o  '
            if (percent_expenses[part]) >= row_num and row_num > 0:
                row_bar += 'o  '
        row_num -= 10
        return row_bar
    
    # create chart top
    chart_top = ''
    for i in range(100, -10, -10):
        chart_top += f"{str(i).rjust(3)}| {bars(percent_expenses)}\n"

    # make bottom divider
    divider = "    -" +  "".rjust(len(categories * 3), "-")
    
    # vertically print categories
    cat_titles = []
    chart_bottom = ''
    for item in range(len(categories)):
        cat_titles.append(categories[item].title)
    cats_flat = ' '.join(cat_titles)
    for x in zip_longest(*cats_flat.split(), fillvalue=' '):
        chart_bottom += ('     ' + '  '.join(x)) + '\n'
        
    return f"{chart_title}\n{chart_top}{divider}\n{chart_bottom}"

food = Category("Food")
beans = Category("Beans")
food.deposit(900, "deposit")
food.withdraw(45.67, "milk, cereal, eggs, bacon, bread")
beans.deposit(100, "something")
beans.withdraw(100, "gone")
rocks = Category("Rocks")
rocks.deposit(500, "iadfjsdf")
rocks.withdraw(200, "bye")

print(create_spend_chart([food, beans, rocks]))

I think the answer lies in this line from devtools:

pyodide.asm.js:9 AssertionError: 'Perc[26 chars]100| \n 90| \n 80| \n 70| o  \n 60| o  \n 50| [261 chars] t\n' != 'Perc[26 chars]100|          \n 90|          \n 80|          [348 chars] t  '

but I am having trouble understanding what it means.

You can see a != in the assertion error. Break it up into 2 lines:

pyodide.asm.js:9 AssertionError: 
'Perc[26 chars]100| \n 90| \n 80| \n 70| o  \n 60| o  \n 50| [261 chars] t\n' 
!= 
'Perc[26 chars]100|          \n 90|          \n 80|          [348 chars] t  '

The first line is your output and the 2nd line is the expected output. You can see you need some spaces after 100| and scroll to the end you can see your line ends with \n but it needs to end with 2 spaces.

1 Like

Thanks. I found some faulty logic that was reversing my 'o’s. I wasn’t using an elif and else at the end of my bar function, just a series of ifs.

1 Like