I'm writing a test method called, say, test_foo
(using pytest). I am testing the behavior of a function, foo
, which takes as an argument another function, get
. foo
calls get
iteratively, conditionally on the return value of get
, e.g.:
def foo(get, param):
max_num_tries = 3
curr_num_tries = 0
response = get(param)
while curr_num_tries < max_num_tries and response.status_code == BAD_STATUS_CODE:
response = get(param)
return response
I am trying to override get
such that it has access to how many times it's been called and can return different values accordingly.
Here's a simplified version of what I have so far:
def test_foo():
tries_so_far = 0
def get(arg1):
global tries_so_far
if tries_so_far < 3:
tries_so_far += 1
print("do something special here")
else:
print("do something else here")
return "some return val"
foo(get, "some arg")
However, I get the following error:
NameError: global name 'tries_so_far' is not defined
If I define tries_so_far
outside of test_foo
, at the module level, I get the expected behavior. However, I would like tries_so_far
to be a variable that is local to test_foo
.
Is there some way to give get
read/write to tries_so_far
using globals, or some other technique? Note: I cannot change the parameters or return value of get
.
According to the accepted answer for this question Why can functions in Python print variables in enclosing scope but cannot use them in assignment?, there is an additional statement added in Python 3: nonlocal
that does what you want. It is like global
, but says to look at the enclosing scope instead of the module level. The following modification should therefore allow you to do exactly what you want:
def test_foo():
tries_so_far = 0
def get(arg1):
nonlocal tries_so_far
if tries_so_far < 3:
tries_so_far += 1
print("do something special here")
else:
print("do something else here")
return "some return val"
foo(get, "some arg")
While your question is not an exact duplicate of the one I cited above, you should read the accepted answer. It is very good and will probably address many unstated questions that you have on the subject.