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

Skip to content

Commit ad2dedd

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 ad2dedd

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-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: 25 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
@@ -84,6 +87,28 @@ def animate(i):
8487
anim = animation.FuncAnimation(fig, animate, init_func=init,
8588
frames=iter(range(5)))
8689

90+
def test_movie_writer_registry():
91+
ffmpeg_path = mpl.rcParams['animation.ffmpeg_path']
92+
# Not sure about the first state as there could be some writer
93+
# which set rcparams
94+
#assert_false(animation.writers._dirty)
95+
assert_true(len(animation.writers._registered) > 0)
96+
animation.writers.list() # resets dirty state
97+
assert_false(animation.writers._dirty)
98+
mpl.rcParams['animation.ffmpeg_path'] = u"not_available_ever_xxxx"
99+
assert_true(animation.writers._dirty)
100+
animation.writers.list() # resets
101+
assert_false(animation.writers._dirty)
102+
assert_false(animation.writers.is_available("ffmpeg"))
103+
# something which is garanteered to be available in path
104+
bin = u"python"
105+
mpl.rcParams['animation.ffmpeg_path'] = bin
106+
assert_true(animation.writers._dirty)
107+
animation.writers.list() # resets
108+
assert_false(animation.writers._dirty)
109+
assert_true(animation.writers.is_available("ffmpeg"))
110+
mpl.rcParams['animation.ffmpeg_path'] = ffmpeg_path
111+
87112

88113
if __name__ == "__main__":
89114
import nose

0 commit comments

Comments
 (0)