I just couldn't pass the test for "create_spend_chart" of Budget App -- I TRIED EVERYTHING!

Hello active learners !

I’m stuck at the very last test of the Python Budge App project that tests the “create_spend_chart”. Here’s what I did:

  • counted the number of characters of the output chart
  • compared it against the example given in the project description
  • doubled checked that each bar should show the “rounded down” (14.9 should be considered as 20, where as 14.0 should be 10) version of percentage of “total expenses of a category over total deposit”

Could anyone please help ?

class Category:

    def __init__(self, name):
        self.name = name
        self.ledger = [] #must be an instance instead of class variable
        self.balance = 0
        self.totalwithdrawal = 0
        self.totaldeposit = 0
    def __str__(self):
        #print title of Category with centered in between asterixes
        lenobjname = len(self.name)
        rightstars = int( (30 - len(self.name))/2)
        leftstars = int( (30-len(self.name)) /2 ) + ( len(self.name) % 2 >0)
        output = ("*" * rightstars) + (self.name) + ("*" * leftstars) 
        itemlist = []
        for item in self.ledger:
            item_descript = item.get("description")
            item_amount = item.get("amount")
            output = output + "\n" + (str(item_descript))[:23].ljust(23) + ("%.2f"%item_amount)[:7].rjust(7)
            #itemlist.append((str(item_descript)).ljust(23) + ("%.2f"%item_amount).rjust(7))

        lastline =  "Total: " + "%.2f"%self.get_balance() 
        output = output + "\n" + lastline.strip()
        #itemlist.append("Total: " + "%.2f"%self.get_balance())
        #print(itemlist, end='')
        return output

    def deposit(self, amount, description=""):
        ledger_item = {
          "amount": amount,
          "description": description,
        }
        self.ledger.append(ledger_item)
        self.balance += amount
        self.totaldeposit += amount

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

    def get_balance(self):
        l=0;
        for item in self.ledger:
            l = l+item.get("amount")
            #print("balance of ", self.name , l)
        return l

    def transfer(self, num, toobj):
        if (self.check_funds(num)):
            self.withdraw(num, "Transfer to "+toobj.name)
            toobj.deposit(num, "Transfer from "+ self.name)
            return True
        else:
            return False
 
    def check_funds(self, num): 
        if (num>self.get_balance()):
            return False
        else:
            return True

def create_spend_chart(categories):
    num_of_cats = len(categories)
    if (num_of_cats < 5):
        withdraw_percentages = []
        for i in categories:
            withdraw_percentages.append(round(((i.totalwithdrawal/i.totaldeposit)*100),1)-10)
            print(withdraw_percentages)
        chart = "Percentage spent by category" + "\n"
        for a in range (100,-10,-10):
            line = (str(a) + "|"  ).rjust(5)
            for j in withdraw_percentages:
                if j >= a: 
                    line = line + " o "
                else: 
                    line = line + "   "
            line = line + " \n"
            chart = chart + line
        line = "     "
        for j in withdraw_percentages:
            line = line + "---"
        line = line + "- \n"
        chart = chart + line
        longestname = 0
        for j in categories:
            if len(j.name) > longestname:
                longestname = len(j.name)
        for i in range (0,longestname):
            line = "     "
            for c in categories:
                if len(c.name) > i:
                    line = line + " " + c.name[i] + " "
                else:
                    line = line + "   "
            line = line + " \n"
            chart = chart + line
        chart2 = list(chart)
        chart2 = "".join([chart[i] for i in range(len(chart)-1)])
    return chart2

Hi, welcome to the forum! :wave:

Open the browser the devtools (pres F12) and check the console for a more detailed error message

AssertionError: 'Perc[21 chars]ory\n 100|          \n  90|          \n  80|  [379 chars] t  ' 
             != 'Perc[21 chars]ory\n100|          \n 90|          \n 80|     [353 chars] t  '

the top is yours, the below is the expected
it looks like you have an extra space at the beginning of each line

thnx for the reply. you meant chrome devtools ? does it have a python interpreter built in ?

no, but the tests have an output there that is more detailed

thanks Ilenia. I removed one space at the beginning of each line now.
I also made sure that:

  • there is one space at the end of each line
  • each percentage bar should be (total expenses / total deposit ) rounded DOWN meaning a result of 65.78238748 or 69.9938382 should be treated as 60 (like math.floor())

but i still couldn’t pass … please kind shed some lights

check the AssertionErrors in the browser console, they tell you exactly how your code differs from the expected

you can also post your updated code

Thanks again ilenia.
Did you mean clicking on the “Console” ? After I clicked on it, i got the following message:
// running tests create_spend_chart should print a different chart representation. Check that all spacing is exact. // tests completed

Below is the code:

class Category:

    def __init__(self, name):
        self.name = name
        self.ledger = [] #must be an instance instead of class variable
        self.balance = 0
        self.totalwithdrawal = 0
        self.totaldeposit = 0
    def __str__(self):
        #print title of Category with centered in between asterixes
        lenobjname = len(self.name)
        rightstars = int( (30 - len(self.name))/2)
        leftstars = int( (30-len(self.name)) /2 ) + ( len(self.name) % 2 >0)
        output = ("*" * rightstars) + (self.name) + ("*" * leftstars)
        itemlist = []
        for item in self.ledger:
            item_descript = item.get("description")
            item_amount = item.get("amount")
            output = output + "\n" + (str(item_descript))[:23].ljust(23) + ("%.2f"%item_amount)[:7].rjust(7)
            #itemlist.append((str(item_descript)).ljust(23) + ("%.2f"%item_amount).rjust(7))

        lastline =  "Total: " + "%.2f"%self.get_balance()
        output = output + "\n" + lastline.strip()
        #itemlist.append("Total: " + "%.2f"%self.get_balance())
        #print(itemlist, end='')
        return output

    def deposit(self, amount, description=""):
        ledger_item = {
          "amount": amount,
          "description": description,
        }
        self.ledger.append(ledger_item)
        self.balance += amount
        self.totaldeposit += abs(amount)

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

    def get_balance(self):
        l=0;
        for item in self.ledger:
            l = l+item.get("amount")
            #print("balance of ", self.name , l)
        return l

    def transfer(self, num, toobj):
        if (self.check_funds(num)):
            self.withdraw(num, "Transfer to "+toobj.name)
            toobj.deposit(num, "Transfer from "+ self.name)
            return True
        else:
            return False
 
    def check_funds(self, num):
        if (num>self.get_balance()):
            return False
        else:
            return True

def create_spend_chart(categories):
    num_of_cats = len(categories)
    if (num_of_cats < 5):
        withdraw_percentages = []
        for i in categories:
            withdraw_percentages.append(round(((i.totalwithdrawal/i.totaldeposit)*100)))
            print("withdraw_percentages = ", withdraw_percentages)
        chart = "Percentage spent by category" + "\n"
        for a in range (100,-10,-10):
            line = (str(a) + "|"  ).rjust(4) 
            for j in withdraw_percentages:
                if j >= a:
                    line = line + " o "
                else:
                    line = line + "   "
            line = line + " \n"
            chart = chart + line
        line = "    "
        for j in withdraw_percentages:
            line = line + "---"
        line = line + "-\n"
        chart = chart + line
        longestname = 0
        for j in categories:
            if len(j.name) > longestname:
                longestname = len(j.name)
        for i in range (0,longestname):
            line = "    "
            for c in categories:
                if len(c.name) > i:
                    line = line + " " + c.name[i] + " "
                else:
                    line = line + "   "
            line = line + " \n"
            chart = chart + line
        chart2 = list(chart)
        chart2 = "".join([chart[i] for i in range(len(chart)-1)])
    return chart2

I’ve edited your code for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (').

I mean the browser console, the one in the browser dev tools. F12 is the usual way to open it.

Your create_spend_chart is not working properly, I don’t know if it’s not calculating the percentages properly, or if you don’t put in the correct dots, but it’s giving the wrong output

your output for the tests:

Percentage spent by category
100|          
 90|          
 80|          
 70|          
 60|          
 50|          
 40|          
 30|          
 20|          
 10|    o     
  0| o  o  o  
    ----------
     B  F  E  
     u  o  n  
     s  o  t  
     i  d  e  
     n     r  
     e     t  
     s     a  
     s     i  
           n  
           m  
           e  
           n  
           t  

The one the tests want:

Percentage spent by category
100|          
 90|          
 80|          
 70|    o     
 60|    o     
 50|    o     
 40|    o     
 30|    o     
 20|    o  o  
 10|    o  o  
  0| o  o  o  
    ----------
     B  F  E  
     u  o  n  
     s  o  t  
     i  d  e  
     n     r  
     e     t  
     s     a  
     s     i  
           n  
           m  
           e  
           n  
           t

sure ileania , let me do that :slight_smile:

class Category:

    def __init__(self, name):
        self.name = name
        self.ledger = [] #must be an instance instead of class variable
        self.balance = 0
        self.totalwithdrawal = 0
        self.totaldeposit = 0
    def __str__(self):
        #print title of Category with centered in between asterixes
        lenobjname = len(self.name)
        rightstars = int( (30 - len(self.name))/2)
        leftstars = int( (30-len(self.name)) /2 ) + ( len(self.name) % 2 >0)
        output = ("*" * rightstars) + (self.name) + ("*" * leftstars)
        itemlist = []
        for item in self.ledger:
            item_descript = item.get("description")
            item_amount = item.get("amount")
            output = output + "\n" + (str(item_descript))[:23].ljust(23) + ("%.2f"%item_amount)[:7].rjust(7)
            #itemlist.append((str(item_descript)).ljust(23) + ("%.2f"%item_amount).rjust(7))

        lastline =  "Total: " + "%.2f"%self.get_balance()
        output = output + "\n" + lastline.strip()
        #itemlist.append("Total: " + "%.2f"%self.get_balance())
        #print(itemlist, end='')
        return output

    def deposit(self, amount, description=""):
        ledger_item = {
          "amount": amount,
          "description": description,
        }
        self.ledger.append(ledger_item)
        self.balance += amount
        self.totaldeposit += abs(amount)

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

    def get_balance(self):
        l=0;
        for item in self.ledger:
            l = l+item.get("amount")
            #print("balance of ", self.name , l)
        return l

    def transfer(self, num, toobj):
        if (self.check_funds(num)):
            self.withdraw(num, "Transfer to "+toobj.name)
            toobj.deposit(num, "Transfer from "+ self.name)
            return True
        else:
            return False
 
    def check_funds(self, num):
        if (num>self.get_balance()):
            return False
        else:
            return True

def create_spend_chart(categories):
    num_of_cats = len(categories)
    if (num_of_cats < 5):
        withdraw_percentages = []
        for i in categories:
            withdraw_percentages.append(round(((i.totalwithdrawal/i.totaldeposit)*100)))
            print("withdraw_percentages = ", withdraw_percentages)
        chart = "Percentage spent by category" + "\n"
        for a in range (100,-10,-10):
            line = (str(a) + "|"  ).rjust(4) 
            for j in withdraw_percentages:
                if j >= a:
                    line = line + " o "
                else:
                    line = line + "   "
            line = line + " \n"
            chart = chart + line
        line = "    "
        for j in withdraw_percentages:
            line = line + "---"
        line = line + "-\n"
        chart = chart + line
        longestname = 0
        for j in categories:
            if len(j.name) > longestname:
                longestname = len(j.name)
        for i in range (0,longestname):
            line = "    "
            for c in categories:
                if len(c.name) > i:
                    line = line + " " + c.name[i] + " "
                else:
                    line = line + "   "
            line = line + " \n"
            chart = chart + line
        chart2 = list(chart)
        chart2 = "".join([chart[i] for i in range(len(chart)-1)])
    return chart2


have you changed anything here from the other code?

The percentage spent should be calculated only with withdrawals and not with deposits.

You need to calculate the amount spent in each category of the total spent across all categories, not related to the total deposit.

just passed it thanks pkdvalis !

1 Like

hi ilenia,

How does the brower devtool, which shows HTML/Javascript codes of the webpage, could debug the output of the python code tested by Freecodecamp?

The freecodecamp tests are generating output and sending it to the console, but that’s just not being sent to the coding interface console on the freecodecamp website.

thanks , i’m down to my last project and would really love to know how I could make use of browser console (I’m using Chrome) to debug.
Attached is a screenshots what the browser console returned:

Below is my code:

import copy
import random

class Hat:
    def __init__(self, **kwargs):
        self.contents = []
        for color, num in kwargs.items():
            for i in range (0,num):
                self.contents.append(color)

    def draw(self, num):
        if num >= len(self.contents):
            return self.contents
        else:
            for i in range(1,num):
                self.contents.pop(random.randrange(len(self.contents)))
            return self.contents


Look at the Assertion error. The first part is your output and the second is the expected output. It says your output != expected output.

Please open a new topic for more questions about this project, thanks!