From e3cc8850528a85a022d6d2171ea9ed6627e18578 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 29 Nov 2020 16:10:22 +0100 Subject: [PATCH] Inline MovieWriter._frame_sink. It plays two fairly different roles in MovieWriter (it's the stdin of the long-standing ffmpeg-like subprocess) and FileMovieWriter (it's the ever-changing handle of the frame currently being saved), with different life-cycles and no reuse between the subclasses, so it's easier to just inline it at the call site (and skip a comment about how FileMovieWriter._frame_sink gets closed in grab_frame, hinting at the tight-coupling between the two of them). Also, no need to close the process stdin after calling communicate() -- communicate() does it for us. --- lib/matplotlib/animation.py | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 5803d7c31b76..097111d1ec41 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -344,13 +344,9 @@ def grab_frame(self, **savefig_kwargs): # All frames must have the same size to save the movie correctly. self.fig.set_size_inches(self._w, self._h) # Save the figure data to the sink, using the frame format and dpi. - self.fig.savefig(self._frame_sink(), format=self.frame_format, + self.fig.savefig(self._proc.stdin, format=self.frame_format, dpi=self.dpi, **savefig_kwargs) - def _frame_sink(self): - """Return the place to which frames should be written.""" - return self._proc.stdin - def _args(self): """Assemble list of encoder-specific command-line arguments.""" return NotImplementedError("args needs to be implemented by subclass.") @@ -358,7 +354,6 @@ def _args(self): def cleanup(self): """Clean-up and collect the process used to write the movie file.""" out, err = self._proc.communicate() - self._frame_sink().close() # Use the encoding/errors that universal_newlines would use. out = TextIOWrapper(BytesIO(out)).read() err = TextIOWrapper(BytesIO(err)).read() @@ -474,30 +469,18 @@ def _base_temp_name(self): # for extension and the prefix. return self.fname_format_str % (self.temp_prefix, self.frame_format) - def _frame_sink(self): - # Creates a filename for saving using the basename and the current - # counter. - path = Path(self._base_temp_name() % self._frame_counter) - - # Save the filename so we can delete it later if necessary - self._temp_paths.append(path) - _log.debug('FileMovieWriter.frame_sink: saving frame %d to path=%s', - self._frame_counter, path) - self._frame_counter += 1 # Ensures each created name is 'unique' - - # This file returned here will be closed once it's used by savefig() - # because it will no longer be referenced and will be gc-ed. - return open(path, 'wb') - def grab_frame(self, **savefig_kwargs): # docstring inherited # Overloaded to explicitly close temp file. - _log.debug('MovieWriter.grab_frame: Grabbing frame.') - # Tell the figure to save its data to the sink, using the - # frame format and dpi. - with self._frame_sink() as myframesink: - self.fig.savefig(myframesink, format=self.frame_format, - dpi=self.dpi, **savefig_kwargs) + # Creates a filename for saving using basename and counter. + path = Path(self._base_temp_name() % self._frame_counter) + self._temp_paths.append(path) # Record the filename for later cleanup. + self._frame_counter += 1 # Ensures each created name is unique. + _log.debug('FileMovieWriter.grab_frame: Grabbing frame %d to path=%s', + self._frame_counter, path) + with open(path, 'wb') as sink: # Save figure to the sink. + self.fig.savefig(sink, format=self.frame_format, dpi=self.dpi, + **savefig_kwargs) def finish(self): # Call run here now that all frame grabbing is done. All temp files