Consider the following block of code (developed inside a Jupyter notebook), for which it is expected that an AssertionError
is raised because a UserWarning
is not triggered:
%%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)
For those unfamiliar with jupyter notebooks, the first line simply exports all following lines into the specified file.
Now if I execute the command:
python3 tests.py
from the terminal (I am using Python 3.5.1 on Ubuntu 14.04), I get a Runtime Error
- the stack trace follows:
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)
Obviously the results are not as expected. However, I notice that either of the following options gets the expected results.
%%writefile ...
and running the code snippet with the Jupyter notebook (which uses the same python interpreter).import pandas as pd
line and running from terminal with the previously given command.Does anyone understand what's going on here?
For reference, the relevant lines in case.py
in the unittest
module are
for v in sys.modules.values():
if getattr(v, '__warningregistry__', None):
v.__warningregistry__ = {}
which would seem to be benign code (which I would also presume is tested enough to say that it's not the source of the problem).
This bug has been filed on 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
is a dict mapping module names to loaded modules.
This problem is difficult to reproduce because there's "something platform dependent" about how the test runner orders the tests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With