Thanks to visit codestin.com
Credit goes to github.com

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)