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

Skip to content

Commit e3e2be9

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 7b517da commit e3e2be9

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
@@ -64,6 +64,12 @@
6464
class MovieWriterRegistry(object):
6565
def __init__(self):
6666
self.avail = dict()
67+
self._registered = dict()
68+
self._dirty = False
69+
70+
def set_dirty(self):
71+
"""Sets a flag to re-setup the writers"""
72+
self._dirty = True
6773

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

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

84105
def is_available(self, name):
106+
self.ensure_not_dirty()
85107
return name in self.avail
86108

87109
def __getitem__(self, name):
110+
self.ensure_not_dirty()
88111
if not self.avail:
89112
raise RuntimeError("No MovieWriters available!")
90113
return self.avail[name]

lib/matplotlib/rcsetup.py

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

805+
def validate_animation_writer_path(p):
806+
# Make sure it's a string and then figure out if the animations
807+
# are already loaded and reset the writers (which will validate
808+
# the path on next call)
809+
if not isinstance(p, six.text_type):
810+
raise ValueError("path must be a (unicode) string")
811+
from sys import modules
812+
# set dirty, so that the next call to the registry will re-evaluate
813+
# the state.
814+
# only set dirty if already loaded. If not loaded, the load will
815+
# trigger the checks.
816+
if "matplotlib.animation" in modules:
817+
modules["matplotlib.animation"].writers.set_dirty()
818+
return p
819+
805820

806821
# a map from key -> value, converter
807822
defaultParams = {
@@ -1222,20 +1237,20 @@ def validate_hist_bins(s):
12221237
# Controls image format when frames are written to disk
12231238
'animation.frame_format': ['png', validate_movie_frame_fmt],
12241239
# Path to FFMPEG binary. If just binary name, subprocess uses $PATH.
1225-
'animation.ffmpeg_path': ['ffmpeg', six.text_type],
1240+
'animation.ffmpeg_path': ['ffmpeg', validate_animation_writer_path],
12261241

12271242
# Additional arguments for ffmpeg movie writer (using pipes)
12281243
'animation.ffmpeg_args': [[], validate_stringlist],
12291244
# Path to AVConv binary. If just binary name, subprocess uses $PATH.
1230-
'animation.avconv_path': ['avconv', six.text_type],
1245+
'animation.avconv_path': ['avconv', validate_animation_writer_path],
12311246
# Additional arguments for avconv movie writer (using pipes)
12321247
'animation.avconv_args': [[], validate_stringlist],
12331248
# Path to MENCODER binary. If just binary name, subprocess uses $PATH.
1234-
'animation.mencoder_path': ['mencoder', six.text_type],
1249+
'animation.mencoder_path': ['mencoder', validate_animation_writer_path],
12351250
# Additional arguments for mencoder movie writer (using pipes)
12361251
'animation.mencoder_args': [[], validate_stringlist],
12371252
# Path to convert binary. If just binary name, subprocess uses $PATH
1238-
'animation.convert_path': ['convert', six.text_type],
1253+
'animation.convert_path': ['convert', validate_animation_writer_path],
12391254
# Additional arguments for mencoder movie writer (using pipes)
12401255

12411256
'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,10 +4,13 @@
44
from matplotlib.externals import six
55

66
import os
7+
import sys
78
import tempfile
89
import numpy as np
910
from numpy.testing import assert_equal
1011
from nose import with_setup
12+
from nose.tools import assert_false, assert_true
13+
import matplotlib as mpl
1114
from matplotlib import pyplot as plt
1215
from matplotlib import animation
1316
from matplotlib.testing.noseclasses import KnownFailureTest
@@ -163,6 +166,29 @@ def animate(i):
163166
frames=iter(range(5)))
164167

165168

169+
def test_movie_writer_registry():
170+
ffmpeg_path = mpl.rcParams['animation.ffmpeg_path']
171+
# Not sure about the first state as there could be some writer
172+
# which set rcparams
173+
#assert_false(animation.writers._dirty)
174+
assert_true(len(animation.writers._registered) > 0)
175+
animation.writers.list() # resets dirty state
176+
assert_false(animation.writers._dirty)
177+
mpl.rcParams['animation.ffmpeg_path'] = u"not_available_ever_xxxx"
178+
assert_true(animation.writers._dirty)
179+
animation.writers.list() # resets
180+
assert_false(animation.writers._dirty)
181+
assert_false(animation.writers.is_available("ffmpeg"))
182+
# something which is garanteered to be available in path
183+
bin = u"python"
184+
mpl.rcParams['animation.ffmpeg_path'] = bin
185+
assert_true(animation.writers._dirty)
186+
animation.writers.list() # resets
187+
assert_false(animation.writers._dirty)
188+
assert_true(animation.writers.is_available("ffmpeg"))
189+
mpl.rcParams['animation.ffmpeg_path'] = ffmpeg_path
190+
191+
166192
if __name__ == "__main__":
167193
import nose
168194
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

0 commit comments

Comments
 (0)
0