@@ -349,78 +349,128 @@ def __init__(self, *args, **kwargs):
349
349
350
350
def _count_ImageOpeners (proxy , data , voxels ):
351
351
CountingImageOpener .num_openers = 0
352
+ # expected data is defined in the test_keep_file_open_* tests
352
353
for i in range (voxels .shape [0 ]):
353
354
x , y , z = [int (c ) for c in voxels [i , :]]
354
355
assert proxy [x , y , z ] == x * 100 + y * 10 + z
355
356
return CountingImageOpener .num_openers
356
357
357
358
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
+
358
366
def test_keep_file_open_true_false_invalid ():
359
367
# Test the behaviour of the keep_file_open __init__ flag, when it is set to
360
368
# 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
+
368
413
dtype = np .float32
369
414
data = np .arange (1000 , dtype = dtype ).reshape ((10 , 10 , 10 ))
370
415
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' )
371
470
with InTemporaryDirectory ():
471
+ fname = 'testdata'
372
472
with open (fname , 'wb' ) as fobj :
373
473
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
424
474
with assert_raises (ValueError ):
425
475
ArrayProxy (fname , ((10 , 10 , 10 ), dtype ), keep_file_open = 55 )
426
476
with assert_raises (ValueError ):
@@ -429,113 +479,6 @@ def test_keep_file_open_true_false_invalid():
429
479
ArrayProxy (fname , ((10 , 10 , 10 ), dtype ), keep_file_open = 'cauto' )
430
480
431
481
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
-
539
482
def test_pickle_lock ():
540
483
# Test that ArrayProxy can be pickled, and that thread lock is created
541
484
0 commit comments