Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 14e6e5f

Browse filesBrowse files
authored
Merge pull request #12369 from anntzer/animation-failure
Improved exception handling on animation failure
2 parents 747c2a7 + 258c53b commit 14e6e5f
Copy full SHA for 14e6e5f

File tree

Expand file treeCollapse file tree

3 files changed

+32
-41
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+32
-41
lines changed
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Exception on failing animations changed
2+
```````````````````````````````````````
3+
4+
Previously, subprocess failures in the animation framework would raise either
5+
in a `RuntimeError` or a `ValueError` depending on when the error occurred.
6+
They now raise a `subprocess.CalledProcessError` with attributes set as
7+
documented by the exception class.

‎lib/matplotlib/animation.py

Copy file name to clipboardExpand all lines: lib/matplotlib/animation.py
+21-35Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -364,22 +364,14 @@ def grab_frame(self, **savefig_kwargs):
364364
command that saves the figure.
365365
'''
366366
_log.debug('MovieWriter.grab_frame: Grabbing frame.')
367-
try:
368-
# re-adjust the figure size in case it has been changed by the
369-
# user. We must ensure that every frame is the same size or
370-
# the movie will not save correctly.
371-
self.fig.set_size_inches(self._w, self._h)
372-
# Tell the figure to save its data to the sink, using the
373-
# frame format and dpi.
374-
self.fig.savefig(self._frame_sink(), format=self.frame_format,
375-
dpi=self.dpi, **savefig_kwargs)
376-
except (RuntimeError, IOError) as e:
377-
out, err = self._proc.communicate()
378-
_log.info('MovieWriter -- Error running proc:\n%s\n%s', out, err)
379-
raise IOError('Error saving animation to file (cause: {0}) '
380-
'Stdout: {1} StdError: {2}. It may help to re-run '
381-
'with logging level set to '
382-
'DEBUG.'.format(e, out, err))
367+
# re-adjust the figure size in case it has been changed by the
368+
# user. We must ensure that every frame is the same size or
369+
# the movie will not save correctly.
370+
self.fig.set_size_inches(self._w, self._h)
371+
# Tell the figure to save its data to the sink, using the
372+
# frame format and dpi.
373+
self.fig.savefig(self._frame_sink(), format=self.frame_format,
374+
dpi=self.dpi, **savefig_kwargs)
383375

384376
def _frame_sink(self):
385377
'''Returns the place to which frames should be written.'''
@@ -396,15 +388,15 @@ def cleanup(self):
396388
# Use the encoding/errors that universal_newlines would use.
397389
out = TextIOWrapper(BytesIO(out)).read()
398390
err = TextIOWrapper(BytesIO(err)).read()
399-
_log.debug("MovieWriter stdout:\n%s", out)
400-
_log.debug("MovieWriter stderr:\n%s", err)
391+
_log.log(
392+
logging.WARNING if self._proc.returncode else logging.DEBUG,
393+
"MovieWriter stdout:\n%s", out)
394+
_log.log(
395+
logging.WARNING if self._proc.returncode else logging.DEBUG,
396+
"MovieWriter stderr:\n%s", err)
401397
if self._proc.returncode:
402-
raise RuntimeError('Error creating movie, return code {}\n'
403-
'stdout:\n'
404-
'{}\n'
405-
'stderr:\n'
406-
'{}\n'
407-
.format(self._proc.returncode, out, err))
398+
raise subprocess.CalledProcessError(
399+
self._proc.returncode, self._proc.args, out, err)
408400

409401
@classmethod
410402
def bin_path(cls):
@@ -511,17 +503,11 @@ def grab_frame(self, **savefig_kwargs):
511503
'''
512504
# Overloaded to explicitly close temp file.
513505
_log.debug('MovieWriter.grab_frame: Grabbing frame.')
514-
try:
515-
# Tell the figure to save its data to the sink, using the
516-
# frame format and dpi.
517-
with self._frame_sink() as myframesink:
518-
self.fig.savefig(myframesink, format=self.frame_format,
519-
dpi=self.dpi, **savefig_kwargs)
520-
521-
except RuntimeError:
522-
out, err = self._proc.communicate()
523-
_log.info('MovieWriter -- Error running proc:\n%s\n%s', out, err)
524-
raise
506+
# Tell the figure to save its data to the sink, using the
507+
# frame format and dpi.
508+
with self._frame_sink() as myframesink:
509+
self.fig.savefig(myframesink, format=self.frame_format,
510+
dpi=self.dpi, **savefig_kwargs)
525511

526512
def finish(self):
527513
# Call run here now that all frame grabbing is done. All temp files

‎lib/matplotlib/tests/test_animation.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_animation.py
+4-6Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from pathlib import Path
3+
import subprocess
34
import sys
45

56
import numpy as np
@@ -237,13 +238,10 @@ def test_cleanup_temporaries(method_name, tmpdir):
237238
assert list(Path(str(tmpdir)).iterdir()) == []
238239

239240

240-
# Currently, this fails with a ValueError after we try to communicate() twice
241-
# with the Popen.
242-
@pytest.mark.xfail
243241
@pytest.mark.skipif(os.name != "posix", reason="requires a POSIX OS")
244242
def test_failing_ffmpeg(tmpdir, monkeypatch):
245243
"""
246-
Test that we correctly raise an OSError when ffmpeg fails.
244+
Test that we correctly raise a CalledProcessError when ffmpeg fails.
247245
248246
To do so, mock ffmpeg using a simple executable shell script that
249247
succeeds when called with no arguments (so that it gets registered by
@@ -252,12 +250,12 @@ def test_failing_ffmpeg(tmpdir, monkeypatch):
252250
try:
253251
with tmpdir.as_cwd():
254252
monkeypatch.setenv("PATH", ".:" + os.environ["PATH"])
255-
exe_path = Path(tmpdir, "ffmpeg")
253+
exe_path = Path(str(tmpdir), "ffmpeg")
256254
exe_path.write_text("#!/bin/sh\n"
257255
"[[ $@ -eq 0 ]]\n")
258256
os.chmod(str(exe_path), 0o755)
259257
animation.writers.reset_available_writers()
260-
with pytest.raises(OSError):
258+
with pytest.raises(subprocess.CalledProcessError):
261259
make_animation().save("test.mpeg")
262260
finally:
263261
animation.writers.reset_available_writers()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.