Build a Budget App - Test 19

Tell us what’s happening:

The test to round down the a categories’ spending percentages to the nearest ten fails to pass. Any assistance will be highly appreciated.

Your code so far

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

    def deposit(self, amount, description=''):
        '''Deposit an amount into the categoory's balance.'''
        self.balance += amount
        self.ledger.append({'amount': amount, 'description': description})

    def withdraw(self, amount, description=''):
        '''Withdraw an amount from the category's balance.'''
        if not self.check_funds(amount):
            return False
        self.balance -= amount
        self.withdrawn += amount
        Category.total_withdrawn += amount
        self.ledger.append({'amount': -amount, 'description': description})
        return True

    def check_funds(self, amount):
        '''Validate whether the balance is sufficient for the transaction.'''
        if self.balance >= amount:
            return True
        return False

    def get_balance(self):
        '''return the current balance of the Category'''
        return self.balance
    
    def transfer(self, amount, other):
        '''Transfer an amount from one category to another.'''
        if self.withdraw(amount, f'Transfer to {other.name}'):
            other.deposit(amount, f'Transfer from {self.name}')
            return True
        else:
            return False

    def __str__(self):
        '''returns a formatted string representation of an object.'''
        output = '{:*^30}\n'.format(self.name)
        for transaction in self.ledger:
            amount, description = transaction.values()
            if len(description) > 23:
                description = description[:23]
            formatted_description = '{:<23}'.format(description)
            formatted_amount = '{:>7.2f}'.format(amount)
            output += '{}{}\n'.format(formatted_description, formatted_amount)
        output += f"Total: {'{:.2f}'.format(self.get_balance())}"
        return output
 
def create_spend_chart(categories):
    '''returns a formatted string of a chart representing the spending percentage of each object'''
    spend_chart = 'Percentage spent by category'
    for y_value in range(100, -1, -10):
        line = f'\n{"{:>3}".format(y_value)}| '
        for category in categories:
            if (((category.withdrawn / Category.total_withdrawn) * 100) // 10) * 10 >= y_value:
                line += 'o  '
            else:
                line += '   '
        spend_chart += line
    horizontal_line = '---' * len(categories) + '-' 
    spend_chart += f'\n{f"{{:>{4+len(horizontal_line)}}}".format(horizontal_line)}'

    for index in range(max([len(category.name) for category in categories])):
        line = f'\n     '
        for category in categories:
            if len(category.name) > index:
                line += f'{category.name[index]}  '
            else:
                line += '   '
        spend_chart += line
    return spend_chart

'''
food = Category('Food')
food.deposit(1000, 'deposit')
food.withdraw(112.15, 'groceries')
food.withdraw(13.89, 'restaurant and more food for dessert')

clothing = Category('Clothing')
clothing.deposit(400, 'deposit')
clothing.withdraw(134.15, 'shirts')
clothing.withdraw(44, 'trousers')

auto = Category('Auto')
auto.deposit(3000, 'deposit')
auto.withdraw(40.15, 'oil')
auto.withdraw(300.89, 'tires and bearings')

food.transfer(23, clothing)
food.transfer(100, auto)

clothing.transfer(50, food)
clothing.transfer(34.4, auto)

auto. transfer(14, food)
auto.transfer(53, clothing)

print(food)
print(clothing)
print(auto)

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

Your browser information:

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

Challenge Information:

Build a Budget App - Build a Budget App

It’s an obvious question but you didn’t mention it so: Are you rounding the values down in the chart?

Can you show some examples of input and output to demonstrate?

1 Like

Thanks for your speedy response. I’ve provided further explanations in the attached photo.

Calculation looks correct to me. I’m not sure why it’s failing yet.

If you look in the browser console (f12) there is a more detailed error.

AssertionError: 
'Perc[77 chars]|          \n 60|          \n 50|          \n [297 chars] t  ' != 
'Perc[77 chars]|    o     \n 60|    o     \n 50|    o     \n [297 chars] t  '

Your output is first, expected is second.

As far as I can tell your output is ok but the test expects something else for some reason.

(Please provide code/text instead of screenshots in the future)

1 Like

That’s what baffles me. I’ve tried multiple tests with various values, and output seems correct every time. I reviewed the error in developer view, but I still don’t know why it is failing.

Maybe skip this for now until someone has some insight, don’t burn yourself out over it.

Might be something we are both missing, or some funky detail in the way it interacts with the tests.

1 Like
   'Perc[77 chars]|          \n 60|          \n 50|          \n [297 chars] t  '
!= 'Perc[77 chars]|    o     \n 60|    o     \n 50|    o     \n [297 chars] t  '

I have no idea what’s going on, testing with the same usecase used by the tests, your code works, but the actual output that the tests see does not have the dots

can you try a solution that does not use

notice how it does a mess with calculations

food = Category("Food")
entertainment = Category("Entertainment")
business = Category("Business")
food.deposit(900, "deposit")
entertainment.deposit(900, "deposit")
business.deposit(900, "deposit")
food.withdraw(78)
entertainment.withdraw(22)
business.withdraw(8)
print(create_spend_chart([business, food, entertainment]))
print(create_spend_chart([food, entertainment]))
print(create_spend_chart([business, entertainment])) # wrong chart
print(create_spend_chart([business, food])) # wrong chart


food = Category("Food")
entertainment = Category("Entertainment")
business = Category("Business")
food.deposit(900, "deposit")
entertainment.deposit(900, "deposit")
business.deposit(900, "deposit")
food.withdraw(105.55)
entertainment.withdraw(33.40)
business.withdraw(10.99)

print(create_spend_chart([business, food, entertainment])) # wrong chart
2 Likes

I have tried several rounding forms, which all seemed correct. The following is the only rounding that was accepted by the test. Make sure to use 0 not -1 as the rounding mode:
if int(round((category.withdrawn / Category.total_withdrawn) * 100), 0) >= y_value:

1 Like

I am elated to inform all interested and supporting parties that the issue has been resolved.

An assessment of the error revealed a fundamental misunderstanding of the instructions on my part.

The instruction for the test was: “You should have a function outside the Category class named create_spend_chart(categories) that returns a bar-chart string. To build the chart: …Calculate percentages from withdrawals only and not from deposits. The percentage should be the percentage of the amount spent for each category to the total spent for all categories (rounded down to the nearest 10). "

The error did not result from the “rounding” of the percentages; it resulted from the “calculation” of the percentages. I had initially calculated the percentage as the percentage of the amount spent for each category (passed into the create_spend_chart method) to the total spent for all categories (whether or not they were passed into the create_spend_chart method). However, the test required the percentage of the amount spent for each category (passed into the create_spend_chart method) to the total spent for all categories passed into the create_spend_chart method (not all instances of the Category class).

This slight misunderstanding led to a seemingly correct output that, in truth, was wrong.

I appreciate all who assisted in finding this solution. Thanks for your support.

1 Like

Nicely done!

Ok, that makes sense, that’s what the Category.total_withdrawn variable is about. Sorry I missed that. It stood out to me but the results were ok (sometimes).

Glad you were able to figure it out

1 Like