Scientific Computing with Python Project 1

I’ve just finished the first project in the scientific computing with python course. My program completely fills the brief and works fine as far as I can tell. However, when I run it through the test module, I fail at every single check. I’m assuming this is because I’ve done the project differently than they’ve expected. Is there a way to salvage this, or do I need to start from scratch?

Code so far

def arithmetic_arranger(*args):
    #Assigns the list of problems into a variable
    problems = args[0]
    # print(problems[0].isnumeric())
    arranged_problems = ""
    
    
    #Returns an error if there are * or / operators
    for problem in problems:
        if ("*" in problem or "/" in problem):
            raise ValueError("Error: Operator must be '+' or '-'.")
    
    
    #Returns an error if more than 5 problems
    if len(problems) > 5:
        raise ValueError("Error: Too many problems.")    
        
        
    #Splits each problem into 3 elements
    for i in range(len(problems)):
        problems[i] = problems[i].split(" ")


    #For loop that raises errors  
    for i in range(len(problems)):
        
        #Raises an error if any characters within operons arn't numeric
        if problems[i][0].isnumeric() == 0 or problems[i][2].isnumeric() ==0:
            raise ValueError("Error: Numbers must only contain digits.")
        
        #Raises an error if any of the operons are more than 4 characters long 
        if len(problems[i][0]) > 4 or len(problems[i][2]) > 4:
            raise ValueError("Error: Numbers cannot be more than four digits.")
           
            
    
    #Code used to display the operations
    
    #Calculating length of largest operon for each problem
    largest_list = []
    for i in range(len(problems)):
        if len(problems[i][0]) > len(problems[i][2]):
            largest_list.append((len(problems[i][0]), 1))
        else:
            largest_list.append((len(problems[i][2]), 2))
        
    #First line
    for i in range(len(problems)):
        for size in range(largest_list[i][0] + 2 - len(problems[i][0])):
            arranged_problems += ' '
        arranged_problems += problems[i][0] + '    '
    arranged_problems += '\n'
    
    
    #Second line
    for i in range(len(problems)):
        arranged_problems += problems[i][1] + ' '
        for size in range(largest_list[i][0] - len(problems[i][2])):
            arranged_problems += ' '
        arranged_problems += (problems[i][2] + '    ')
    arranged_problems += '\n'
    
    
    #Dashes
    for i in range(len(problems)):
        for i in range(largest_list[i][0] + 2):
            arranged_problems += '-'
        arranged_problems += '    '  
    
    
   #Prints the answer if 2nd arguement is "True"
    if args[-1] == True:
        arranged_problems += '\n'
        for i in range(len(problems)):
            
            #Addition
            if problems[i][1] == "+":
                answer = int(problems[i][0]) + int(problems[i][2])
                
            #Subtraction
            elif problems[i][1] == "-":
                answer = int(problems[i][0]) - int(problems[i][2])
            
            #ValueError due to incorrect operator
            else:
                raise ValueError(F"{problems[i][1]} isn't an accepted operator.")
              
            #Print answer
            for size in range(largest_list[i][0] + 2 - len(str(answer))):
                arranged_problems += ' '
            arranged_problems += str(answer) + '    '

    return arranged_problems

Challenge: Arithmetic Formatter

Link to the challenge:

what do the tests say?

An example where I’ve failed to display the equation properly is:

test_module.py:77: AssertionError
________________ test_template[test_four_problems_arrangement] ________________

arguments = [[['3', '+', '855'], ['3801', '-', '2'], ['45', '+', '43'], ['123', '+', '49']]]
expected_output = '    3      3801      45      123\n+ 855    -    2    + 43    +  49\n-----    ------    ----    -----'
fail_message = 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]'

    @pytest.mark.parametrize('arguments,expected_output,fail_message', test_cases)
    def test_template(arguments, expected_output, fail_message):
        actual = arithmetic_arranger(*arguments)
>       assert actual == expected_output, fail_message
E       AssertionError: Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]
E       assert '' == '    3      3...----    -----'
E         -     3      3801      45      123
E         - + 855    -    2    + 43    +  49
E         - -----    ------    ----    -----

An example where I’ve failed to print the correct error message is:

test_module.py:77: AssertionError
_______________________ test_template[test_only_digits] _______________________

arguments = [[['98', '+', '3g5'], ['3801', '-', '2'], ['45', '+', '43'], ['123', '+', '49']]]
expected_output = 'Error: Numbers must only contain digits.'
fail_message = 'Expected calling "arithmetic_arranger()" with a problem that contains a letter character in the number to return "Error: Numbers must only contain digits."'

    @pytest.mark.parametrize('arguments,expected_output,fail_message', test_cases)
    def test_template(arguments, expected_output, fail_message):
        actual = arithmetic_arranger(*arguments)
>       assert actual == expected_output, fail_message
E       AssertionError: Expected calling "arithmetic_arranger()" with a problem that contains a letter character in the number to return "Error: Numbers must only contain digits."
E       assert '' == 'Error: Numbe...ntain digits.'
E         - Error: Numbers must only contain digits.

In both cases, to me it looks like the output at the bottom is correct, but I’m obviously doing something wrong!

the left is your output, the right is the expected. You are returning an empty string, in both cases

Oh I see, I was reading the failure message completely wrong, thankyou!

I think I’ve figured it out now, my error messages weren’t working because I was using the ‘ValueError’ function. The brief says to return an error message, and sure enough when I change my error messages to ‘return’ it works!

As for the rest of the failures, I believe it’s because of the way that the test module inputs the arguments? If I’m reading the error message correctly, the test module inserts the arguments as a tuple of lists.

e.g.
args = ([[‘32’, ‘-’, ‘698’], [‘1’, ‘-’, ‘3801’], [‘45’, ‘+’, ‘43’], [‘123’, ‘+’, ‘49’], [‘988’, ‘+’, ‘40’]], True)

The way I’ve built my code was to accept strings instead, as this was the way that it was displayed on the brief.

e.g.
([“32 + 698”, “3801 - 2”, “45 + 43”, “123 + 49”])

I’ll try and change my code to account for this and let you know if it works.

Thanks for the help!

that’s correct

if you look at the test file you should see that the function is called with a list of strings

Oh I once again read the error message completely wrong, sorry!

I still haven’t managed to crack the problem. However, I think it has something to do with the way that I assign the ‘problems’ variable based on the error message below:

args = ([[['3'], ['+'], ['855']], ['3801', '-', '2'], ['45', '+', '43'], ['123', '+', '49']],)
problems = [[['3'], ['+'], ['855']], ['3801', '-', '2'], ['45', '+', '43'], ['123', '+', '49']]
arranged_problems = '', problem = ['123', '+', '49']

    def arithmetic_arranger(*args):
        #Assigns the list of problems into a variable
        problems = args[0]
        # print(problems[0].isnumeric())
        arranged_problems = ""
    
    
        #Returns an error if there are * or / operators
        for problem in problems:
            if ("*" in problem or "/" in problem):
                return "Error: Operator must be '+' or '-'."
    
    
        #Returns an error if more than 5 problems
        if len(problems) > 5:
            return "Error: Too many problems."
    
    
        #Splits each problem into 3 elements
        for i in range(len(problems)):
>           problems[i] = problems[i].split(" ")
E           AttributeError: 'list' object has no attribute 'split'

The first argument is stored differently from the rest. Also, every one of my failures have the same ‘AttributeError: ‘list’ object has no attribute ‘split’’ message, which means the issue must be within the code:

def arithmetic_arranger(*args):
    #Assigns the list of problems into a variable
    problems = args[0]
    arranged_problems = ""

    #Splits each problem into 3 elements
    for i in range(len(problems)):
        problems[i] = problems[i].split(" ")

This error message doesn’t show up when I run my own code though. Could it be something to do with the version of Python that I’m running?

args[0] is a list of strings, that’s your issue

the function is called

arithmetic_arranger(["1 + 3", "124 - 32"], True)
arithmetic_arranger(["1 + 3", "124 - 32"])

I thought that I could refer to each string individually by iterating through ‘problems’ with the code:

for i in range(len(problems)):
        problems[i] = problems[i].split(" ")

Since I am referencing “problems[i]”, shouldn’t this only select one element of the list and return a string?

Also, what is causing this to work in my own code, but not in the test module? If I print “arranged_answers” at the bottom of my function it displays the correct output.

can you share your replit please?

Ofcourse. I don’t usually work in replit, but I’ve pasted my code in. I’ve pasted my replit link below, but I’m not sure if it’s showing up.

boilerplate-arithmetic-formatter-2 - Replit

I don’t see the value error thing with split running that replit, only the assertion errors for wrong output
have you changed something?
or where you adding function calls yourself to test?

I redownloaded both the main and the test file to make sure I didn’t change anything, and the error message still occurs.

However, the first time I run the main.py code, the split error doesn’t occur, so I guess it’s something to do with variables carrying over between each run. If I restart the kernel between each run, the split error doesn’t occur.

I write my code in Spyder, which doesn’t restart the kernel automatically like replit does, which is probably causing this.

I’m still unsure why I’m getting the wrong output message though. This is probably largely because I’m not sure how to interpret the error message.


================================== FAILURES ===================================
________________ test_template[test_two_problems_arrangement1] ________________

arguments = [[['3801', '-', '2'], ['123', '+', '49']]]
expected_output = '  3801      123\n-    2    +  49\n------    -----'
fail_message = 'Expected different output when calling "arithmetic_arranger()" with ["3801 - 2", "123 + 49"]'

    @pytest.mark.parametrize('arguments,expected_output,fail_message', test_cases)
    def test_template(arguments, expected_output, fail_message):
        actual = arithmetic_arranger(*arguments)
>       assert actual == expected_output, fail_message
E       AssertionError: Expected different output when calling "arithmetic_arranger()" with ["3801 - 2", "123 + 49"]
E       assert '  3801      ...    -----    ' == '  3801      ...----    -----'
E         -   3801      123
E         +   3801      123    
E         ?                ++++
E         - -    2    +  49
E         + -    2    +  49    
E         ?                ++++
E         - ------    -----...
E         
E         ...Full output truncated (3 lines hidden), use '-vv' to show

To me, both outputs look the same, but my output on the “assert” line is completely wrong. I don’t know what I’ve done wrong to cause this

you have extra spaces at the end of each line

Wow I can’t believe the issue was that simple all along. I went back and changed my code to not add spaces at the end of each line, and now it passes the test.

Thankyou so much for all your help, I don’t think I would’ve ever spotted that error :sweat_smile: