What does this AssertionError mean in the context of my code? FAIL: test_arrangement (test_module.UnitTests)

I’m working on an arithmetic arranger problem.

The program arranges and returns the problem as shown below in the console output. It is a function that accepts two parameters: a list where each item is an addition or subtraction problem, and an optional second argument that, when true, displays each answer beneath the dashes under each problem.

To me, it looks like the program is failing 1 out of the 6 tests in the test_module file.

Here’s the console output when I run the program, the error is shown here:

python main.py
   32      3801      50      123        12
+ 698    -    2    + 50    -  49    + 3600
-----    ------    ----    -----    ------
  730      3799     100       74      3612
F.....
======================================================================
FAIL: test_arrangement (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 10, in test_arrangement
    self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]')
AssertionError: '    [68 chars]-    ------    ----    -----\n  858      3799      88      172' != '    [68 chars]-    ------    ----    -----'
      3      3801      45      123
  + 855    -    2    + 43    +  49
- -----    ------    ----    -----
?                                 -
+ -----    ------    ----    ------   858      3799      88      172 : Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]

----------------------------------------------------------------------
Ran 6 tests in 0.006s

FAILED (failures=1)

The contents of my main.py file:

# This entrypoint file to be used in development. Start by reading README.md
from arithmetic_arranger import arithmetic_arranger
from unittest import main


print(arithmetic_arranger(["32 + 698", "3801 - 2", "50 + 50", "123 - 49", "12 + 3600"], True))


# Run unit tests automatically
main(module='test_module', exit=False)

The contents of my arithmetic_arranger.py file:

def arithmetic_arranger(problems, results):
  if len(problems) > 5:
    return 'Error: Too many problems.'
  
  top = []
  bottom = []
  dashes = []
  spaces = '    '
  answers = []

# ["32 + 698", "3801 - 2", "50 + 50", "123 - 49", "12 + 3600"]

  for problem in problems:
    first = '  ' + problem.split()[0]
    second = problem.split(' ', 1)[1]
    length_first = len(first)
    length_second = len(second)
    difference_first = length_first - length_second
    difference_second = length_second - length_first

    width_first = len(problem.split()[0])
    width_second = len(problem.split()[2])

    if width_first > 4 or width_second > 4:
      return "Error: Numbers cannot be more than four digits."
      
    if second[0] != '+' and second[0] != '-':
      return "Error: Operator must be '+' or '-'."
    
    if first.lstrip().isdigit() != True or second[2:].isdigit() != True:
      return 'Error: Numbers must only contain digits.'
    
    if difference_first > 0:
      second = second[0] + ' ' * (difference_first + 1) + second[2:]
    elif difference_second > 0:
      first = ' ' * difference_second + first

    # Optional condition to display answers under problems:
    if results:
      if second[0] == '+':
        answer = int(first) + int(second[2:])
      else:
        answer = int(first) - int(second[2:])

      answer_to_string = str(answer)
      length_result = len(answer_to_string)
      answer_to_string = '  ' + answer_to_string
      length_maximum = max([len(first.lstrip()), len(second[1:].lstrip())])

      if length_maximum > length_result:
        answer_to_string = ' ' * (length_maximum - length_result) + answer_to_string
      elif length_maximum < length_result:
        answer_to_string = answer_to_string[1:]

      answers.append(answer_to_string)

  # Append variables to lists
    top.append(first)
    bottom.append(second)
    dashes.append('-' * len(second))

  # Set spacing
    spaced_top = spaces.join(top)
    spaced_bottom = spaces.join(bottom)
    spaced_dashes = spaces.join(dashes)
    spaced_answers = spaces.join(answers)
  
  return spaced_top + '\n' + spaced_bottom + '\n' + spaced_dashes + '\n' + spaced_answers

The contents of my test_module.py file:

import unittest
from arithmetic_arranger import arithmetic_arranger


# the test case
class UnitTests(unittest.TestCase):
    def test_arrangement(self):
        actual = arithmetic_arranger(["3 + 855", "3801 - 2", "45 + 43", "123 + 49"], True)
        expected = "    3      3801      45      123\n+ 855    -    2    + 43    +  49\n-----    ------    ----    -----"
        self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]')

        actual = arithmetic_arranger(["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"], True)
        expected = "  11      3801      1      123         1\n+  4    - 2999    + 2    +  49    - 9380\n----    ------    ---    -----    ------"
        self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"]')

    def test_too_many_problems(self):
        actual = arithmetic_arranger(["44 + 815", "909 - 2", "45 + 43", "123 + 49", "888 + 40", "653 + 87"], True)
        expected = "Error: Too many problems."
        self.assertEqual(actual, expected, 'Expected calling "arithmetic_arranger()" with more than five problems to return "Error: Too many problems."')

    def test_incorrect_operator(self):
        actual = arithmetic_arranger(["3 / 855", "3801 - 2", "45 + 43", "123 + 49"], True)
        expected = "Error: Operator must be '+' or '-'."
        self.assertEqual(actual, expected, '''Expected calling "arithmetic_arranger()" with a problem that uses the "/" operator to return "Error: Operator must be '+' or '-'."''')
        
    def test_too_many_digits(self):
        actual = arithmetic_arranger(["24 + 85215", "3801 - 2", "45 + 43", "123 + 49"], True)
        expected = "Error: Numbers cannot be more than four digits."
        self.assertEqual(actual, expected, 'Expected calling "arithmetic_arranger()" with a problem that has a number over 4 digits long to return "Error: Numbers cannot be more than four digits."')

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

    def test_solutions(self):
        actual = arithmetic_arranger(["32 - 698", "1 - 3801", "45 + 43", "123 + 49"], True)
        expected = "   32         1      45      123\n- 698    - 3801    + 43    +  49\n-----    ------    ----    -----\n -666     -3800      88      172"
        self.assertEqual(actual, expected, 'Expected solutions to be correctly displayed in output when calling "arithmetic_arranger()" with arithmetic problems and a second argument of `True`.')


if __name__ == "__main__":
    unittest.main()

Any help on why I’m getting this error is appreciated, thank you!

Answer returned by function is not matching expected one. It is returning answer with results of calculated problems, but this test isn’t (shouldn’t) requiring that. Looking at the test_module.py, test function calls were modified, to always require calculated problems.

1 Like

I’m not sure I understand what you’re saying. What should I change to fix the problem?

I’d suggest starting with reverting test_module.py to the original version, otherwise tests may give results more strange than they should or seemingly incorrect.

1 Like
Here is the output when I revert test_module.py to the original version:

 python main.py
   32      3801      50      123        12
+ 698    -    2    + 50    -  49    + 3600
-----    ------    ----    -----    ------
  730      3799     100       74      3612
EEE.EE
======================================================================
ERROR: test_arrangement (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 8, in test_arrangement
    actual = arithmetic_arranger(["3 + 855", "3801 - 2", "45 + 43", "123 + 49"])
TypeError: arithmetic_arranger() missing 1 required positional argument: 'results'

======================================================================
ERROR: test_incorrect_operator (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 22, in test_incorrect_operator
    actual = arithmetic_arranger(["3 / 855", "3801 - 2", "45 + 43", "123 + 49"])
TypeError: arithmetic_arranger() missing 1 required positional argument: 'results'

======================================================================
ERROR: test_only_digits (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 32, in test_only_digits
    actual = arithmetic_arranger(["98 + 3g5", "3801 - 2", "45 + 43", "123 + 49"])
TypeError: arithmetic_arranger() missing 1 required positional argument: 'results'

======================================================================
ERROR: test_too_many_digits (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 27, in test_too_many_digits
    actual = arithmetic_arranger(["24 + 85215", "3801 - 2", "45 + 43", "123 + 49"])
TypeError: arithmetic_arranger() missing 1 required positional argument: 'results'

======================================================================
ERROR: test_too_many_problems (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 17, in test_too_many_problems
    actual = arithmetic_arranger(["44 + 815", "909 - 2", "45 + 43", "123 + 49", "888 + 40", "653 + 87"])
TypeError: arithmetic_arranger() missing 1 required positional argument: 'results'

----------------------------------------------------------------------
Ran 6 tests in 0.002s

FAILED (errors=5)

Function is defined as always requiring two arguments, while the second one should be optional per specification.

1 Like

This is really helpful, I see what you’re saying. However I’m unsure how to define the function so that the second argument is optional.

Here is how my function is currently written:

def arithmetic_arranger(problems, results)

Inside the function, I run a conditional if results is true. I thought this would make it optional. What am I missing?

Thank you!

Check in function can be done for what that optional parameter is exactly, but that will not be enough to allow calling function without that parameter. For that it needs to be made as optional in the signature.

For example, the following function accepts name parameter and if it’s passed it will use it in print. If function would be called without any argument - greet() it will use the optional, default value of name, which is 'stranger' in this case.

def greet(name='stranger'):
     print('Hello', name)
1 Like

Thank you! I will try this!

I’m still having trouble getting it to work, is this how I should be writing it?

print(arithmetic_arranger(["32 + 698", "3801 - 2", "50 + 50", "123 - 49", "12 + 3600"], results = True))

Please let me know, thank you so much!

This is how function can be called, results argument can be included or not, but making it as optional is done in the function definition, to be more specific on the line with the def.

1 Like

Thank you!
Here is my function definition now:

def arithmetic_arranger(problems, results = True):

Here is the output when I run it:

python main.py
   32      3801      50      123        12
+ 698    -    2    + 50    -  49    + 3600
-----    ------    ----    -----    ------
  730      3799     100       74      3612
F.....
======================================================================
FAIL: test_arrangement (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 10, in test_arrangement
    self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]')
AssertionError: '    [68 chars]-    ------    ----    -----\n  858      3799      88      172' != '    [68 chars]-    ------    ----    -----'
      3      3801      45      123
  + 855    -    2    + 43    +  49
- -----    ------    ----    -----
?                                 -
+ -----    ------    ----    ------   858      3799      88      172 : Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]

----------------------------------------------------------------------
Ran 6 tests in 0.001s

FAILED (failures=1)

It seems to be failing the test as shown in AssertionError because the output is different than expected, but I’m having trouble making sense of what it is trying to tell me. I really appreciate your help.

It’s just it should be results=False as by default function is not expected to calculate problem answers. Only when explicitly passing True during function call. :slight_smile:

1 Like

When I use this case:

def arithmetic_arranger(problems, results = False):

I get a similar error as when using results = True. Here’s the error:

python main.py
   32      3801      50      123        12
+ 698    -    2    + 50    -  49    + 3600
-----    ------    ----    -----    ------

F.....
======================================================================
FAIL: test_arrangement (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 10, in test_arrangement
    self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]')
AssertionError: '    [36 chars]   -    2    + 43    +  49\n-----    ------    ----    -----\n' != '    [36 chars]   -    2    + 43    +  49\n-----    ------    ----    -----'
      3      3801      45      123
  + 855    -    2    + 43    +  49
- -----    ------    ----    -----
?                                 -
+ -----    ------    ----    ----- : Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]

----------------------------------------------------------------------
Ran 6 tests in 0.001s

FAILED (failures=1)

I notice this difference between the two errors:

when I use results = True, the AssertionError states ‘[68 chars]’…

When I use results = False, the AssertionError states [36 chars]’…

To me this means that when results = True, there are extra characters due to the answers being printed as well.

I also see that the actual value is:
' [68 chars]- ------ ---- -----\n 858 3799 88 172'
and the test is stating that this is != to the expected value, which appears to be:
' [68 chars]- ------ ---- -----'
So is the problem that my code is printing the dashes followed by a newline followed by the answers? When I should be printing only the dashes?

Sounds about right, that’s what error is pointing at now.

1 Like

I think I found the exact problem:

AssertionError: ' [36 chars] - 2 + 43 + 49\n----- ------ ---- -----\n' != ' [36 chars] - 2 + 43 + 49\n----- ------ ---- -----'

In the actual output, at the end of the first set of dashes there is an extra newline character ’ \n ’ right before the ’ != '.

Here is my code for this section:

# Set spacing
    spaced_top = spaces.join(top)
    spaced_bottom = spaces.join(bottom)
    spaced_dashes = spaces.join(dashes)
    spaced_answers = spaces.join(answers)
  
  x = spaced_top + '\n' + spaced_bottom + '\n' + spaced_dashes + '\n' + spaced_answers

  return x

I can see that I added the newline character in the code in order to push the spaced_answers down to the next line. I’m not sure why the ’ \n ’ is appearing in the actual output, though. @sanity thank you!!

In the above code adding \n doesn’t depend on if spaced_answers are actually added or if it’s just empty (when results equals False).

1 Like

I’m not sure I understand what you’re saying, but I added another conditional and it seems to be working when results = False. Here’s the new conditional:

  if results:
    arranged_problems = spaced_top + '\n' + spaced_bottom + '\n' + spaced_dashes + '\n' + spaced_answers
  else:
    arranged_problems = spaced_top + '\n' + spaced_bottom + '\n' + spaced_dashes

  return arranged_problems

Now when I run it with results = False as shown:
def arithmetic_arranger(problems, results = False):
I get this console output:

python main.py
   32      3801      50      123        12
+ 698    -    2    + 50    -  49    + 3600
-----    ------    ----    -----    ------
......
----------------------------------------------------------------------
Ran 6 tests in 0.004s

OK

However, when I run it as results = True:
def arithmetic_arranger(problems, results = True):
I get the same error again:

 python main.py
   32      3801      50      123        12
+ 698    -    2    + 50    -  49    + 3600
-----    ------    ----    -----    ------
  730      3799     100       74      3612
F.....
======================================================================
FAIL: test_arrangement (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-arithmetic-formatter-4/test_module.py", line 10, in test_arrangement
    self.assertEqual(actual, expected, 'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]')
AssertionError: '    [68 chars]-    ------    ----    -----\n  858      3799      88      172' != '    [68 chars]-    ------    ----    -----'
      3      3801      45      123
  + 855    -    2    + 43    +  49
- -----    ------    ----    -----
?                                 -
+ -----    ------    ----    ------   858      3799      88      172 : Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]

----------------------------------------------------------------------
Ran 6 tests in 0.022s

FAILED (failures=1)

Which makes me think the error is encountered when I try to add the newline and the line of answers. I don’t see what I’m doing wrong to get this error however. @sanity thank you so much for the help, I appreciate it!

The False here sets the default value. The default value should be False, which is why all tests pass when you do this.

If you want to use different value for results, you do it by calling arithmetic_arranger(problems, results = True), not by redefining your function.

1 Like

So in my main.py file, I would do this?

print(arithmetic_arranger(["32 + 698", "3801 - 2", "50 + 50", "123 - 49", "12 + 3600"], results = True))

To call the function with the optional answers?

1 Like