Help with budget-app create_spend_chart

Tell us what’s happening:
Hello! I’m having trouble with the budget-app challenge from Scientific Computing with Python Certification and would appreciate if someone could help me.

My problem is in the second part, with the create_spend_chart function. Specifically, dispalying the letters.

I made the mistake of building and testing my function based on the input to the function being a list of strings. In that case everything works fine. But the problem is that in the complete program (and not in a separate file where I was testing it with a list of strings) the input has to be a list of objects. So my code fails because I need to convert those objects to strings and I can’t think a way of how to do it.

Your code so far

class Category:
    
    def __init__(self,budgetname):
        self.budget = budgetname
        self.ledger = []
        self.funds = 0
        #self.positivebalance = 0
        self.negativebalance = 0

    def deposit(self, amount, description = ""):
        self.ledger.append({"amount": amount, "description": description})
        self.funds += amount
        #self.positivebalance += amount

    def withdraw(self, amount, description = ""):
        if self.check_funds(amount) == True:
            self.ledger.append({"amount": -amount, "description": description})
            self.funds -= amount
            self.negativebalance += amount
            return True
        else:
            return False

    def get_balance(self):
        return self.funds

    def check_funds(self, amount):
        if amount > self.funds:
            return False
        else:
            return True

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

    def __str__(self):
        totalstars = 30 - len(self.budget)
        if totalstars%2 == 0:
            lstars = int(totalstars/2)
            rstars = int(totalstars/2)
        elif totalstars%2 != 0:
            lstars = int(totalstars/2)
            rstars = int(totalstars/2) + 1
        leftstars = "*" * lstars
        rightstars = "*" * rstars

        display = ""
        for entry in self.ledger:
            desc = entry["description"]
            am = entry["amount"]
            if isinstance(am,int):
                am = str(am) + ".00"
                
            if len(desc) <= 23:
                wspaces = " " * (30 - len(desc) - len(str(am)))
                display += f"{desc}{wspaces}{am}\n"
            else:
                dif = len(desc) - 23
                wspaces = " " * (7 - len(str(am)))
                display += f"{desc[:-(dif)]}{wspaces}{am}\n"
            
        finaldisplay = f"{leftstars}{self.budget}{rightstars}\n" + display + f"Total: {self.get_balance()}"
        return finaldisplay

def get_percentage(self):
    #actual funds
    balance = self.funds
    #total withdrawals
    withdraw = self.negativebalance
    #percentage calculation
    percentage_spend = int((10 * withdraw) / (balance + withdraw))
    return percentage_spend
    
def create_spend_chart(categories):
    grid = []
    
    for category in categories:
        #create a list for each element in "categories" with empty strings in the first 10 elements
        column = [" "," "," "," "," "," "," "," "," "," "]
        #add the capitalized-category-name as individual letters at the end of the corresponding "column" list
        cap = category.capitalize() ##ERROR HERE##
        splitletters = list(cap)
        column.extend(splitletters)
        #append all lists to "grid" list
        grid.append(column)
        per = get_percentage(category)

        #replace empty strings with "o" according to percentage
        for j in range(0, len(grid)): 
            for i in range(0,per): 
                grid[j][i] = "o"

    #preparing percentage display
    graph = ""
    for j in range (9,-1, -1):
        row = " "
        for i in range (0, len(categories)):
            element = grid[i][j] + "  "
            row += element
        pernum = (j+1)*10
        margin = " " * (3 - len(str(pernum)))
        graph += "\n" + margin + str(pernum) + "|" + row
            
    dashes = ("---" * len(categories) ) + "-"

    #preparing words display
    longestword = max(categories, key=len) ##ERROR HERE##
    lenlongestword = len(longestword)

    letters = ""
    for j in range(10,lenlongestword + 10):
        line = " "
        for i in range(0, len(categories)):
            try:
                element = grid[i][j] + "  "
                line += element
            except:
                line += "   "
        letters += "\n    " + line 
    

    display = "Percentage spent by category" + graph +"\n    " + dashes + letters

    
    print(display)    
    
    #return display

#TEST
food = Category("Food")
food.deposit(100, "deposit")
food.withdraw(80, "pizza")
clothing = Category("Clothing")
clothing.deposit(100, "deposit")
clothing.withdraw(50, "boots")
entretainment = Category("Entretainment")
entretainment.deposit(100, "deposit")
entretainment.withdraw(10, "cinema")

create_spend_chart([food, clothing, entretainment])




Errors in my editor console
line 86, in create_spend_chart
cap = category.capitalize() ##ERROR HERE##
AttributeError: ‘Category’ object has no attribute ‘capitalize’

line 112, in create_spend_chart
longestword = max(categories, key=len) ##ERROR HERE##
TypeError: object of type ‘Category’ has no len()

An additional problem that I also see coming is that in the line in which I use the get_percentage function I need the input to be an object, which will not be coherent if I transform everything into strings …

Your browser information:

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

Challenge: Budget App

Link to the challenge:

Notice that each Category instance has attribute, that’s name of the category. Why not use that?

2 Likes

Yes! You’re right! Thank you!

I changed my code in the spliting part like this:

....

for category in categories:
        #create a list for each element in "categories" with empty strings in the first 10 elements
        column = [" "," "," "," "," "," "," "," "," "," "]
        #add the capitalized-category-name as individual letters at the end of the corresponding "column" list
        name = category.budget
        splittedname = list(name)
        column.extend(splittedname)
....

and the calculation for the longest name like this:

names = []
    for category in categories:
        name = category.budget
        names.append(name)

    longestword = max(names, key=len) 
    lenlongestword = len(longestword)

So far now all works on my editor. Thank you so much! !