Skip to content

Warn if an animation is gc'd before doing anything. #18445

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

Merged
merged 1 commit into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion lib/matplotlib/animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import sys
from tempfile import TemporaryDirectory
import uuid
import warnings

import numpy as np

Expand Down Expand Up @@ -907,6 +908,8 @@ class Animation:
"""

def __init__(self, fig, event_source=None, blit=False):
self._draw_was_started = False

self._fig = fig
# Disables blitting for backends that don't support it. This
# allows users to request it if available, but still have a
Expand All @@ -931,6 +934,14 @@ def __init__(self, fig, event_source=None, blit=False):
if self._blit:
self._setup_blit()

def __del__(self):
if not getattr(self, '_draw_was_started', True):
warnings.warn(
'Animation was deleted without rendering anything. This is '
'most likely unintended. To prevent deletion, assign the '
'Animation to a variable that exists for as long as you need '
'the Animation.')

def _start(self, *args):
"""
Starts interactive animation. Adds the draw frame command to the GUI
Expand Down Expand Up @@ -1166,7 +1177,7 @@ def _draw_next_frame(self, framedata, blit):
def _init_draw(self):
# Initial draw to clear the frame. Also used by the blitting code
# when a clean base is required.
pass
self._draw_was_started = True

def _pre_draw(self, framedata, blit):
# Perform any cleaning or whatnot before the drawing of the frame.
Expand Down Expand Up @@ -1484,6 +1495,7 @@ def __init__(self, fig, artists, *args, **kwargs):
super().__init__(fig, *args, **kwargs)

def _init_draw(self):
super()._init_draw()
# Make all the artists involved in *any* frame invisible
figs = set()
for f in self.new_frame_seq():
Expand Down Expand Up @@ -1695,6 +1707,7 @@ def gen():
return gen()

def _init_draw(self):
super()._init_draw()
# Initialize the drawing either using the given init_func or by
# calling the draw function with the first item of the frame sequence.
# For blitting, the init_func should return a sequence of modified
Expand Down
9 changes: 9 additions & 0 deletions lib/matplotlib/tests/test_animation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import gc
import os
from pathlib import Path
import subprocess
Expand Down Expand Up @@ -75,6 +76,14 @@ def test_null_movie_writer():
assert writer._count == num_frames


def test_animation_delete():
anim = make_animation(frames=5)

with pytest.warns(Warning, match='Animation was deleted'):
del anim
gc.collect()


def test_movie_writer_dpi_default():
class DummyMovieWriter(animation.MovieWriter):
def _run(self):
Expand Down