Pandas 和 Unittest 之间的冲突?
Conflict between Pandas and Unittest?
考虑以下代码块(在 Jupyter notebook 中开发),预计会引发 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)
对于那些不熟悉 jupyter 笔记本的人,第一行只是将所有后续行导出到指定文件中。
现在如果我执行命令:
python3 tests.py
从终端(我在 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)
显然结果不如预期。但是,我注意到以下任一选项都能获得预期的结果。
- 用
%%writefile ...
注释掉第一行,用 Jupyter 笔记本 运行 注释掉代码片段(使用相同的 python 解释器)。
- 使用先前给出的命令从终端注释掉
import pandas as pd
行和 运行。
有人知道这里发生了什么吗?
作为参考,unittest
模块中case.py
中的相关行是
for v in sys.modules.values():
if getattr(v, '__warningregistry__', None):
v.__warningregistry__ = {}
这似乎是良性代码(我也认为它已经过足够的测试,可以说它不是问题的根源)。
此错误已在 Python's bug tracker 上提交。
The problem is in the iteration over sys.modules
in unittest.case._AssertWarnsContext.__enter__()
and accessing every module's __warningregistry__
attribute. On this access, the module-like objects may perform arbitrary actions including importing of further modules which extends sys.modules
.
sys.modules
是一个将模块名称映射到已加载模块的字典。
这个问题很难重现,因为关于测试运行器如何排序测试有“something platform dependent”。
考虑以下代码块(在 Jupyter notebook 中开发),预计会引发 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)
对于那些不熟悉 jupyter 笔记本的人,第一行只是将所有后续行导出到指定文件中。
现在如果我执行命令:
python3 tests.py
从终端(我在 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)
显然结果不如预期。但是,我注意到以下任一选项都能获得预期的结果。
- 用
%%writefile ...
注释掉第一行,用 Jupyter 笔记本 运行 注释掉代码片段(使用相同的 python 解释器)。 - 使用先前给出的命令从终端注释掉
import pandas as pd
行和 运行。
有人知道这里发生了什么吗?
作为参考,unittest
模块中case.py
中的相关行是
for v in sys.modules.values():
if getattr(v, '__warningregistry__', None):
v.__warningregistry__ = {}
这似乎是良性代码(我也认为它已经过足够的测试,可以说它不是问题的根源)。
此错误已在 Python's bug tracker 上提交。
The problem is in the iteration over
sys.modules
inunittest.case._AssertWarnsContext.__enter__()
and accessing every module's__warningregistry__
attribute. On this access, the module-like objects may perform arbitrary actions including importing of further modules which extendssys.modules
.
sys.modules
是一个将模块名称映射到已加载模块的字典。
这个问题很难重现,因为关于测试运行器如何排序测试有“something platform dependent”。