大熊猫和Unittest之间的冲突?

Cha*_*lie 10 python-3.x pandas python-unittest

考虑下面的代码块(在Jupyter笔记本中开发),AssertionError由于UserWarning没有触发,因此需要引发一个代码:

%%writefile Game/tests/tests.py
import unittest
import pandas as pd

class TestGame(unittest.TestCase):
    def test_getters(self):
        print('Just before the critical line.')
        with self.assertWarns(UserWarning):
            print('Just testing...')

suite = unittest.TestLoader().loadTestsFromTestCase(TestGame)
unittest.TextTestRunner().run(suite)
Run Code Online (Sandbox Code Playgroud)

对于那些不熟悉jupyter笔记本的人,第一行只是将所有后续行导出到指定的文件中.

现在,如果我执行命令:

python3 tests.py
Run Code Online (Sandbox Code Playgroud)

从终端(我在Ubuntu 14.04上使用Python 3.5.1),我得到一个Runtime Error- 堆栈跟踪如下:

Just before the critical line:
E
======================================================================
ERROR: test_getters (__main__.TestGame)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests.py", line 8, in test_getters
    with self.assertWarns(UserWarning):
  File "/opt/anaconda3/lib/python3.5/unittest/case.py", line 225, in __enter__
    for v in sys.modules.values():
RuntimeError: dictionary changed size during iteration

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (errors=1)
Run Code Online (Sandbox Code Playgroud)

显然结果不如预期.但是,我注意到以下任一选项都会获得预期的结果.

  1. %%writefile ...使用Jupyter笔记本(使用相同的python解释器)注释掉第一行并运行代码片段.
  2. import pandas as pd用前面给出的命令注释掉行并从终端运行.

有谁知道这里发生了什么?

作为参考,相关线路中case.py的在unittest模块是

for v in sys.modules.values():
    if getattr(v, '__warningregistry__', None):
        v.__warningregistry__ = {}
Run Code Online (Sandbox Code Playgroud)

这似乎是良性代码(我也认为它已经足够测试,说它不是问题的根源).

hon*_*gsy 2

此错误已在Python 的错误跟踪器上归档。

问题在于迭代sys.modulesunittest.case._AssertWarnsContext.__enter__()访问每个模块的__warningregistry__属性。在此访问中,类模块对象可以执行任意操作,包括导入扩展的其他模块sys.modules

sys.modules是一个将模块名称映射到加载模块的字典。

这个问题很难重现,因为测试运行者如何排序测试存在“一些依赖于平台的东西”。