-
-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use inline backend or Plots pane to display plots #142
Comments
What happens if you run pytest outside Spyder? In other words, is this problem due to how pytest and matplotlib works or is it due to something we do in Spyder and this plugin? |
@jitseniesen All tests pass, though no plots generated when ran via Anaconda Powershell Prompt. Tests also pass if the test |
Thanks. It looks like it is up to us then. Can you please give a minimal (or at least small) example of a test? |
Sure: import pytest
import matplotlib.pyplot as plt
def test_plot():
plt.plot(list(range(10)))
plt.show() # no stall if commented, but no plot either
if __name__ == '__main__':
pytest.main([__file__, "-s"]) |
spyder-unittest runs the tests as a regular python process (i.e. not on a ipython kernel). I'm not sure if it's possible to use spyder's inline backend (the plots pane) for rendering matplotlib output from such a process. However, in my opinion, unit tests are supposed to run automatically without user interaction. If the plot is (part of) the test result then the test should assert that it equals the expected result. You can use import pytest
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.testing.compare import compare_images
def test_plot_compare(tmp_path):
expected = 'baseline_test_plot.png'
actual = str(tmp_path / 'test_plot.png')
with mpl.rc_context(rc=mpl.rc_params()):
plt.plot(list(range(10)))
plt.savefig(actual)
assert compare_images(expected, actual, 0) is None
if __name__ == '__main__':
pytest.main([__file__, "-s"]) As a bonus you also get the difference image to see how exactly the actual result differs from the expected. The context manager is used here to make the test run correctly both on the spyder console and from the unittest plugin as the matplotlib rc settings used by spyder differ from the default values (figsize, dip, subplot.bottom). So if you create your baseline image in spyder and then run the test from the plugin it will fail unless you enforce the same parameters. |
@StefRe Thanks for the suggestion. From what I can tell, |
I guess we talk about different things, maybe I couldn't make myself clear or I misunderstood your question in the first place. |
@StefRe By "silencing isn't always an option" I meant I need to personally validate generated plots (can't code "check if annotation floats nicely near histogram"). True that I don't always need to do this across all files at once, and that a workaround is to silence everything most of the time to get coverage statistics - but that's just ignoring the problem, not fixing it. Admittedly I need the plots to also be generated inline, as sorting through dozens of generated windows manually is a no-no - so this complicates things further (for Spyder). Regardless, it's better than nothing. The issue can then be considered a "feature request". As far as a bug status, I'll call the issue resolved. |
I misunderstood the issue. I thought that the plugin behaves differently from running pytest directly (from the command line), which I would consider a bug. However, the problem is that it behaves differently from running in a Spyder console. That is fine with me, the Spyder console is meant to be used interactively and tests (normally) not. If you need to do manual validation, it is not automatic testing, so this seems to be a rather atypical use case. I don't think I'll be working on it anytime soon, but I'm happy to keep the issue open. |
@jitseniesen It's automatic once I validate all figures look as expected, e.g. changing any non-visual features don't require inspection - hence why I consider the issue part-solved. Glad it's kept open as an enhancement - but yes, nothing urgent, just a nice feature to look forward to. Thanks @StefRe for suggesting |
My handling of the suggestion, for others' reference; add below to import os
import matplotlib
if not os.environ.get('IS_MAIN', '0') == '1':
matplotlib.use('template') # suppress figures for spyder unit testing and, below to individual test files: # test code ...
if __name__ == '__main__':
os.environ['IS_MAIN'] = '1'
pytest.main([__file__, "-s"]) The effect is to suppress plots unless files are ran as |
I somehow lucked with the aforementioned workaround, as imports do happen before setting the environment flag. import os
if __name__ == '__main__':
os.environ['IS_MAIN'] = '1'
# other imports & code |
In order to disable interactive plotting of a program only when run from the spyder-unittest plugin, you can place the following def pytest_configure(config):
import traceback
t = traceback.extract_stack()
if 'pytestworker.py' in t[0][0]:
import matplotlib as mpl
mpl.use('template') It checks whether the program under test was called from Although it's more like a dirty trick than a clean solution (as it depends on spyder-unittest's internals) I think it still may be an acceptable workaround for your specific situation. |
@StefRe Indeed a better workaround - thanks. |
Matplotlib figures, if not closed, prevent testing (or any test code execution) from advancing. When running pytest via
pytest.main([__file__, "-s"])
(F5,__main__
), plots are inlined and there isn't a problem. Plots may be part of testing, so silencing isn't always an option.Moving plots to the Plots pane, or inline, or really anywhere as long as they don't stall testing would work. Is this currently doable?
The text was updated successfully, but these errors were encountered: