Skip to content

BF: Fix interaction between indexed_gzip presence and keep_file_open flag #679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 15, 2018

Conversation

pauldmccarthy
Copy link
Contributor

@pauldmccarthy pauldmccarthy commented Oct 12, 2018

According to the discussion in #614, the behaviour of the keep_file_open flag should be as follows (copied verbatim from this comment, which I believe was the behaviour that was agreed upon):

HAVE_INDEXED_GZIP keep_file_open Library used ArrayProxy persists opener indexed_gzip.drop_handles
False False gzip No na
False 'auto' gzip No na
False True gzip Yes na
True False indexed_gzip Yes True
True 'auto' indexed_gzip Yes False
True True indexed_gzip Yes False

But the behaviour of nibabel 2.3.0 doesn't match this expected behaviour.

Assuming that indexed_gzip is installed, a simple test shows that the ArrayProxy is not creating and persisting one ImageOpener:

In [1]: import nibabel as nib

In [2]: from nibabel.openers import HAVE_INDEXED_GZIP

In [3]: HAVE_INDEXED_GZIP
Out[3]: True

In [4]: img = nib.load('some_image.nii.gz')

In [5]: _ = img.dataobj[..., 0]

In [6]: img.dataobj._opener
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-356fc96fb10d> in <module>()
----> 1 img.dataobj._opener

AttributeError: 'ArrayProxy' object has no attribute '_opener'

In [7]:

This PR aims to fix the behaviour of nibabel so that it matches what was discussed in #614.

It does so by changing the internal logic of ArrayProxy so that two flags are used:

  • The _persist_opener flag is used to control whether a single ImageOpener is created and used for the lifetime of the ArrayProxy, or whether a new ImageOpener is created for each file access
  • The _keep_file_open flag is used in a similar manner to control the lifetime of the underlying file handles.

The distinction between these two flags is only relevant when indexed_gzip is being used. The existing ArrayProxy code dodes not correctly make this distinction.

I've updated the unit tests in test_arrayproxy.py to make it clearer what scenarios are tested, and what the expected behaviour is for each scenario.

@pauldmccarthy pauldmccarthy mentioned this pull request Oct 12, 2018
19 tasks
…re used,

one to control persistence of ImageOpeners, another to control persistence of
underlying file handles. This distinction is only relevant when indexed_gzip
is being used.
@pauldmccarthy pauldmccarthy changed the title WIP,BF: Fix interaction between indexed_gzip presence and keep_file_open flag BF: Fix interaction between indexed_gzip presence and keep_file_open flag Oct 12, 2018
@coveralls
Copy link

coveralls commented Oct 12, 2018

Coverage Status

Coverage increased (+0.002%) to 91.849% when pulling 9d7fb3f on pauldmccarthy:bf/fix_keep_file_open into 791678e on nipy:master.

@codecov-io
Copy link

codecov-io commented Oct 12, 2018

Codecov Report

Merging #679 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #679      +/-   ##
==========================================
+ Coverage   88.87%   88.87%   +<.01%     
==========================================
  Files          93       93              
  Lines       11444    11447       +3     
  Branches     1890     1891       +1     
==========================================
+ Hits        10171    10174       +3     
  Misses        933      933              
  Partials      340      340
Impacted Files Coverage Δ
nibabel/arrayproxy.py 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 791678e...9d7fb3f. Read the comment docs.

@pauldmccarthy
Copy link
Contributor Author

Hey @effigies, ready for a review - apologies if this changed your release plans!

@effigies
Copy link
Member

Thanks, Paul. I should have time today or tomorrow, and I'll shoot for a Monday release. We'll need to give Yarik time to run another round of tests on Neurodebian.

Is Neurodebian up-to-date with the latest indexed-gzip? Might be a good time to bump that, too.

@pauldmccarthy
Copy link
Contributor Author

Neurodebian is at indexed_gzip 0.8.6, which is a tiny bit out of date - 0.8.7 contains mostly Windows-specific fixes, but also a small improvement in the read function.

Copy link
Member

@effigies effigies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some very minor comments. This LGTM. Thanks for building out the logic in truth-table form. That makes things much simpler.

@matthew-brett I'll plan on merging Monday AM (PDT), in case you want to double-check the logic.

assert not fobj1.closed
assert not fobj2.closed
except Exception:
print('Failed test', test)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this debug print statement. If it's useful to add context, you can use six.raise_from to raise a new exception with the old one as context.

fobj1.close()
fobj2.close()
# Test invalid values of keep_file_open
print('testinv')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, let's drop this print.

@pauldmccarthy
Copy link
Contributor Author

Thanks for the quick review! I had mean to remove those prints before pushing, they're gone now.

The logic was doing my head in, so making that truth table was essential!

@effigies
Copy link
Member

Thanks for this.

@effigies effigies merged commit a474254 into nipy:master Oct 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants