gpt4 book ai didi

Python 模拟错误 : stop called on unstarted patcher

转载 作者:行者123 更新时间:2023-11-28 20:05:37 26 4
gpt4 key购买 nike

我有一个函数,比方说 def temp .我正在通过以下方式 mock 它:

msg = "Mocked!!!!!!!"
@mock.patch.object(Someothermodule.Someclass,'Somefunction',create=True,side_effect=Error(Error.something,msg))

def temp(self,mock_A):

这是一个巨大的项目,所以不能在这里发布细节。但是正在发生的是函数 temp确实被 mock 了,我确实得到了正确的信息,但后来我得到了stop called on unstarted patcher程序失败了。这里有什么解决方法吗,它以某种方式禁用了 _exitmock或任何其他方法。我猜内容在某种程度上不足以创建整个场景,但这是我能做的最好的。

此外,如果我不提供 mock_A 会怎样功能def temp .在这种情况下补丁的作用是什么?

编辑:

我有一个解决方法,其中我定义了我的补丁如下:

@mock.patch.object(Someothermodule.Someclass,'Somefunction',create=True,some_function)
def temp(self):

现在的问题是

1) 当我使用 side_effect 时或 return_value我必须提供 mock_object到装饰器后面的函数。

2) 当我只是使用函数而不是 side_effect 时,我不需要为装饰器后面的函数提供模拟对象..

所以,

When we dont pass mock_obj,do all the function know about the patch?how exactly is this working?What is the difference between the scenario wherein we have to explicitly pass mock_object and wherein we dont have to?

(请注意,这与 new_callable 的定义中的 patch 有关。)

最佳答案

关于 patch 的基本信息:

Inside the body of the function or with statement, the target is patched with a new object. When the function/with statement exits the patch is undone.

If new is omitted, then the target is replaced with a MagicMock. If patch() is used as a decorator and new is omitted, the created mock is passed in as an extra argument to the decorated function. If patch() is used as a context manager the created mock is returned by the context manager.

第一个告诉我们补丁在函数体(装饰器案例)中充当上下文管理器。第二个告诉你是否不指定 new 参数(第一个在 patch 类函数中 targeting arguments 之后)补丁创建一个新的 MagicMock() 对象来修补目标,创建的模拟作为额外参数传递给装饰函数

这解释了问题的最后一部分,因为

@mock.patch.object(Someothermodule.Someclass,'Somefunction',create=True,some_function)
def temp(self):

你将 Someothermodule.Someclass.Somefunction 替换为 some_function object 并且 patch 装饰器不需要通过它到 temp

现在回到问题的根源:stop called on unstarted patcher 错误消息。

这意味着您尝试多次删除补丁。怎么可能?

如果您查看 mock.py代码你可以很容易地理解补丁不支持补丁堆栈,它被设计为每个上下文只执行一次。换句话说,如果您尝试修补已在您的上下文中修补的内容,您将得到相同的错误。在答案的最后,我提供了一个生成错误的合成示例。

在没有看到您的代码的情况下,如果您不使用模拟而是通过函数修补您的方法,我只能猜测和推测为什么您的问题seams 已修复。恕我直言,它的工作只是偶然,你在玩某种竞争条件。

我能做的是为您提供一种方法来解决您的问题,并提供一个良好的解决方法

如果您在补丁中多次调用 __exit__,则只需使用 patch 作为上下文管理器并覆盖 __exit__。一种未经测试的方法可能是:

def my_wrapper(f):
count = 0
@functools.wraps(f)
def exit(*args, **kwargs):
count += 1
print ("EXIT CALL {}".format(count))
f(*args, **kwargs)

def temp(self):
patcher = mock.patch.object(Someothermodule.Someclass,'Somefunction',create=True,side_effect=Error(Error.something,msg))
patcher.__exit__ = my_wrapper(patcher.__exit__)
with patcher as mock_A:
#... your stuff

最后是解决方法(仅在您找不到任何方法来修复双重调用时使用)

class MyStackPatch():
def __init__(p):
self._patcher = p
self._count = 0
self._lock = threading.RLock()

def __enter__(self):
with self._lock:
if not self._count:
self._patcher.start()
self._count += 1

def __exit__(self, *exc_info):
with self._lock:
self._count -= 1
if not self._count:
self._patcher.stop()


def temp(self):
patcher = mock.patch.object(Someothermodule.Someclass,'Somefunction',create=True,side_effect=Error(Error.something,msg))
with MyStackPatch(patcher) as mock_A:
#... your stuff

扩展它并编写装饰器也很容易...但我认为这足以解决问题。


这是一个生成 stop called on unstarted patcher 错误消息的合成示例。要生成它,我们必须在补丁上下文中再次调用补丁。我们可以通过递归或线程来完成,递归在这种情况下真的很奇怪。

target 调用 patched 方法并启动一个也调用 t() 的新线程。我使用了 Event() 来强制错误并使竞争条件始终为真。

import threading
from mock import patch

def somemethod():
pass

e = threading.Event()

@patch("__main__.somemethod")
def t(state,m):
if state:
e.set()
while e.is_set():
e.wait(.5)
somemethod()

def target():
threading.Thread(target=t,args=(True,)).start()
while not e.is_set():
e.wait(.1)
t(False)
e.clear()

target()
/usr/bin/python2.7 /home/damico/PycharmProjects/untitled1/mock_and_thread.py
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1214, in patched
patching.__exit__(*exc_info)
File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1376, in __exit__
raise RuntimeError('stop called on unstarted patcher')
RuntimeError: stop called on unstarted patcher

关于Python 模拟错误 : stop called on unstarted patcher,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29065512/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com