ValueError:展开时出现包装循环

问题描述 投票:0回答:2

Python3 测试用例(文档测试)在我的示例代码中失败。但在 Python2 中同样可以正常工作。

test.py

class Test(object):
    def __init__(self, a=0):
        self.a = a

    def __getattr__(self, attr):
        return Test(a=str(self.a) + attr)

tst.py

from test import Test

t = Test()

运行测试用例:

python3 -m doctest -v tst.py

错误:

Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3.6/doctest.py", line 2787, in <module>
    sys.exit(_test())
  File "/usr/lib/python3.6/doctest.py", line 2777, in _test
    failures, _ = testmod(m, verbose=verbose, optionflags=options)
  File "/usr/lib/python3.6/doctest.py", line 1950, in testmod
    for test in finder.find(m, name, globs=globs, extraglobs=extraglobs):
  File "/usr/lib/python3.6/doctest.py", line 933, in find
    self._find(tests, obj, name, module, source_lines, globs, {})
  File "/usr/lib/python3.6/doctest.py", line 992, in _find
    if ((inspect.isroutine(inspect.unwrap(val))
  File "/usr/lib/python3.6/inspect.py", line 513, in unwrap
    raise ValueError('wrapper loop when unwrapping {!r}'.format(f))
ValueError: wrapper loop when unwrapping <test.Test object at 0x7f6e80028550>
python doctest
2个回答
8
投票

对于

unittest.mock
尝试将项目导入为

from unittest import mock

而不是

from unittest.mock import patch

这解决了我的错误。


6
投票

这可以说是 doctest 中的一个错误。发生的情况是 doctest 正在使用文档字符串搜索函数/方法/可调用对象,并且在执行此操作时,它会“展开”它找到的任何装饰器。为什么它会这样做,我不知道。但无论如何, doctest 最终会调用 inspect.unwrap(t) (其中

t
是一个
Test
实例),这本质上相当于这样做:

while True: try: t = t.__wrapped__ except AttributeError: break

因为 
t

是一个

Test
实例,访问
t.__wrapped__
会调用
__getattr__
并返回一个新的
Test
实例。这会永远持续下去,但是
inspect.unwrap
足够聪明,注意到它没有到达任何地方,并抛出异常而不是进入无限循环。

作为解决方法,您可以重写
__getattr__

方法,以在访问

AttributeError
时抛出
__wrapped__
。更好的是,当访问
any
dunder-attribute 时抛出 AttributeError: def __getattr__(self, attr): if attr.startswith('__') and attr.endswith('__'): raise AttributeError return Test(a=str(self.a) + attr)

© www.soinside.com 2019 - 2024. All rights reserved.