4747from ..tmpdirs import InTemporaryDirectory
4848
4949from .test_api_validators import ValidateAPI
50- from .test_helpers import bytesio_round_trip , assert_data_similar
50+ from .test_helpers import (bytesio_round_trip , bytesio_filemap ,
51+ assert_data_similar )
5152from .test_minc1 import EXAMPLE_IMAGES as MINC1_EXAMPLE_IMAGES
5253from .test_minc2 import EXAMPLE_IMAGES as MINC2_EXAMPLE_IMAGES
5354from .test_parrec import EXAMPLE_IMAGES as PARREC_EXAMPLE_IMAGES
@@ -100,38 +101,10 @@ def obj_params(self):
100101 """
101102 raise NotImplementedError
102103
103- def validate_affine (self , imaker , params ):
104- # Check affine API
105- img = imaker ()
106- assert_almost_equal (img .affine , params ['affine' ], 6 )
107- assert_equal (img .affine .dtype , np .float64 )
108- img .affine [0 , 0 ] = 1.5
109- assert_equal (img .affine [0 , 0 ], 1.5 )
110- # Read only
111- assert_raises (AttributeError , setattr , img , 'affine' , np .eye (4 ))
112-
113- def validate_affine_deprecated (self , imaker , params ):
114- # Check deprecated affine API
115- img = imaker ()
116- with clear_and_catch_warnings () as w :
117- warnings .simplefilter ('always' , DeprecationWarning )
118- assert_almost_equal (img .get_affine (), params ['affine' ], 6 )
119- assert_equal (len (w ), 1 )
120- assert_equal (img .get_affine ().dtype , np .float64 )
121- aff = img .get_affine ()
122- aff [0 , 0 ] = 1.5
123- assert_true (aff is img .get_affine ())
124-
125104 def validate_header (self , imaker , params ):
126105 # Check header API
127106 img = imaker ()
128107 hdr = img .header # we can fetch it
129- # Change shape in header, check this changes img.header
130- shape = hdr .get_data_shape ()
131- new_shape = (shape [0 ] + 1 ,) + shape [1 :]
132- hdr .set_data_shape (new_shape )
133- assert_true (img .header is hdr )
134- assert_equal (img .header .get_data_shape (), new_shape )
135108 # Read only
136109 assert_raises (AttributeError , setattr , img , 'header' , hdr )
137110
@@ -152,7 +125,6 @@ def validate_shape(self, imaker, params):
152125 # Same as array shape if passed
153126 if 'data' in params :
154127 assert_equal (img .shape , params ['data' ].shape )
155- assert_equal (img .shape , img .get_data ().shape )
156128 # Read only
157129 assert_raises (AttributeError , setattr , img , 'shape' , np .eye (4 ))
158130
@@ -164,6 +136,51 @@ def validate_shape_deprecated(self, imaker, params):
164136 assert_equal (img .get_shape (), params ['shape' ])
165137 assert_equal (len (w ), 1 )
166138
139+ def validate_filenames (self , imaker , params ):
140+ # Validate the filename, file_map interface
141+ if not self .can_save :
142+ raise SkipTest
143+ img = imaker ()
144+ img .set_data_dtype (np .float32 ) # to avoid rounding in load / save
145+ # Make sure the object does not have a file_map
146+ img .file_map = None
147+ # The bytesio_round_trip helper tests bytesio load / save via file_map
148+ rt_img = bytesio_round_trip (img )
149+ assert_array_equal (img .shape , rt_img .shape )
150+ assert_almost_equal (img .get_data (), rt_img .get_data ())
151+ # Give the image a file map
152+ klass = type (img )
153+ rt_img .file_map = bytesio_filemap (klass )
154+ # This object can now be saved and loaded from its own file_map
155+ rt_img .to_file_map ()
156+ rt_rt_img = klass .from_file_map (rt_img .file_map )
157+ assert_almost_equal (img .get_data (), rt_rt_img .get_data ())
158+ # get_ / set_ filename
159+ fname = 'an_image' + self .standard_extension
160+ img .set_filename (fname )
161+ assert_equal (img .get_filename (), fname )
162+ assert_equal (img .file_map ['image' ].filename , fname )
163+ # to_ / from_ filename
164+ fname = 'another_image' + self .standard_extension
165+ with InTemporaryDirectory ():
166+ img .to_filename (fname )
167+ rt_img = img .__class__ .from_filename (fname )
168+ assert_array_equal (img .shape , rt_img .shape )
169+ assert_almost_equal (img .get_data (), rt_img .get_data ())
170+ del rt_img # to allow windows to delete the directory
171+
172+ def validate_no_slicing (self , imaker , params ):
173+ img = imaker ()
174+ assert_raises (TypeError , img .__getitem__ , 'string' )
175+ assert_raises (TypeError , img .__getitem__ , slice (None ))
176+
177+
178+ class GetSetDtypeMixin (object ):
179+ """ Adds dtype tests
180+
181+ Add this one if your image has ``get_data_dtype`` and ``set_data_dtype``.
182+ """
183+
167184 def validate_dtype (self , imaker , params ):
168185 # data / storage dtype
169186 img = imaker ()
@@ -182,9 +199,17 @@ def validate_dtype(self, imaker, params):
182199 rt_img = bytesio_round_trip (img )
183200 assert_equal (rt_img .get_data_dtype ().type , np .float32 )
184201
185- def validate_data (self , imaker , params ):
202+
203+ class DataInterfaceMixin (GetSetDtypeMixin ):
204+ """ Test dataobj interface for images with array backing
205+
206+ Use this mixin if your image has a ``dataobj`` property that contains an
207+ array or an array-like thing.
208+ """
209+ def validate_data_interface (self , imaker , params ):
186210 # Check get data returns array, and caches
187211 img = imaker ()
212+ assert_equal (img .shape , img .dataobj .shape )
188213 assert_data_similar (img .dataobj , params )
189214 if params ['is_proxy' ]:
190215 assert_false (isinstance (img .dataobj , np .ndarray ))
@@ -243,6 +268,8 @@ def validate_data(self, imaker, params):
243268 img .uncache ()
244269 assert_array_equal (get_data_func (), 42 )
245270 assert_true (img .in_memory )
271+ # Data shape is same as image shape
272+ assert_equal (img .shape , img .get_data ().shape )
246273 # dataobj is read only
247274 fake_data = np .zeros (img .shape ).astype (img .get_data_dtype ())
248275 assert_raises (AttributeError , setattr , img , 'dataobj' , fake_data )
@@ -262,37 +289,60 @@ def validate_data_deprecated(self, imaker, params):
262289 fake_data = np .zeros (img .shape ).astype (img .get_data_dtype ())
263290 assert_raises (AttributeError , setattr , img , '_data' , fake_data )
264291
265- def validate_filenames (self , imaker , params ):
266- # Validate the filename, file_map interface
267- if not self .can_save :
268- raise SkipTest
292+
293+ class HeaderShapeMixin (object ):
294+ """ Tests that header shape can be set and got
295+
296+ Add this one of your header supports ``get_data_shape`` and
297+ ``set_data_shape``.
298+ """
299+
300+ def validate_header_shape (self , imaker , params ):
301+ # Change shape in header, check this changes img.header
269302 img = imaker ()
270- img .set_data_dtype (np .float32 ) # to avoid rounding in load / save
271- # The bytesio_round_trip helper tests bytesio load / save via file_map
272- rt_img = bytesio_round_trip (img )
273- assert_array_equal (img .shape , rt_img .shape )
274- assert_almost_equal (img .get_data (), rt_img .get_data ())
275- # get_ / set_ filename
276- fname = 'an_image' + self .standard_extension
277- img .set_filename (fname )
278- assert_equal (img .get_filename (), fname )
279- assert_equal (img .file_map ['image' ].filename , fname )
280- # to_ / from_ filename
281- fname = 'another_image' + self .standard_extension
282- with InTemporaryDirectory ():
283- img .to_filename (fname )
284- rt_img = img .__class__ .from_filename (fname )
285- assert_array_equal (img .shape , rt_img .shape )
286- assert_almost_equal (img .get_data (), rt_img .get_data ())
287- del rt_img # to allow windows to delete the directory
303+ hdr = img .header
304+ shape = hdr .get_data_shape ()
305+ new_shape = (shape [0 ] + 1 ,) + shape [1 :]
306+ hdr .set_data_shape (new_shape )
307+ assert_true (img .header is hdr )
308+ assert_equal (img .header .get_data_shape (), new_shape )
288309
289- def validate_no_slicing (self , imaker , params ):
310+
311+ class AffineMixin (object ):
312+ """ Adds test of affine property, method
313+
314+ Add this one if your image has an ``affine`` property. If so, it should
315+ (for now) also have a ``get_affine`` method returning the same result.
316+ """
317+
318+ def validate_affine (self , imaker , params ):
319+ # Check affine API
290320 img = imaker ()
291- assert_raises (TypeError , img .__getitem__ , 'string' )
292- assert_raises (TypeError , img .__getitem__ , slice (None ))
321+ assert_almost_equal (img .affine , params ['affine' ], 6 )
322+ assert_equal (img .affine .dtype , np .float64 )
323+ img .affine [0 , 0 ] = 1.5
324+ assert_equal (img .affine [0 , 0 ], 1.5 )
325+ # Read only
326+ assert_raises (AttributeError , setattr , img , 'affine' , np .eye (4 ))
327+
328+ def validate_affine_deprecated (self , imaker , params ):
329+ # Check deprecated affine API
330+ img = imaker ()
331+ with clear_and_catch_warnings () as w :
332+ warnings .simplefilter ('always' , DeprecationWarning )
333+ assert_almost_equal (img .get_affine (), params ['affine' ], 6 )
334+ assert_equal (len (w ), 1 )
335+ assert_equal (img .get_affine ().dtype , np .float64 )
336+ aff = img .get_affine ()
337+ aff [0 , 0 ] = 1.5
338+ assert_true (aff is img .get_affine ())
293339
294340
295- class LoadImageAPI (GenericImageAPI ):
341+ class LoadImageAPI (GenericImageAPI ,
342+ DataInterfaceMixin ,
343+ AffineMixin ,
344+ GetSetDtypeMixin ,
345+ HeaderShapeMixin ):
296346 # Callable returning an image from a filename
297347 loader = None
298348 # Sequence of dictionaries, where dictionaries have keys
@@ -324,9 +374,6 @@ class MakeImageAPI(LoadImageAPI):
324374 # Example shapes for created images
325375 example_shapes = ((2 ,), (2 , 3 ), (2 , 3 , 4 ), (2 , 3 , 4 , 5 ))
326376
327- def img_from_arr_aff (self , arr , aff , header = None ):
328- return self .image_maker (arr , aff , header )
329-
330377 def obj_params (self ):
331378 # Return any obj_params from superclass
332379 for func , params in super (MakeImageAPI , self ).obj_params ():
0 commit comments