有可能monkeypatch函数体中引入的局部变量?

时间:2016-12-06 14:28:18

标签: python python-3.x pytest

py.test monkeypatching/mocking documentation中没有提及,但是可以对函数体中引入的局部变量进行monkeypatch?

我的实验:

def my_method():
    my_var = 'foo'
    return my_var[:2]

测试是:

def test_my_method(monkeypatch):
    monkeypatch.setattr(my_module.MyClass.my_method.my_var, lambda: 'bar')
    assert my_method() == 'ba'
  

AttributeError:MyClass.my_method中的'function'对象没有   属性'my_var'

2 个答案:

答案 0 :(得分:6)

这是不可能的,因为变量不会提前存在,并且就我所知,py.test无法挂钩创建局部变量。

答案 1 :(得分:3)

稍加注意,就有可能使用ctypes在功能代码对象中修补const。

import ctypes
from contextlib import contextmanager

def tuple_setitem(tup, index, item):
    obj = ctypes.py_object(tup)
    item = ctypes.py_object(item)
    ref_count = ctypes.c_long.from_address(id(tup))
    original_count = ref_count.value
    if original_count != 1:
        ref_count.value = 1
    ctypes.pythonapi.Py_IncRef(item)
    ctypes.pythonapi.PyTuple_SetItem(obj, ctypes.c_ssize_t(index), item)
    ref_count.value = original_count

@contextmanager
def patch_tuple_item(tup, index, item):
    old = tup[index]
    try:
        tuple_setitem(tup, index, item)
        yield
    finally:
        tuple_setitem(tup, index, old)

演示:

>>> def my_method():
...     my_var = "foo"
...     return my_var[:2]
...
>>> consts = my_method.__code__.co_consts
>>> consts
(None, 'foo', 2)
>>> with patch_tuple_item(consts, index=1, item="bar"):
...     print(my_method())
...
ba
>>> print(my_method())
fo