99import pytest
1010
1111import matplotlib as mpl
12- from matplotlib import pyplot as plt , rc_context
12+ from matplotlib import pyplot as plt
1313from matplotlib import animation
1414
1515
@@ -40,26 +40,8 @@ def finish(self):
4040 pass
4141
4242
43- def make_animation (** kwargs ):
44- fig , ax = plt .subplots ()
45- line , = ax .plot ([])
46-
47- def init ():
48- pass
49-
50- def animate (i ):
51- line .set_data ([0 , 1 ], [0 , i ])
52- return line ,
53-
54- return animation .FuncAnimation (fig , animate , ** kwargs )
55-
56-
57- def test_null_movie_writer ():
43+ def test_null_movie_writer (anim ):
5844 # Test running an animation with NullMovieWriter.
59-
60- num_frames = 5
61- anim = make_animation (frames = num_frames )
62-
6345 filename = "unused.null"
6446 dpi = 50
6547 savefig_kwargs = dict (foo = 0 )
@@ -68,17 +50,17 @@ def test_null_movie_writer():
6850 anim .save (filename , dpi = dpi , writer = writer ,
6951 savefig_kwargs = savefig_kwargs )
7052
71- assert writer .fig == plt .figure (1 ) # The figure used by make_animation.
53+ assert writer .fig == plt .figure (1 ) # The figure used by anim fixture
7254 assert writer .outfile == filename
7355 assert writer .dpi == dpi
7456 assert writer .args == ()
7557 assert writer .savefig_kwargs == savefig_kwargs
76- assert writer ._count == num_frames
58+ assert writer ._count == anim . save_count
7759
7860
79- def test_animation_delete ():
80- anim = make_animation ( frames = 5 )
81-
61+ @ pytest . mark . parametrize ( 'anim' , [ dict ( fixture = dict )], indirect = [ 'anim' ])
62+ def test_animation_delete ( anim ):
63+ anim = animation . FuncAnimation ( ** anim )
8264 with pytest .warns (Warning , match = 'Animation was deleted' ):
8365 del anim
8466 gc .collect ()
@@ -137,7 +119,7 @@ def isAvailable(cls):
137119
138120
139121@pytest .fixture ()
140- def simple_animation ( ):
122+ def anim ( request ):
141123 fig , ax = plt .subplots ()
142124 line , = ax .plot ([], [])
143125
@@ -154,40 +136,48 @@ def animate(i):
154136 line .set_data (x , y )
155137 return line ,
156138
157- return dict (fig = fig , func = animate , init_func = init , frames = 5 )
139+ # "fixture" can be passed to determine the class returned by the fixture
140+ kwargs = dict (getattr (request , 'param' , {})) # make a copy
141+ fixture = kwargs .pop ('fixture' , animation .FuncAnimation )
142+ if 'frames' not in kwargs :
143+ kwargs ['frames' ] = 5
144+ return fixture (fig = fig , func = animate , init_func = init , ** kwargs )
158145
159146
160147# Smoke test for saving animations. In the future, we should probably
161148# design more sophisticated tests which compare resulting frames a-la
162149# matplotlib.testing.image_comparison
163150@pytest .mark .parametrize ('writer, output' , WRITER_OUTPUT )
164- def test_save_animation_smoketest (tmpdir , writer , output , simple_animation ):
151+ @pytest .mark .parametrize ('anim' , [dict (fixture = dict )], indirect = ['anim' ])
152+ def test_save_animation_smoketest (tmpdir , writer , output , anim ):
165153 if not animation .writers .is_available (writer ):
166154 pytest .skip ("writer '%s' not available on this system" % writer )
167155
156+ anim = animation .FuncAnimation (** anim )
168157 dpi = None
169158 codec = None
170159 if writer == 'ffmpeg' :
171160 # Issue #8253
172- simple_animation [ 'fig' ] .set_size_inches ((10.85 , 9.21 ))
161+ anim . _fig .set_size_inches ((10.85 , 9.21 ))
173162 dpi = 100.
174163 codec = 'h264'
175164
176165 # Use temporary directory for the file-based writers, which produce a file
177166 # per frame with known names.
178167 with tmpdir .as_cwd ():
179- anim = animation .FuncAnimation (** simple_animation )
180168 anim .save (output , fps = 30 , writer = writer , bitrate = 500 , dpi = dpi ,
181169 codec = codec )
170+ with pytest .warns (None ):
171+ del anim
182172
183173
184174@pytest .mark .parametrize ('writer' , [
185- pytest .param ('ffmpeg' ,
186- marks = pytest .mark .skipif (
175+ pytest .param (
176+ 'ffmpeg' , marks = pytest .mark .skipif (
187177 not animation .FFMpegWriter .isAvailable (),
188178 reason = 'Requires FFMpeg' )),
189- pytest .param ('imagemagick' ,
190- marks = pytest .mark .skipif (
179+ pytest .param (
180+ 'imagemagick' , marks = pytest .mark .skipif (
191181 not animation .ImageMagickWriter .isAvailable (),
192182 reason = 'Requires ImageMagick' )),
193183])
@@ -196,8 +186,11 @@ def test_save_animation_smoketest(tmpdir, writer, output, simple_animation):
196186 ('html5' , '<video width' ),
197187 ('jshtml' , '<script ' )
198188])
199- def test_animation_repr_html (writer , html , want , simple_animation ):
200- anim = animation .FuncAnimation (** simple_animation )
189+ @pytest .mark .parametrize ('anim' , [dict (fixture = dict )], indirect = ['anim' ])
190+ def test_animation_repr_html (writer , html , want , anim ):
191+ # create here rather than in the fixture otherwise we get __del__ warnings
192+ # about producing no output
193+ anim = animation .FuncAnimation (** anim )
201194 with plt .rc_context ({'animation.writer' : writer ,
202195 'animation.html' : html }):
203196 html = anim ._repr_html_ ()
@@ -207,9 +200,10 @@ def test_animation_repr_html(writer, html, want, simple_animation):
207200 assert want in html
208201
209202
210- def test_no_length_frames ():
211- (make_animation (frames = iter (range (5 )))
212- .save ('unused.null' , writer = NullMovieWriter ()))
203+ @pytest .mark .parametrize ('anim' , [dict (frames = iter (range (5 )))],
204+ indirect = ['anim' ])
205+ def test_no_length_frames (anim ):
206+ anim .save ('unused.null' , writer = NullMovieWriter ())
213207
214208
215209def test_movie_writer_registry ():
@@ -228,11 +222,12 @@ def test_movie_writer_registry():
228222 not animation .writers .is_available (mpl .rcParams ["animation.writer" ]),
229223 reason = "animation writer not installed" )),
230224 "to_jshtml" ])
231- def test_embed_limit (method_name , caplog , tmpdir ):
225+ @pytest .mark .parametrize ('anim' , [dict (frames = 1 )], indirect = ['anim' ])
226+ def test_embed_limit (method_name , caplog , tmpdir , anim ):
232227 caplog .set_level ("WARNING" )
233228 with tmpdir .as_cwd ():
234229 with mpl .rc_context ({"animation.embed_limit" : 1e-6 }): # ~1 byte.
235- getattr (make_animation ( frames = 1 ) , method_name )()
230+ getattr (anim , method_name )()
236231 assert len (caplog .records ) == 1
237232 record , = caplog .records
238233 assert (record .name == "matplotlib.animation"
@@ -245,14 +240,15 @@ def test_embed_limit(method_name, caplog, tmpdir):
245240 not animation .writers .is_available (mpl .rcParams ["animation.writer" ]),
246241 reason = "animation writer not installed" )),
247242 "to_jshtml" ])
248- def test_cleanup_temporaries (method_name , tmpdir ):
243+ @pytest .mark .parametrize ('anim' , [dict (frames = 1 )], indirect = ['anim' ])
244+ def test_cleanup_temporaries (method_name , tmpdir , anim ):
249245 with tmpdir .as_cwd ():
250- getattr (make_animation ( frames = 1 ) , method_name )()
246+ getattr (anim , method_name )()
251247 assert list (Path (str (tmpdir )).iterdir ()) == []
252248
253249
254250@pytest .mark .skipif (os .name != "posix" , reason = "requires a POSIX OS" )
255- def test_failing_ffmpeg (tmpdir , monkeypatch ):
251+ def test_failing_ffmpeg (tmpdir , monkeypatch , anim ):
256252 """
257253 Test that we correctly raise a CalledProcessError when ffmpeg fails.
258254
@@ -267,7 +263,7 @@ def test_failing_ffmpeg(tmpdir, monkeypatch):
267263 "[[ $@ -eq 0 ]]\n " )
268264 os .chmod (str (exe_path ), 0o755 )
269265 with pytest .raises (subprocess .CalledProcessError ):
270- make_animation () .save ("test.mpeg" )
266+ anim .save ("test.mpeg" )
271267
272268
273269@pytest .mark .parametrize ("cache_frame_data" , [False , True ])
0 commit comments