9
9
import pytest
10
10
11
11
import matplotlib as mpl
12
- from matplotlib import pyplot as plt , rc_context
12
+ from matplotlib import pyplot as plt
13
13
from matplotlib import animation
14
14
15
15
@@ -40,26 +40,8 @@ def finish(self):
40
40
pass
41
41
42
42
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 ):
58
44
# Test running an animation with NullMovieWriter.
59
-
60
- num_frames = 5
61
- anim = make_animation (frames = num_frames )
62
-
63
45
filename = "unused.null"
64
46
dpi = 50
65
47
savefig_kwargs = dict (foo = 0 )
@@ -68,17 +50,17 @@ def test_null_movie_writer():
68
50
anim .save (filename , dpi = dpi , writer = writer ,
69
51
savefig_kwargs = savefig_kwargs )
70
52
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
72
54
assert writer .outfile == filename
73
55
assert writer .dpi == dpi
74
56
assert writer .args == ()
75
57
assert writer .savefig_kwargs == savefig_kwargs
76
- assert writer ._count == num_frames
58
+ assert writer ._count == anim . save_count
77
59
78
60
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 )
82
64
with pytest .warns (Warning , match = 'Animation was deleted' ):
83
65
del anim
84
66
gc .collect ()
@@ -137,7 +119,7 @@ def isAvailable(cls):
137
119
138
120
139
121
@pytest .fixture ()
140
- def simple_animation ( ):
122
+ def anim ( request ):
141
123
fig , ax = plt .subplots ()
142
124
line , = ax .plot ([], [])
143
125
@@ -154,40 +136,48 @@ def animate(i):
154
136
line .set_data (x , y )
155
137
return line ,
156
138
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 )
158
145
159
146
160
147
# Smoke test for saving animations. In the future, we should probably
161
148
# design more sophisticated tests which compare resulting frames a-la
162
149
# matplotlib.testing.image_comparison
163
150
@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 ):
165
153
if not animation .writers .is_available (writer ):
166
154
pytest .skip ("writer '%s' not available on this system" % writer )
167
155
156
+ anim = animation .FuncAnimation (** anim )
168
157
dpi = None
169
158
codec = None
170
159
if writer == 'ffmpeg' :
171
160
# Issue #8253
172
- simple_animation [ 'fig' ] .set_size_inches ((10.85 , 9.21 ))
161
+ anim . _fig .set_size_inches ((10.85 , 9.21 ))
173
162
dpi = 100.
174
163
codec = 'h264'
175
164
176
165
# Use temporary directory for the file-based writers, which produce a file
177
166
# per frame with known names.
178
167
with tmpdir .as_cwd ():
179
- anim = animation .FuncAnimation (** simple_animation )
180
168
anim .save (output , fps = 30 , writer = writer , bitrate = 500 , dpi = dpi ,
181
169
codec = codec )
170
+ with pytest .warns (None ):
171
+ del anim
182
172
183
173
184
174
@pytest .mark .parametrize ('writer' , [
185
- pytest .param ('ffmpeg' ,
186
- marks = pytest .mark .skipif (
175
+ pytest .param (
176
+ 'ffmpeg' , marks = pytest .mark .skipif (
187
177
not animation .FFMpegWriter .isAvailable (),
188
178
reason = 'Requires FFMpeg' )),
189
- pytest .param ('imagemagick' ,
190
- marks = pytest .mark .skipif (
179
+ pytest .param (
180
+ 'imagemagick' , marks = pytest .mark .skipif (
191
181
not animation .ImageMagickWriter .isAvailable (),
192
182
reason = 'Requires ImageMagick' )),
193
183
])
@@ -196,8 +186,11 @@ def test_save_animation_smoketest(tmpdir, writer, output, simple_animation):
196
186
('html5' , '<video width' ),
197
187
('jshtml' , '<script ' )
198
188
])
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 )
201
194
with plt .rc_context ({'animation.writer' : writer ,
202
195
'animation.html' : html }):
203
196
html = anim ._repr_html_ ()
@@ -207,9 +200,10 @@ def test_animation_repr_html(writer, html, want, simple_animation):
207
200
assert want in html
208
201
209
202
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 ())
213
207
214
208
215
209
def test_movie_writer_registry ():
@@ -228,11 +222,12 @@ def test_movie_writer_registry():
228
222
not animation .writers .is_available (mpl .rcParams ["animation.writer" ]),
229
223
reason = "animation writer not installed" )),
230
224
"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 ):
232
227
caplog .set_level ("WARNING" )
233
228
with tmpdir .as_cwd ():
234
229
with mpl .rc_context ({"animation.embed_limit" : 1e-6 }): # ~1 byte.
235
- getattr (make_animation ( frames = 1 ) , method_name )()
230
+ getattr (anim , method_name )()
236
231
assert len (caplog .records ) == 1
237
232
record , = caplog .records
238
233
assert (record .name == "matplotlib.animation"
@@ -245,14 +240,15 @@ def test_embed_limit(method_name, caplog, tmpdir):
245
240
not animation .writers .is_available (mpl .rcParams ["animation.writer" ]),
246
241
reason = "animation writer not installed" )),
247
242
"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 ):
249
245
with tmpdir .as_cwd ():
250
- getattr (make_animation ( frames = 1 ) , method_name )()
246
+ getattr (anim , method_name )()
251
247
assert list (Path (str (tmpdir )).iterdir ()) == []
252
248
253
249
254
250
@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 ):
256
252
"""
257
253
Test that we correctly raise a CalledProcessError when ffmpeg fails.
258
254
@@ -267,7 +263,7 @@ def test_failing_ffmpeg(tmpdir, monkeypatch):
267
263
"[[ $@ -eq 0 ]]\n " )
268
264
os .chmod (str (exe_path ), 0o755 )
269
265
with pytest .raises (subprocess .CalledProcessError ):
270
- make_animation () .save ("test.mpeg" )
266
+ anim .save ("test.mpeg" )
271
267
272
268
273
269
@pytest .mark .parametrize ("cache_frame_data" , [False , True ])
0 commit comments