[Tutor] raise exception works as planned in program but not when imported into testing module

Dave Angel davea at davea.name
Thu Apr 30 06:14:57 CEST 2015


On 04/29/2015 09:05 PM, Jim Mooney Py3.4.3winXP wrote:
> I raised an exception in the parse_string function in my math parser
> program, function_tosser.py, and caught it in the calling routine, and that
> worked fine. But when I imported function_tosser.py into a test program,
> tester.py, it threw the exception in the parse_string function instead of
> handling it in the try block in the calling routine. Why did it work in one
> and not the other? The testing program works fine if I return None as I did
> before, instead of raising the exception.

It'd be nice if you were explicit about which code you're describing.  I 
can make guesses, but your above paragraph leaves a lot of confusion.

I'm guessing you're talking about the line in parse_string():
         raise ValueError

And I assume you're talking about it being referenced in the other file 
by the line:
         print(ft.parse_string(monkey_wrench), '\n')

But why are you surprised?  There's no try/except protecting the latter 
line, so the exception will be uncaught, and you'll see it reported in 
parse_string().

 > in the try block in the calling routine.

What routine is that?  The line I quoted above is in top-level code, not 
in a routine. And it doesn't have a try/except there.

>
> # function_tosser.py
> """
> Takes the name of a binary math operation and two numbers from input,
> repeatedly, and displays the results until done
> """
>
>
> def add(a, b):
>      return a + b
>
>
> def subtract(a, b):
>      return b - a
>
> def minus(a, b):
>      return a - b
>
>
> def multiply(a, b):
>      return a * b
>
>
> def divide(a, b):
>      return a / b
>
>
> operations = {'add': add, '+': add, 'plus': add, 'subtract': subtract,
> 'subtracted': subtract,
>                '-': minus, 'minus': minus, 'multiply': multiply, '*':
> multiply, 'multiplied': multiply,
>                'times': multiply, 'divide': divide, '/': divide, 'divided':
> divide}
>
> def test_number(astring):
>      """
>      Input: A string that should represent a valid int or float. Output:
>      An int or float on success. None on failure.
>      """
>      for make_type in (int, float):
>          try:
>              return make_type(astring)
>          except ValueError: # Previously returned None, which worked. This
> works fine here but when imported into the test program
>              pass           # it doesn't wait for the try block in the
> calling routine.
>      return None
>
>
> def parse_string(math_string):
>      """Input: A math string with a verbal or mathematical operation
>      and two valid numbers to operate on. Extra numbers and operations
>      are ignored. Output: A tuple containing a function corresponding
>      to the operation and the two numbers. Returns None on failure.
>      """
>      operation = None
>      tokens = math_string.split()
>      numbers = []
>      for token in tokens:
>          if token in operations:
>              operation = operations[token]
>          elif test_number(token) != None:
>              numbers.append(test_number(token))
>          if len(numbers) > 1:
>              break
>      if operation is None or len(numbers) < 2:
>          raise ValueError
>      else:
>          return operation, numbers[0], numbers[1]
>
> if __name__ == "__main__":
>      instructions = '''Enter two numbers and one of the four basid math
> operations,
>      either mathematical or verbal. i.e. 3 + 2, 12 divided by 14, 10 minus
> 4, etc.
>      Enter done to quit.
>      '''
>      try:
>          user_input = input(instructions)
>          while True:
>              if user_input == 'done':
>                  break
>              try:
>                  result = parse_string(user_input)
>              except ValueError:
>                  print("Not a valid math operation.")
>              else:
>                  func, num1, num2 = result
>                  print(func(num1, num2))
>              user_input = input()
>      except KeyboardInterrupt:
>          print("Program terminated by user")
>
> # tester.py
>
> '''Test function_tosser.py mainlogic against random operators, operands,
> and bad input'''
> import random
> import function_tosser as ft
> valid_terms = list(ft.operations.keys())
> def eval_test():
>      pass
>
> trash = ['1 +', 'blah', '3-4', 'gargle', 'Newt Gingrich',
>      ",,,,,", '{+=-33.44 minus12 3 times blarg 1445641654644555455']
>
> for ctr in range(50):
>      term = ' ' + random.choice(valid_terms) + ' '
>      num1 = str(random.randint(1,1000))
>      num2 = str(random.randint(1,1000))
>      if term == ' subtract ' or term == ' subtracted ': term = ' subtracted
> from '
>      if ctr % 10 == 0: # stress testing for a None failure
>          monkey_wrench = random.choice(trash)
>          print(ft.parse_string(monkey_wrench), '\n')
>      else:
>          func, num1, num2 = ft.parse_string(num1 + term + num2)
>          print(func, num1, term, num2)
>          print('result:',func(num1, num2), '\n')
>
>


-- 
DaveA


More information about the Tutor mailing list