Budget app - Replit Error

Hi guys I’m currently testing my code in replit and I’m getting this error message but I can’t figure out what’s wrong with my code:

This is the error message:

FAIL: test_create_spend_chart (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-budget-app/test_module.py", line 102, in test_create_spend_chart
    self.assertEqual(actual, expected, 'Expected different chart representation. Check that all spacing is exact.')
AssertionError: 'Perc[25 chars]n100|\n 90| o \n 80| o  o \n 70| o  o \n 60| o[304 chars]  \n' != 'Perc[25 chars]n100|          \n 90|          \n 80|         [349 chars] t  '
  Percentage spent by category
- 100|
-  90| o 
-  80| o  o 
+ 100|          
+  90|          
+  80|          
-  70| o  o 
?         ^
+  70|    o     
?      +++   ^^
-  60| o  o 
?         ^
+  60|    o     
?      +++   ^^
-  50| o  o 
?         ^
+  50|    o     
?      +++   ^^
-  40| o  o 
?         ^
+  40|    o     
?      +++   ^^
-  30| o  o 
?         ^
+  30|    o     
?      +++   ^^
-  20| o  o 
+  20|    o  o  
?      +++     +
-  10| o  o  o 
?            --
+  10|    o  o  
?      +++
-   0| o  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  
?               -
+            t   : Expected different chart representation. Check that all spacing is exact.

----------------------------------------------------------------------
Ran 11 tests in 0.018s

FAILED (failures=1)

And this is my code:

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

        n = int((30 - len(self.name))/2) #n - number of asterisks       
        num_asterisks = '*' * n    
        headline = num_asterisks+self.name+num_asterisks+'\n'
        line = ''        
        num_spaces = 0
        display = headline+line
        
        for transactions in self.ledger:
            
            amount = float(self.get_balance())
            total = f'Total: {amount:.2f}'
            white_space = ''
            
            description = transactions['description']
            amount = transactions['amount']          
            length_description = len(description)
               
            if length_description > 23:
                length_description = 23
                description = description[0:length_description]    

            amount_float = float(amount) 
            amount_str = '{:.2f}'.format(amount_float) # Adds two decimal numbers                     
            
            num_spaces = 30 - (length_description + len(amount_str)) 
                     
            for i in range(num_spaces):
                white_space += ' '

            line = f'{description}{white_space}{amount_str}\n'
            display +=line
            display
        display +=total
        return display       
        
    def deposit (self, amount, description=''):
        '''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}.'''
              
        self.ledger.append(dict(amount=amount, description=description))
        self.deposits.append(amount)       
        return True
    
    def withdraw (self, amount, 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.'''
        if self.check_funds(amount):           
            self.ledger.append(dict(amount=amount*-1, description=description))
            self.withdrawals.append(amount)            
            return True
        else:
            return False

    def get_balance(self):
        '''A get_balance method that returns the current balance of the budget category based on the deposits and withdrawals that have occurred.'''
        
        balance = 0
        for amount in self.ledger:
            balance += amount['amount']
        return balance
      
    def transfer (self, amount, other_category):
        '''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.'''
        if self.check_funds(amount):
            self.withdraw(amount, 'Transfer to '+ other_category.name)
            other_category.deposit(amount,'Transfer from '+self.name)
            return True
        else: 
            return False

    def check_funds(self,amount):
        '''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.'''
        if amount > self.get_balance():
            return False
        else:
            return True
def create_spend_chart(category):

    zero_line = '  0|'
    separator = '  '
    dashes = '-'
    white_space = ' '
    margin = '    '
    lower_margin= '     '
    zero_line_dashes = margin+'-'
    ten_line = ' 10|'
    twenty_line= ' 20|'
    thirty_line= ' 30|'
    forty_line= ' 40|'
    fifty_line = ' 50|'
    sixty_line = ' 60|'
    seventy_line = ' 70|'
    eighty_line = ' 80|'
    ninety_line = ' 90|'
    hundred_line = '100|'
    title = 'Percentage spent by category'
    lista = [zero_line,ten_line,twenty_line,thirty_line,forty_line,fifty_line,sixty_line,seventy_line,eighty_line,ninety_line,hundred_line]    
    index = lista.index(zero_line)
    all_expenses = []
    for items in category:
        
        withdrawal = sum(items.withdrawals)
        deposits = sum(items.deposits)
        all_expenses.append(withdrawal)
        #deposits = sum(items.deposits)
        all_withdrawals = int(sum(all_expenses))    
        percentage_spent = (withdrawal * 100) / all_withdrawals
        how_many_os = percentage_spent / 10        
        for i in range(index, int(how_many_os)):
            lista[i] = lista[i]+ ' o '                      
    lista.reverse()
    display = '\n'.join(lista)
    length_category = len(category)    
#___Adjusting the dashes size
    for i in range(length_category):
        zero_line_dashes = margin+'-' *((length_category*2)+4) 
    
    output = title+'\n'+display+'\n'+zero_line_dashes
    letters_list = []
    vertical_words = ['\n']   
    longest_length = 0
    lengths = []
#___Turns each letter in category.name into a list of strings
    for words in category:        
#_______Creates a list from the category.name
        category_names = words.name
        category_names.capitalize()
        letters = list(category_names)
#_______
        lengths.append((len(words.name)))
#_______Creates a list of lists
        letters_list.append(letters)
#____Finds the longest length of this new list
#___ Deixar de fora do loop para fazer a consulta apenas uma vez.    
    longest_length = max(lengths)
    

    for idx in range(longest_length):
        vertical_words.append(lower_margin)
        for letters in letters_list:
            
            if len(letters) > idx:
                
                vertical_words.append(letters[idx])
                vertical_words.append('  ')
                
            else:
                vertical_words.append(' ')
                vertical_words.append('  ')
               
        
        vertical_words.append('\n')
    vertical_display = ''.join(vertical_words)
    output+=vertical_display
        
    return output

Notice that on your chart the percents are summing over 100. Why is that?

1 Like

I have absolutely no clue… Gotta say this was the hardest challenge so far. 30 days working on it and can’t see myself finishing it. I was doing so well in the first two challenges (I even completed the shape_calculator in less time) but this one…
##################################################################

I mean, It’s like the interpreter prints in the business category what should be in the food category. But why is it skipping, I can’t tell.

The interpreter knows how many os each category should have but I can’t figure a way to add it to each particular place

Taking a look at part of the printout:

-  20| o  o 
+  20|    o  o  
?      +++     +

- indicates line returned by script
+ is expected line
and ? shows where exactly are differences

Script is printing everything aligned to the left. What could be done to prevent that? For example the o should be only in the last category.

1 Like

I noticed that the o’s of the Food category were printed in the business, that’s why the larger number in the first column. I found a way to solve that but replit still gave me errors.

Here is my code:

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

        n = int((30 - len(self.name))/2) #n - number of asterisks       
        num_asterisks = '*' * n    
        headline = num_asterisks+self.name+num_asterisks+'\n'
        line = ''        
        num_spaces = 0
        display = headline+line
        
        for transactions in self.ledger:
            
            amount = float(self.get_balance())
            total = f'Total: {amount:.2f}'
            white_space = ''
            
            description = transactions['description']
            amount = transactions['amount']          
            length_description = len(description)
               
            if length_description > 23:
                length_description = 23
                description = description[0:length_description]    

            amount_float = float(amount) 
            amount_str = '{:.2f}'.format(amount_float) # Adds two decimal numbers                     
            
            num_spaces = 30 - (length_description + len(amount_str)) 
                     
            for i in range(num_spaces):
                white_space += ' '

            line = f'{description}{white_space}{amount_str}\n'
            display +=line
            display
        display +=total
        return display       
        
    def deposit (self, amount, description=''):
        '''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}.'''
              
        self.ledger.append(dict(amount=amount, description=description))
        self.deposits.append(amount)       
        return True
    
    def withdraw (self, amount, 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.'''
        if self.check_funds(amount):           
            self.ledger.append(dict(amount=amount*-1, description=description))
            self.withdrawals.append(amount)            
            return True
        else:
            return False

    def get_balance(self):
        '''A get_balance method that returns the current balance of the budget category based on the deposits and withdrawals that have occurred.'''
        
        balance = 0
        for amount in self.ledger:
            balance += amount['amount']
        return balance
      
    def transfer (self, amount, other_category):
        '''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.'''
        if self.check_funds(amount):
            self.withdraw(amount, 'Transfer to '+ other_category.name)
            other_category.deposit(amount,'Transfer from '+self.name)
            return True
        else: 
            return False

    def check_funds(self,amount):
        '''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.'''
        if amount > self.get_balance():
            return False
        else:
            return True
def create_spend_chart(category):

    zero_line = '  0|'
    separator = '  '
    dashes = '-'
    white_space = ' '
    margin = '    '
    lower_margin= '     '
    zero_line_dashes = margin+'-'
    ten_line = ' 10|   '
    twenty_line= ' 20|   '
    thirty_line= ' 30|   '
    forty_line= ' 40|   '
    fifty_line = ' 50|   '
    sixty_line = ' 60|   '
    seventy_line = ' 70|'
    eighty_line = ' 80|'
    ninety_line = ' 90|'
    hundred_line = '100|'
    title = 'Percentage spent by category'
    lista = [zero_line,ten_line,twenty_line,thirty_line,forty_line,fifty_line,sixty_line,seventy_line,eighty_line,ninety_line,hundred_line]    
    index = lista.index(zero_line)
    all_expenses = []
    how_many_os =0
    for items in category: 
#_______How many withdrawals were made in total by each item? 
      withdrawal = int(sum(items.withdrawals))
#_______Adding each withdrawal to this list        
      all_expenses.append(withdrawal)
        
#___All_withdrawals equals 100% of the withdrawals
    all_withdrawals = int(sum(all_expenses))

    for withdrawals in all_expenses:
        percentage_spent = (withdrawals * 100) / all_withdrawals
        how_many_os = (percentage_spent/10)
        if how_many_os >1:
            how_many_os = int((percentage_spent / 10))    
        else:
            how_many_os = 1 

        for i in range(index, int(how_many_os)):     
            #   spaces = ' '     
           
            if i > index:      
                if ' o ' in lista[i]:
                    lista[i].replace('   ', 'o')
                else:          
                    lista[i] = lista[i] +'   '
                
            lista[i] +=' o '
  
    
    lista.reverse()
    display = '\n'.join(lista)
    length_category = len(category)    
#___Adjusting the dashes size
    for i in range(length_category):
        zero_line_dashes = margin+'-' *((length_category*2)+4) 
    
    output = title+'\n'+display+'\n'+zero_line_dashes
    letters_list = []
    vertical_words = ['\n']   
    longest_length = 0
    lengths = []
#___Turns each letter in category.name into a list of strings
    for words in category:        
#_______Creates a list from the category.name
        category_names = words.name
        category_names = category_names.capitalize()
        letters = list(category_names)
#_______
        lengths.append((len(words.name)))
#_______Creates a list of lists
        letters_list.append(letters)
#____Finds the longest length of this new list
#___ Deixar de fora do loop para fazer a consulta apenas uma vez.    
    longest_length = max(lengths)
    

    for idx in range(longest_length):
        vertical_words.append(lower_margin)
        for letters in letters_list:
            
            if len(letters) > idx:
                
                vertical_words.append(letters[idx])
                vertical_words.append('  ')
                
            else:
                vertical_words.append(' ')
                vertical_words.append('  ')
               
        
        vertical_words.append('\n')
    vertical_words.pop()
    vertical_display = ''.join(vertical_words)
    output+=vertical_display
        
    return output

The message that Replit sends is the following:

FAIL: test_create_spend_chart (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-budget-app/test_module.py", line 102, in test_create_spend_chart
    self.assertEqual(actual, expected, 'Expected different chart representation. Check that all spacing is exact.')
AssertionError: 'Perc[25 chars]n100|\n 90|\n 80|\n 70|\n 60|       o \n 50|  [305 chars] t  ' != 'Perc[25 chars]n100|          \n 90|          \n 80|         [349 chars] t  '
  Percentage spent by category
+ 100|          
- 100|
-  90|
-  80|
-  70|
-  60|       o 
?  ^         ^
+  90|          
?  ^         ^^
-  50|       o 
?  ^         ^
+  80|          
?  ^         ^^
+  70|    o     
+  60|    o     
+  50|    o     
-  40|       o 
?         ---
+  40|    o     
?           ++++
-  30|       o 
?         ---
+  30|    o     
?           ++++
-  20|       o 
?         ---
+  20|    o  o  
?           ++++
-  10|       o  o 
?         ---
+  10|    o  o  
?              +
-   0| o  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  

I read what you told me about the ?, - and + signs to see if I could figure out what to do. Now, looking at it, it seems that Replit wants me to add blank spaces even if there’s nothing there (This doesn’t seem to make much sense to me)

Yes, the number of characters in the line is expected to be the same for all lines. It’s just one of the requirements, whether it makes sense in every situation is debatable.

1 Like

Take a look at the example output in the freecodecamp exercise briefing. Then replicate that exactly in your model.

1 Like

Hello guys,

I’m happy to announce that I’ve finally finished the budget app project.

Surely it has been the most challenging so far. The solution I got to add spaces was writing a for loop through the list: if there was an ‘o’ in the line, I would only add the necessary number of spaces to leave it aligned. Else, I just add the same number os spaces as the number of dashes.

Thanks for all that helped me here. I’m now gonna work on the final project.

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.