0

I have a function that iterates through tests and executes them. Before executing each test, it calls a function confirm_execute() to check if the tests have been cancelled. confirm_execute() is shown below (pardon the mess of debugging messages):

def confirm_execute(self):
    self._update_hil_status()
    status = self.hil_status['status']
    print 'STATUS =', status

    if status == 'TESTING':
        return True
    elif status == 'CANCEL':
        print '##### Cancelling #####'
        return False

    elif status == 'REQUEST_STOP':
        print '##### Stopping tests #####'
        self._set_hil_status(status='STOPPED')
    elif status == 'STOPPED':
        time.sleep(5)
    elif status == 'RESUME':
        print '##### Resuming tests #####'
        self._set_hil_status(status='TESTING')
    else:
        print '##### Invalid status {} - setting stop status #####'.format(status)
        self._set_hil_status(status='STOPPED')

    self.confirm_execute()  # only exit if status is testing or cancel

The portion of function that checks for permission before executing a test is here:

allow = self.status.confirm_execute()
if allow:
    print 'continue: {}'.format(allow)
    # run a test
else:
    print 'cancel: {}'.format(allow)
    # clean up

Here's the issue: when I set the status to CANCEL, confirm_execute seems to return None instead of False. Here's the output on the console when I stop a set of tests and then attempt to cancel:

STATUS = REQUEST_STOP
##### Stopping tests #####
SETTING STOPPED
STATUS = STOPPED
STATUS = STOPPED
STATUS = CANCEL
##### Cancelling #####
cancel: None

Note that I get the ##### Cancelling ##### message, which means that I should be returning False. However, the value of allow received seems to be None.

What simple mistake am I making?

Jeremy Weirich
  • 387
  • 5
  • 20
  • 2
    You probably mean `return self.confirm_execute()` when you recursively re-call the method. Otherwise you are abandoning the return value of the recursive call and falling off the end of the method (which means returning `None`). – khelwood Mar 23 '17 at 15:21

2 Answers2

3

Your function only explicitly return a value for TESTING and CANCEL. Otherwise it just prints things, calls itself, and does not explicitly return anything. This means it implicitly returns None.

What you wanted is return self.confirm_execute().

9000
  • 39,899
  • 9
  • 66
  • 104
3

Recursion is not the appropriate solution here. Every time the result is not CANCEL or TESTING, the function will call itself; but you do not return the values from those nested calls, so they are lost.

Instead of recursing, you should put the whole function within a while True loop - so it will continue to loop until one of the return cases is reached.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Recursion could work here if it's not more than a few hundred calls deep. Else it will blow the stack (hence the site name). Unfortunately, Python does not feature tail call elimination. – 9000 Mar 23 '17 at 15:35
  • @9000 technically it would - but why risk it/do it if it's not required anyway? :p – Jon Clements Mar 23 '17 at 15:37
  • @JonClements: No point risking it. The point is that the thing could work for smaller test cases, and then suddenly blow up under production load. Something to be aware of. – 9000 Mar 23 '17 at 15:49