@@ -349,78 +349,128 @@ def __init__(self, *args, **kwargs):
349349
350350def _count_ImageOpeners (proxy , data , voxels ):
351351 CountingImageOpener .num_openers = 0
352+ # expected data is defined in the test_keep_file_open_* tests
352353 for i in range (voxels .shape [0 ]):
353354 x , y , z = [int (c ) for c in voxels [i , :]]
354355 assert proxy [x , y , z ] == x * 100 + y * 10 + z
355356 return CountingImageOpener .num_openers
356357
357358
359+ @contextlib .contextmanager
360+ def patch_keep_file_open_default (value ):
361+ # Patch arrayproxy.KEEP_FILE_OPEN_DEFAULT with the given value
362+ with mock .patch ('nibabel.arrayproxy.KEEP_FILE_OPEN_DEFAULT' , value ):
363+ yield
364+
365+
358366def test_keep_file_open_true_false_invalid ():
359367 # Test the behaviour of the keep_file_open __init__ flag, when it is set to
360368 # True or False. Expected behaviour is as follows:
361- # igzip present | keep_file_open | persist ImageOpener | igzip.drop_handles
362- # False | False | False | n/a
363- # False | True | True | n/a
364- # True | False | True | True
365- # True | True | True | False
366- CountingImageOpener .num_openers = 0
367- fname = 'testdata'
369+ # keep_open | igzip present | persist ImageOpener | igzip.drop_handles
370+ # | and is gzip file | |
371+ # ----------|------------------|---------------------|-------------------
372+ # False | False | False | n/a
373+ # False | True | True | True
374+ # True | False | True | n/a
375+ # True | True | True | False
376+ # 'auto' | False | False | n/a
377+ # 'auto' | True | True | False
378+ #
379+ # Each test tuple contains:
380+ # - file type - gzipped ('gz') or not ('bin'), or an open file handle
381+ # ('open')
382+ # - keep_file_open value passed to ArrayProxy
383+ # - whether or not indexed_gzip is present
384+ # - expected value for internal ArrayProxy._persist_opener flag
385+ # - expected value for internal ArrayProxy._keep_file_open flag
386+ tests = [
387+ # open file handle - kfo and have_igzip are both irrelevant
388+ ('open' , False , False , False , False ),
389+ ('open' , False , True , False , False ),
390+ ('open' , True , False , False , False ),
391+ ('open' , True , True , False , False ),
392+ ('open' , 'auto' , False , False , False ),
393+ ('open' , 'auto' , True , False , False ),
394+ # non-gzip file - have_igzip is irrelevant, decision should be made
395+ # solely from kfo flag
396+ ('bin' , False , False , False , False ),
397+ ('bin' , False , True , False , False ),
398+ ('bin' , True , False , True , True ),
399+ ('bin' , True , True , True , True ),
400+ ('bin' , 'auto' , False , False , False ),
401+ ('bin' , 'auto' , True , False , False ),
402+ # gzip file. If igzip is present, we persist the ImageOpener. If kfo
403+ # is 'auto':
404+ # - if igzip is present, kfo -> True
405+ # - otherwise, kfo -> False
406+ ('gz' , False , False , False , False ),
407+ ('gz' , False , True , True , False ),
408+ ('gz' , True , False , True , True ),
409+ ('gz' , True , True , True , True ),
410+ ('gz' , 'auto' , False , False , False ),
411+ ('gz' , 'auto' , True , True , True )]
412+
368413 dtype = np .float32
369414 data = np .arange (1000 , dtype = dtype ).reshape ((10 , 10 , 10 ))
370415 voxels = np .random .randint (0 , 10 , (10 , 3 ))
416+
417+ for test in tests :
418+ filetype , kfo , have_igzip , exp_persist , exp_kfo = test
419+ with InTemporaryDirectory (), \
420+ mock .patch ('nibabel.openers.ImageOpener' , CountingImageOpener ), \
421+ patch_indexed_gzip (have_igzip ):
422+ fname = 'testdata.{}' .format (filetype )
423+ # create the test data file
424+ if filetype == 'gz' :
425+ with gzip .open (fname , 'wb' ) as fobj :
426+ fobj .write (data .tostring (order = 'F' ))
427+ else :
428+ with open (fname , 'wb' ) as fobj :
429+ fobj .write (data .tostring (order = 'F' ))
430+ if filetype == 'open' :
431+ fname = open (fname , 'rb' )
432+ try :
433+ proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
434+ keep_file_open = kfo )
435+ # We also test that we get the same behaviour when the
436+ # KEEP_FILE_OPEN_DEFAULT flag is changed
437+ with patch_keep_file_open_default (kfo ):
438+ proxy_def = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ))
439+ # check internal flags
440+ assert proxy ._persist_opener == exp_persist
441+ assert proxy ._keep_file_open == exp_kfo
442+ assert proxy_def ._persist_opener == exp_persist
443+ assert proxy_def ._keep_file_open == exp_kfo
444+ # check persist_opener behaviour - whether one imageopener is
445+ # created for the lifetime of the ArrayProxy, or one is
446+ # created on each access
447+ if exp_persist :
448+ assert _count_ImageOpeners (proxy , data , voxels ) == 1
449+ assert _count_ImageOpeners (proxy_def , data , voxels ) == 1
450+ else :
451+ assert _count_ImageOpeners (proxy , data , voxels ) == 10
452+ assert _count_ImageOpeners (proxy_def , data , voxels ) == 10
453+ # if indexed_gzip is active, check that the file object was
454+ # created correctly - the _opener.fobj will be a
455+ # MockIndexedGzipFile, defined in test_openers.py
456+ if filetype == 'gz' and have_igzip :
457+ assert proxy ._opener .fobj ._drop_handles == (not exp_kfo )
458+ # if we were using an open file handle, check that the proxy
459+ # didn't close it
460+ if filetype == 'open' :
461+ assert not fname .closed
462+ except Exception :
463+ print ('Failed test' , test )
464+ raise
465+ finally :
466+ if filetype == 'open' :
467+ fname .close ()
468+ # Test invalid values of keep_file_open
469+ print ('testinv' )
371470 with InTemporaryDirectory ():
471+ fname = 'testdata'
372472 with open (fname , 'wb' ) as fobj :
373473 fobj .write (data .tostring (order = 'F' ))
374- # Without indexed_gzip, test that ArrayProxy(keep_file_open=True) only
375- # creates one ImageOpener, and that ArrayProxy(keep_file_open=False)
376- # creates an ImageOpener on every data access.
377- with mock .patch ('nibabel.openers.ImageOpener' , CountingImageOpener ), \
378- patch_indexed_gzip (False ):
379- proxy_no_kfp = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
380- keep_file_open = False )
381- assert not proxy_no_kfp ._keep_file_open
382- assert _count_ImageOpeners (proxy_no_kfp , data , voxels ) == 10
383- proxy_kfp = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
384- keep_file_open = True )
385- assert proxy_kfp ._keep_file_open
386- assert _count_ImageOpeners (proxy_kfp , data , voxels ) == 1
387- del proxy_kfp
388- del proxy_no_kfp
389- # With indexed_gzip, test that both ArrayProxy(keep_file_open=True)
390- # and ArrayProxy(keep_file_open=False) only create one ImageOpener,
391- # but that the drop_handles parameter passed to the IndexedGzipFile
392- # is set appropriately
393- with mock .patch ('nibabel.openers.ImageOpener' , CountingImageOpener ), \
394- patch_indexed_gzip (True ):
395- proxy_no_kfp = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
396- keep_file_open = False )
397- assert proxy_no_kfp ._keep_file_open
398- assert _count_ImageOpeners (proxy_no_kfp , data , voxels ) == 1
399- # check that the drop_handles flag is set - the fobj attribute
400- # should be a MockIndexedGzipFile, defined in test_openers.
401- assert proxy_no_kfp ._opener .fobj ._drop_handles
402- proxy_kfp = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
403- keep_file_open = True )
404- assert proxy_kfp ._keep_file_open
405- assert _count_ImageOpeners (proxy_kfp , data , voxels ) == 1
406- assert not proxy_no_kfp ._opener .fobj ._drop_handles
407- del proxy_kfp
408- del proxy_no_kfp
409- # Test that the keep_file_open flag has no effect if an open file
410- # handle is passed in
411- with open (fname , 'rb' ) as fobj :
412- for kfo in (True , False , 'auto' ):
413- proxy = ArrayProxy (fobj , ((10 , 10 , 10 ), dtype ),
414- keep_file_open = kfo )
415- assert proxy ._keep_file_open is False
416- for i in range (voxels .shape [0 ]):
417- x , y , z = [int (c ) for c in voxels [i , :]]
418- assert proxy [x , y , z ] == x * 100 + y * 10 + z
419- assert not fobj .closed
420- del proxy
421- assert not fobj .closed
422- assert fobj .closed
423- # Test invalid values of keep_file_open
424474 with assert_raises (ValueError ):
425475 ArrayProxy (fname , ((10 , 10 , 10 ), dtype ), keep_file_open = 55 )
426476 with assert_raises (ValueError ):
@@ -429,113 +479,6 @@ def test_keep_file_open_true_false_invalid():
429479 ArrayProxy (fname , ((10 , 10 , 10 ), dtype ), keep_file_open = 'cauto' )
430480
431481
432- def test_keep_file_open_auto ():
433- # Test the behaviour of the keep_file_open __init__ flag, when it is set to
434- # 'auto'. Expected behaviour is as follows:
435- # igzip present | keep_file_open | persist ImageOpener | igzip.drop_handles
436- # False | 'auto' | False | n/a
437- # True | 'auto' | False | False
438- dtype = np .float32
439- data = np .arange (1000 , dtype = dtype ).reshape ((10 , 10 , 10 ))
440- voxels = np .random .randint (0 , 10 , (10 , 3 ))
441- with InTemporaryDirectory ():
442- fname = 'testdata.gz'
443- with gzip .open (fname , 'wb' ) as fobj :
444- fobj .write (data .tostring (order = 'F' ))
445- # If no have_indexed_gzip, then a separate ImageOpener should be
446- # created on every access.
447- with patch_indexed_gzip (False ), \
448- mock .patch ('nibabel.openers.ImageOpener' , CountingImageOpener ):
449- CountingImageOpener .num_openers = 0
450- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
451- keep_file_open = 'auto' )
452- assert not proxy ._keep_file_open
453- assert _count_ImageOpeners (proxy , data , voxels ) == 10
454- # If have_indexed_gzip, then the arrayproxy should create one
455- # ImageOpener, and the IndexedGzipFile drop_handles parameter should
456- # be set to False, so the file handle stays open.
457- with patch_indexed_gzip (True ), \
458- mock .patch ('nibabel.openers.ImageOpener' , CountingImageOpener ):
459- CountingImageOpener .num_openers = 0
460- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
461- keep_file_open = 'auto' )
462- assert proxy ._keep_file_open
463- assert _count_ImageOpeners (proxy , data , voxels ) == 1
464- assert not proxy ._opener .fobj ._drop_handles
465- # If not a gzip file, keep_file_open should be False
466- fname = 'testdata'
467- with open (fname , 'wb' ) as fobj :
468- fobj .write (data .tostring (order = 'F' ))
469- # regardless of whether indexed_gzip is present or not
470- with patch_indexed_gzip (True ), \
471- mock .patch ('nibabel.openers.ImageOpener' , CountingImageOpener ):
472- CountingImageOpener .num_openers = 0
473- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
474- keep_file_open = 'auto' )
475- assert proxy ._keep_file_open is False
476- assert _count_ImageOpeners (proxy , data , voxels ) == 10
477- with patch_indexed_gzip (False ), \
478- mock .patch ('nibabel.openers.ImageOpener' , CountingImageOpener ):
479- CountingImageOpener .num_openers = 0
480- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ),
481- keep_file_open = 'auto' )
482- assert proxy ._keep_file_open is False
483- assert _count_ImageOpeners (proxy , data , voxels ) == 10
484-
485-
486- @contextlib .contextmanager
487- def patch_keep_file_open_default (value ):
488- # Patch arrayproxy.KEEP_FILE_OPEN_DEFAULT with the given value
489- with mock .patch ('nibabel.arrayproxy.KEEP_FILE_OPEN_DEFAULT' , value ):
490- yield
491-
492-
493- def test_keep_file_open_default ():
494- # Test the behaviour of the keep_file_open __init__ flag, when the
495- # arrayproxy.KEEP_FILE_OPEN_DEFAULT value is changed
496- dtype = np .float32
497- data = np .arange (1000 , dtype = dtype ).reshape ((10 , 10 , 10 ))
498- with InTemporaryDirectory ():
499- fname = 'testdata.gz'
500- with gzip .open (fname , 'wb' ) as fobj :
501- fobj .write (data .tostring (order = 'F' ))
502- # If KEEP_FILE_OPEN_DEFAULT is False, ArrayProxy instances should
503- # interpret keep_file_open as False
504- with patch_keep_file_open_default (False ):
505- with patch_indexed_gzip (False ):
506- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ))
507- assert proxy ._keep_file_open is False
508- with patch_indexed_gzip (True ):
509- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ))
510- assert proxy ._keep_file_open is False
511- # If KEEP_FILE_OPEN_DEFAULT is True, ArrayProxy instances should
512- # interpret keep_file_open as True
513- with patch_keep_file_open_default (True ):
514- with patch_indexed_gzip (False ):
515- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ))
516- assert proxy ._keep_file_open is True
517- with patch_indexed_gzip (True ):
518- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ))
519- assert proxy ._keep_file_open is True
520- # If KEEP_FILE_OPEN_DEFAULT is auto, ArrayProxy instances should
521- # interpret it as auto if indexed_gzip is present, False otherwise.
522- with patch_keep_file_open_default ('auto' ):
523- with patch_indexed_gzip (False ):
524- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ))
525- assert proxy ._keep_file_open is False
526- with patch_indexed_gzip (True ):
527- proxy = ArrayProxy (fname , ((10 , 10 , 10 ), dtype ))
528- assert proxy ._keep_file_open == 'auto'
529- # KEEP_FILE_OPEN_DEFAULT=any other value should cuse an error to be
530- # raised
531- with patch_keep_file_open_default ('badvalue' ):
532- assert_raises (ValueError , ArrayProxy , fname , ((10 , 10 , 10 ),
533- dtype ))
534- with patch_keep_file_open_default (None ):
535- assert_raises (ValueError , ArrayProxy , fname , ((10 , 10 , 10 ),
536- dtype ))
537-
538-
539482def test_pickle_lock ():
540483 # Test that ArrayProxy can be pickled, and that thread lock is created
541484
0 commit comments