-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Reset the available animation movie writer on rcParam change #5628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e3e2be9
6a01829
6c6cf91
96b439a
9b61b34
33f564a
e783867
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,12 @@ | |
class MovieWriterRegistry(object): | ||
def __init__(self): | ||
self.avail = dict() | ||
self._registered = dict() | ||
self._dirty = False | ||
|
||
def set_dirty(self): | ||
"""Sets a flag to re-setup the writers""" | ||
self._dirty = True | ||
|
||
# Returns a decorator that can be used on classes to register them under | ||
# a name. As in: | ||
|
@@ -72,19 +78,36 @@ def __init__(self): | |
# pass | ||
def register(self, name): | ||
def wrapper(writerClass): | ||
self._registered[name] = writerClass | ||
if writerClass.isAvailable(): | ||
self.avail[name] = writerClass | ||
return writerClass | ||
return wrapper | ||
|
||
def ensure_not_dirty(self): | ||
"""If dirty, reasks the writers if they are available""" | ||
if self._dirty: | ||
self.reset_available_writers() | ||
|
||
def reset_available_writers(self): | ||
"""Reset the available state of all registered writers""" | ||
self.avail = {} | ||
for name, writerClass in self._registered.items(): | ||
if writerClass.isAvailable(): | ||
self.avail[name] = writerClass | ||
self._dirty = False | ||
|
||
def list(self): | ||
''' Get a list of available MovieWriters.''' | ||
self.ensure_not_dirty() | ||
return list(self.avail.keys()) | ||
|
||
def is_available(self, name): | ||
self.ensure_not_dirty() | ||
return name in self.avail | ||
|
||
def __getitem__(self, name): | ||
self.ensure_not_dirty() | ||
if not self.avail: | ||
raise RuntimeError("No MovieWriters available!") | ||
return self.avail[name] | ||
|
@@ -315,10 +338,11 @@ def isAvailable(cls): | |
Check to see if a MovieWriter subclass is actually available by | ||
running the commandline tool. | ||
''' | ||
if not cls.bin_path(): | ||
bin_path = cls.bin_path() | ||
if not bin_path: | ||
return False | ||
try: | ||
p = subprocess.Popen(cls.bin_path(), | ||
p = subprocess.Popen(bin_path, | ||
shell=False, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
|
@@ -432,9 +456,19 @@ def finish(self): | |
# Check error code for creating file here, since we just run | ||
# the process here, rather than having an open pipe. | ||
if self._proc.returncode: | ||
raise RuntimeError('Error creating movie, return code: ' | ||
+ str(self._proc.returncode) | ||
+ ' Try running with --verbose-debug') | ||
try: | ||
stdout = [s.decode() for s in self._proc._stdout_buff] | ||
stderr = [s.decode() for s in self._proc._stderr_buff] | ||
verbose.report("MovieWriter.finish: stdout: %s" % stdout, | ||
level='helpful') | ||
verbose.report("MovieWriter.finish: stderr: %s" % stderr, | ||
level='helpful') | ||
except Exception as e: | ||
pass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not my finest code, but it works on py35... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just to provide improved debugging feed back right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, when the called converter fails and the user adds the Unfortunately, it doesn't work for the unittests unless I add such a |
||
msg = ('Error creating movie, return code: ' + | ||
str(self._proc.returncode) + | ||
' Try setting mpl.verbose.set_level("helpful")') | ||
raise RuntimeError(msg) | ||
|
||
def cleanup(self): | ||
MovieWriter.cleanup(self) | ||
|
@@ -619,12 +653,28 @@ def _init_from_registry(cls): | |
binpath = '' | ||
rcParams[cls.exec_key] = rcParamsDefault[cls.exec_key] = binpath | ||
|
||
@classmethod | ||
def isAvailable(cls): | ||
''' | ||
Check to see if a ImageMagickWriter is actually available | ||
|
||
Done by first checking the windows registry (if applicable) and then | ||
running the commandline tool. | ||
''' | ||
bin_path = cls.bin_path() | ||
if bin_path == "convert": | ||
cls._init_from_registry() | ||
return super(ImageMagickBase, cls).isAvailable() | ||
|
||
ImageMagickBase._init_from_registry() | ||
|
||
|
||
# Note: the base classes need to be in that order to get | ||
# isAvailable() from ImageMagickBase called and not the | ||
# one from MovieWriter. The latter is then called by the | ||
# former. | ||
@writers.register('imagemagick') | ||
class ImageMagickWriter(MovieWriter, ImageMagickBase): | ||
class ImageMagickWriter(ImageMagickBase, MovieWriter): | ||
def _args(self): | ||
return ([self.bin_path(), | ||
'-size', '%ix%i' % self.frame_size, '-depth', '8', | ||
|
@@ -633,8 +683,12 @@ def _args(self): | |
+ self.output_args) | ||
|
||
|
||
# Note: the base classes need to be in that order to get | ||
# isAvailable() from ImageMagickBase called and not the | ||
# one from MovieWriter. The latter is then called by the | ||
# former. | ||
@writers.register('imagemagick_file') | ||
class ImageMagickFileWriter(FileMovieWriter, ImageMagickBase): | ||
class ImageMagickFileWriter(ImageMagickBase, FileMovieWriter): | ||
supported_formats = ['png', 'jpeg', 'ppm', 'tiff', 'sgi', 'bmp', | ||
'pbm', 'raw', 'rgba'] | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW: should that be "is_available"? It's the only method in that class(es) which use CamelCase instead of underscores...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is annoying, but I don't think worth breaking user code over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At most, we can rename and add an alias
isAvailable
->is_available
with the@deprecated
decorator.