8000 Reset the available animation movie writer on rcParam change · matplotlib/matplotlib@90b8e27 · GitHub
[go: up one dir, main page]

Skip to content {"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}

Commit 90b8e27

Browse files
committed
Reset the available animation movie writer on rcParam change
If one of the rcParams for a path to a program, which was called by a movie writer, is changed, the the available movie writer in the registry should be reevaluated if they are (still/became) available. This also fixes the problem that you have to set the path to a movie writer before importing mpl.animation, as before the state was fixed on import time.
1 parent b698502 commit 90b8e27

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

lib/matplotlib/animation.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@
6363
class MovieWriterRegistry(object):
6464
def __init__(self):
6565
self.avail = dict()
66+
self._registered = dict()
67+
self._dirty = False
68+
69+
def set_dirty(self):
70+
"""Sets a flag to re-setup the writers"""
71+
self._dirty = True
6672

6773
# Returns a decorator that can be used on classes to register them under
6874
# a name. As in:
@@ -71,19 +77,36 @@ def __init__(self):
7177
# pass
7278
def register(self, name):
7379
def wrapper(writerClass):
80+
self._registered[name] = writerClass
7481
if writerClass.isAvailable():
7582
self.avail[name] = writerClass
7683
return writerClass
7784
return wrapper
7885

86+
def endsure_not_dirty(self):
87+
"""If dirty, reasks the writers if they are available"""
88+
if self._dirty:
89+
self.reset_available_writers()
90+
91+
def reset_available_writers(self):
92+
"""Reset the available state of all registered writers"""
93+
self.avail = {}
94+
for name, writerClass in self._registered.items():
95+
if writerClass.isAvailable():
96+
self.avail[name] = writerClass
97+
self._dirty = False
98+
7999
def list(self):
80100
''' Get a list of available MovieWriters.'''
101+
self.endsure_not_dirty()
81102
return list(self.avail.keys())
82103

83104
def is_available(self, name):
105+
self.endsure_not_dirty()
84106
return name in self.avail
85107

86108
def __getitem__(self, name):
109+
self.endsure_not_dirty()
87110
if not self.avail:
88111
raise RuntimeError("No MovieWriters available!")
89112
return self.avail[name]

lib/matplotlib/rcsetup.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,21 @@ def validate_hist_bins(s):
786786
raise ValueError("'hist.bins' must be 'auto', an int or " +
787787
"a sequence of floats")
788788

789+
def validate_animation_writer_path(p):
790+
# Make sure it's a string and then figure out if the animations
791+
# are already loaded and reset the writers (which will validate
792+
# the path on next call)
793+
if not isinstance(p, six.text_type):
794+
raise ValueError("path must be a (unicode) string")
795+
from sys import modules
796+
# set dirty, so that the next call to the reistry will reevaluate
797+
# the state.
798+
# only set dirty if already loaded. If not loaded, the load will
799+
# trigger the checks.
800+
if "matplotlib.animation" in modules:
801+
modules["matplotlib.animation"].writers.set_dirty()
802+
return p
803+
789804

790805
# a map from key -> value, converter
791806
defaultParams = {
@@ -1192,20 +1207,20 @@ def validate_hist_bins(s):
11921207
# Controls image format when frames are written to disk
11931208
'animation.frame_format': ['png', validate_movie_frame_fmt],
11941209
# Path to FFMPEG binary. If just binary name, subprocess uses $PATH.
1195-
'animation.ffmpeg_path': ['ffmpeg', six.text_type],
1210+
'animation.ffmpeg_path': ['ffmpeg', validate_animation_writer_path],
11961211

11971212
# Additional arguments for ffmpeg movie writer (using pipes)
11981213
'animation.ffmpeg_args': [[], validate_stringlist],
11991214
# Path to AVConv binary. If just binary name, subprocess uses $PATH.
1200-
'animation.avconv_path': ['avconv', six.text_type],
1215+
'animation.avconv_path': ['avconv', validate_animation_writer_path],
12011216
# Additional arguments for avconv movie writer (using pipes)
12021217
'animation.avconv_args': [[], validate_stringlist],
12031218
# Path to MENCODER binary. If just binary name, subprocess uses $PATH.
1204-
'animation.mencoder_path': ['mencoder', six.text_type],
1219+
'animation.mencoder_path': ['mencoder', validate_animation_writer_path],
12051220
# Additional arguments for mencoder movie writer (using pipes)
12061221
'animation.mencoder_args': [[], validate_stringlist],
12071222
# Path to convert binary. If just binary name, subprocess uses $PATH
1208-
'animation.convert_path': ['convert', six.text_type],
1223+
'animation.convert_path': ['convert', validate_animation_writer_path],
12091224
# Additional arguments for mencoder movie writer (using pipes)
12101225

12111226
'animation.convert_args': [[], validate_stringlist],

lib/matplotlib/tests/test_animation.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
from matplotlib.externals import six
55

66
import os
7+
import sys
78
import tempfile
89
import numpy as np
910
from nose import with_setup
11+
from nose.tools import assert_false, assert_true
12+
import matplotlib as mpl
1013
from matplotlib import pyplot as plt
1114
from matplotlib import animation
1215
from matplotlib.testing.noseclasses import KnownFailureTest
@@ -85,6 +88,29 @@ def animate(i):
8588
frames=iter(range(5)))
8689

8790

91+
def test_movie_writer_registry():
92+
ffmpeg_path = mpl.rcParams['animation.ffmpeg_path']
93+
# Not sure about the first state as there could be some writer
94+
# which set rcparams
95+
#assert_false(animation.writers._dirty)
96+
assert_true(len(animation.writers._registered) > 0)
97+
animation.writers.list() # resets dirty state
98+
assert_false(animation.writers._dirty)
99+
mpl.rcParams['animation.ffmpeg_path'] = u"not_available_ever_xxxx"
100+
assert_true(animation.writers._dirty)
101+
animation.writers.list() # resets
102+
assert_false(animation.writers._dirty)
103+
assert_false(animation.writers.is_available("ffmpeg"))
104+
# something which is garanteered to be available in path
105+
bin = u"python"
106+
mpl.rcParams['animation.ffmpeg_path'] = bin
107+
assert_true(animation.writers._dirty)
108+
animation.writers.list() # resets
109+
assert_false(animation.writers._dirty)
110+
assert_true(animation.writers.is_available("ffmpeg"))
111+
mpl.rcParams['animation.ffmpeg_path'] = ffmpeg_path
112+
113+
88114
if __name__ == "__main__":
89115
import nose
90116
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

0 commit comments

Comments
 (0)
0