Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9cd3fbe

Browse files
committed
Figure equality-based tests.
Implement a `check_figures_equal` decorator, which allows tests whereboth the reference and the test image are generated. The idea is toallow tests of the form "this feature should be equivalent to that(usually more complex) way of achieving the same thing" without furtherbloating the test image directory.The saved images are properly created in the `result_images` folder, butcannot be "accepted" or "rejected" using the triage_tests UI (as thereis indeed no reference image to be saved in the repo).Includes an example use case.
1 parentaf7a74b commit9cd3fbe

File tree

3 files changed

+70
-25
lines changed

3 files changed

+70
-25
lines changed

‎lib/matplotlib/testing/decorators.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,46 @@ def image_comparison(baseline_images, extensions=None, tol=0,
407407
savefig_kwargs=savefig_kwarg,style=style)
408408

409409

410+
defcheck_figures_equal(*,extensions=("png","pdf","svg"),tol=0):
411+
"""
412+
Decorator for test cases that generate and compare two figures.
413+
414+
The decorated function must take two arguments, *fig_test* and *fig_ref*,
415+
and draw the test and reference images on them. After the function
416+
returns, the figures are saved and compared.
417+
418+
Arguments
419+
---------
420+
extensions : list, default: ["png", "pdf", "svg"]
421+
The extensions to test.
422+
tol : float
423+
The RMS threshold above which the test is considered failed.
424+
"""
425+
426+
defdecorator(func):
427+
importpytest
428+
429+
_,result_dir=map(Path,_image_directories(func))
430+
431+
@pytest.mark.parametrize("ext",extensions)
432+
defwrapper(ext):
433+
fig_test=plt.figure("test")
434+
fig_ref=plt.figure("reference")
435+
func(fig_test,fig_ref)
436+
test_image_path=str(
437+
result_dir/ (func.__name__+"."+ext))
438+
ref_image_path=str(
439+
result_dir/ (func.__name__+"-expected."+ext))
440+
fig_test.savefig(test_image_path)
441+
fig_ref.savefig(ref_image_path)
442+
_raise_on_image_difference(
443+
ref_image_path,test_image_path,tol=tol)
444+
445+
returnwrapper
446+
447+
returndecorator
448+
449+
410450
def_image_directories(func):
411451
"""
412452
Compute the baseline and result image directories for testing *func*.

‎lib/matplotlib/tests/test_axes.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
importwarnings
1515

1616
importmatplotlib
17-
frommatplotlib.testing.decoratorsimportimage_comparison
17+
frommatplotlib.testing.decoratorsimportimage_comparison,check_figures_equal
1818
importmatplotlib.pyplotasplt
1919
importmatplotlib.markersasmmarkers
2020
importmatplotlib.patchesasmpatches
@@ -5702,18 +5702,11 @@ def test_plot_columns_cycle_deprecation():
57025702
plt.plot(np.zeros((2,2)),np.zeros((2,3)))
57035703

57045704

5705-
deftest_markerfacecolor_none_alpha():
5706-
fig1,ax1=plt.subplots()
5707-
ax1.plot(0,"o",mfc="none",alpha=.5)
5708-
buf1=io.BytesIO()
5709-
fig1.savefig(buf1)
5710-
5711-
fig2,ax2=plt.subplots()
5712-
ax2.plot(0,"o",mfc="w",alpha=.5)
5713-
buf2=io.BytesIO()
5714-
fig2.savefig(buf2)
5715-
5716-
assertbuf1.getvalue()==buf2.getvalue()
5705+
# pdf and svg tests fail using travis' old versions of gs and inkscape.
5706+
@check_figures_equal(extensions=["png"])
5707+
deftest_markerfacecolor_none_alpha(fig_test,fig_ref):
5708+
fig_test.subplots().plot(0,"o",mfc="none",alpha=.5)
5709+
fig_ref.subplots().plot(0,"o",mfc="w",alpha=.5)
57175710

57185711

57195712
deftest_tick_padding_tightbbox():

‎tools/triage_tests.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,22 @@ def set_large_image(self, index):
192192
self.thumbnails[self.current_thumbnail].setFrameShape(1)
193193

194194
defaccept_test(self):
195-
self.entries[self.current_entry].accept()
195+
entry=self.entries[self.current_entry]
196+
ifentry.status=='autogen':
197+
print('Cannot accept autogenerated test cases.')
198+
return
199+
entry.accept()
196200
self.filelist.currentItem().setText(
197201
self.entries[self.current_entry].display)
198202
# Auto-move to the next entry
199203
self.set_entry(min((self.current_entry+1),len(self.entries)-1))
200204

201205
defreject_test(self):
202-
self.entries[self.current_entry].reject()
206+
entry=self.entries[self.current_entry]
207+
ifentry.status=='autogen':
208+
print('Cannot reject autogenerated test cases.')
209+
return
210+
entry.reject()
203211
self.filelist.currentItem().setText(
204212
self.entries[self.current_entry].display)
205213
# Auto-move to the next entry
@@ -261,11 +269,14 @@ def __init__(self, path, root, source):
261269
]
262270
self.thumbnails= [os.path.join(self.dir,x)forxinself.thumbnails]
263271

264-
self.status='unknown'
265-
266-
ifself.same(os.path.join(self.dir,self.generated),
272+
ifnotPath(self.destdir,self.generated).exists():
273+
# This case arises from a check_figures_equal test.
274+
self.status='autogen'
275+
elifself.same(os.path.join(self.dir,self.generated),
267276
os.path.join(self.destdir,self.generated)):
268277
self.status='accept'
278+
else:
279+
self.status='unknown'
269280

270281
defsame(self,a,b):
271282
"""
@@ -297,16 +308,18 @@ def display(self):
297308
Get the display string for this entry. This is the text that
298309
appears in the list widget.
299310
"""
300-
status_map= {'unknown':'\N{BALLOT BOX}',
301-
'accept':'\N{BALLOT BOX WITH CHECK}',
302-
'reject':'\N{BALLOT BOX WITH X}'}
311+
status_map= {
312+
'unknown':'\N{BALLOT BOX}',
313+
'accept':'\N{BALLOT BOX WITH CHECK}',
314+
'reject':'\N{BALLOT BOX WITH X}',
315+
'autogen':'\N{WHITE SQUARE CONTAINING BLACK SMALL SQUARE}',
316+
}
303317
box=status_map[self.status]
304318
return'{} {} [{}]'.format(box,self.name,self.extension)
305319

306320
defaccept(self):
307321
"""
308-
Accept this test by copying the generated result to the
309-
source tree.
322+
Accept this test by copying the generated result to the source tree.
310323
"""
311324
a=os.path.join(self.dir,self.generated)
312325
b=os.path.join(self.destdir,self.generated)
@@ -315,8 +328,7 @@ def accept(self):
315328

316329
defreject(self):
317330
"""
318-
Reject this test by copying the expected result to the
319-
source tree.
331+
Reject this test by copying the expected result to the source tree.
320332
"""
321333
a=os.path.join(self.dir,self.expected)
322334
b=os.path.join(self.destdir,self.generated)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp