2

I need to unit-test a python module by changing a default in the head of the application module called process.py. The declared default is a fixed int. I could change it to use something else from os.environ, but I was hoping to simply assign the global, but clearly I am missing some comprehension around 'def'.

process.default_timeout_secs = 2

# --name: process

default_timeout_secs = 120

def call_process(cmd, timeout=default_timeout_secs):
    print 'run:', cmd, 'timeout:', timeout
    ...



# --name: test_process
from nose.tools import *
import process

@ raises(TimeoutExpired)
def test_process_run_modified_default():
    process.default_timeout_secs = 5
    run(sleep 10)

I understand from other posts, that the process.call_process.func_defaults value for default_timeout_secs is not the one in the top of the module when the module is imported. How do I change the default used in the function?

process.default_timeout_secs = 5 process.call_process.func_globals['default_timeout'] 5 process.call_process.func_defaults (120)

Out[21]: 5
>>> process.call_process(cmd)

Out[22]: call_process: cmd= sleep 2 timeout= 120       <----- 120? 
         Executing cmd sleep 2 verbose=True

The output should show exception TimoutExpired.

msudder
  • 505
  • 3
  • 14

3 Answers3

1

Function defaults are evaluated at definition time, not call time (see "Least Astonishment" and the Mutable Default Argument).

The only way to access and modify the function defaults are through its __defaults__ property (func_defaults in older versions):

>>> def f(a=5):
...     return a
>>> f.__defaults__
(5,)
>>> f.__defaults__ = (99,)
>>> f()
99

Note that __defaults__ is a tuple so you cannot assign its members individually, but you can assign it as a whole.

Community
  • 1
  • 1
ecatmur
  • 152,476
  • 27
  • 293
  • 366
0
d = list(process.call_process.func_defaults)

In [10]: d
Out[10]: [True, True, 120]

In [11]: d[-1] = 5

In [12]: d
Out[12]: [True, True, 5]

In [13]: t = tuple(d)

In [14]: t
Out[14]: (True, True, 5)

In [15]: process.call_process.func_defaults = t
process.call_process('sleep 8')

call_process(cmd, verbose, shell, timeout, **kwargs)
     94         except:
     95             print(str(c.getName()) + 'running cmd "'+ cmd+ '" could not be terminated')
---> 96         raise TimeoutExpired('calling '+cmd)
     97     else:
     98         return c.response

TimeoutExpired: calling sleep 8

In [17]: call_process result: 0 :--:-None-:
ecatmur
  • 152,476
  • 27
  • 293
  • 366
msudder
  • 505
  • 3
  • 14
0

Concerning your original question about changing a default for testing purpose, you might want to use a dictionary which is a mutable object. See my answer there for details.

Community
  • 1
  • 1
foudfou
  • 976
  • 6
  • 11