Scientific Computing with Python Projects - Budget App

Tell us what’s happening:

Hello!

When I run the tests on my Budget App, the final test (testing the create_spend_chart method) fails every time. I think it’s just a formatting issue, but I can’t figure out what is wrong with the format- to my eyes at least, it looks the same as the expected output.

Here is my code:

Your code so far

def create_spend_chart(categories):

    category_totals = [sum(transaction['amount'] for transaction in category.ledger if transaction['amount'] < 0) for category in categories]
    total_spent = sum(category_totals)

    percentages = [(amount / total_spent) * 100 for amount in category_totals]
    rounded_percentages = [int(percent // 10) * 10 for percent in percentages]

    chart = "Percentage spent by category\n"

    for i in range(100, -1, -10):
        line = f"{i:3}| "

        line += " ".join("o " if percent >= i else "  " for percent in rounded_percentages)
        line += "\n"
        chart += line


    chart += "    " + "-" * (len(categories) * 3 + 1) + "\n"

    longest_name = max(len(category.name) for category in categories)

    for i in range(longest_name):
        line = "     "
        for category in categories:
            if i < len(category.name):
                line += f"{category.name[i]}  "
            else:
                line += "   "
        if i != longest_name - 1:
            line += "\n"
        chart += line

    return chart

Your browser information:

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

Challenge Information:

Scientific Computing with Python Projects - Budget App

Please share the complete code. Your implementation of the Category class is vital for accurately reproducing the result from create_spend_chart function.

My apologies, here is my full code:

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

    def __str__(self):
        title = f'{self.name:*^30}'
        items = ''
        total = 0

        for transaction in self.ledger:
            description = transaction['description'][:23]
            amount = transaction['amount']
            total += amount
            items += f'{description:<23}{amount:>7.2f}\n'
        
        output = title + '\n' + items + f'Total: {total:.2f}'
        return output

    # A deposit method that accepts an amount and description. If no description is given, 
    # it should default to an empty string. The method should append an object to the ledger list in 
    # the form of {"amount": amount, "description": description}.
    def deposit(self, amount, description=''):
        self.ledger.append({"amount":amount, "description":description})
        
    
    # A withdraw method that is similar to the deposit method, but the amount passed in should be stored 
    # in the ledger as a negative number. If there are not enough funds, nothing should be added 
    # to the ledger. This method should return True if the withdrawal took place, and False otherwise.
    def withdraw(self, amount, description=''):
        if self.check_funds(amount):
            self.ledger.append({'amount':(amount*-1), 'description':description})
            return True
        else:
            return False 
        

    # A get_balance method that returns the current balance of the budget category based on the deposits 
    # and withdrawals that have occurred.

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

    # A transfer method that accepts an amount and another budget category as arguments. 
    # The method should add a withdrawal with the amount and the description 
    # "Transfer to [Destination Budget Category]". The method should then add a deposit to the other 
    # budget category with the amount and the description "Transfer from [Source Budget Category]". 
    # If there are not enough funds, nothing should be added to either ledgers. This method should 
    # return True if the transfer took place, and False otherwise.

    def transfer(self,amount,category):
        if self.check_funds(amount):
            self.withdraw(amount, f'Transfer to {category.name}')
            category.deposit(amount, f'Transfer from {self.name}')
            return True
        else:
            return False

    # A check_funds method that accepts an amount as an argument. It returns False if the amount is 
    # greater than the balance of the budget category and returns True otherwise. This method should 
    # be used by both the withdraw method and transfer method.

    def check_funds(self, amount):
        total_balance = self.get_balance()
        return amount <= total_balance

def create_spend_chart(categories):

    category_totals = [sum(transaction['amount'] for transaction in category.ledger if transaction['amount'] < 0) for category in categories]
    total_spent = sum(category_totals)

    percentages = [(amount / total_spent) * 100 for amount in category_totals]
    rounded_percentages = [int(percent // 10) * 10 for percent in percentages]

    chart = "Percentage spent by category\n"

    for i in range(100, -1, -10):
        line = f"{i:3}| "

        line += " ".join("o " if percent >= i else "  " for percent in rounded_percentages)
        line += "\n"
        chart += line


    chart += "    " + "-" * (len(categories) * 3 + 1) + "\n"

    longest_name = max(len(category.name) for category in categories)

    for i in range(longest_name):
        line = "     "
        for category in categories:
            if i < len(category.name):
                line += f"{category.name[i]}  "
            else:
                line += "   "
        if i != longest_name - 1:
            line += "\n"
        chart += line

    return chart

Looking in the bowser’s console (not the console on the page) after running tests will give the specifics why test failed. The trouble is in the formatting little detail. Each line with the 0-100 labels requires one more space at the end.

Thank you for your help! I must admit I still did not see any info in the console other than “Check that all spacing is exact.” May I ask how you realized that one space was needed at the end of each line?

This is part of the test error output from browser’s console (colors helpfully added by forum):

  • line with - indicates the line returned by function
  • line with + indicates the expected line
  • line with ? points to specific place where difference is present
- 100|         
+ 100|          
?              +
-  90|         
+  90|          
?              +
-  80|         
+  80|          
?              +
-  70|    o    
+  70|    o     
?              +
-  60|    o    
+  60|    o     
?              +