Skip to content

ENH: Add resolve/rebase BasePath traits methods & tests #2970

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 13 commits into from
Aug 1, 2019

Conversation

oesteban
Copy link
Contributor

List of changes proposed in this PR (pull-request)

Two new methods resolve_path_traits and rebase_path_traits are being included.

They take trait instances from a spec (selected via spec.trait('traitname')), the value and a base path. Returns the modified value (if necessary).

Summary

These two functions will be useful to progress towards #2944.

Acknowledgment

  • (Mandatory) I acknowledge that this contribution will be available under the Apache 2 license.

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.

My biggest concern is with monkey-patching traits. I think providing replacements in the nipype namespace is fine.

A couple potential corner cases for tests:

  • rebase_path_traits: cwd not a prefix of value
  • resolve_path_traits: value already absolute

@codecov-io
Copy link

Codecov Report

Merging #2970 into master will decrease coverage by 3.31%.
The diff coverage is 92.4%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2970      +/-   ##
==========================================
- Coverage   67.61%   64.29%   -3.32%     
==========================================
  Files         344      342       -2     
  Lines       43798    43822      +24     
  Branches     5471     5498      +27     
==========================================
- Hits        29612    28174    -1438     
- Misses      13475    14558    +1083     
- Partials      711     1090     +379
Flag Coverage Δ
#smoketests ?
#unittests 64.29% <92.4%> (-0.75%) ⬇️
Impacted Files Coverage Δ
nipype/interfaces/base/traits_extension.py 89.09% <92.4%> (-5.24%) ⬇️
nipype/interfaces/nilearn.py 40% <0%> (-56.67%) ⬇️
nipype/utils/spm_docs.py 25.92% <0%> (-44.45%) ⬇️
nipype/interfaces/freesurfer/base.py 50% <0%> (-30.51%) ⬇️
nipype/utils/logger.py 59.7% <0%> (-29.86%) ⬇️
nipype/algorithms/rapidart.py 35% <0%> (-29.42%) ⬇️
nipype/interfaces/spm/base.py 57.94% <0%> (-29.14%) ⬇️
nipype/utils/provenance.py 55.73% <0%> (-28.35%) ⬇️
nipype/interfaces/fsl/model.py 55.26% <0%> (-25.35%) ⬇️
nipype/testing/fixtures.py 77.33% <0%> (-21.34%) ⬇️
... and 41 more

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 3454c9a...4544b34. Read the comment docs.

@codecov-io
Copy link

codecov-io commented Jul 19, 2019

Codecov Report

Merging #2970 into master will decrease coverage by 2.84%.
The diff coverage is 98.97%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2970      +/-   ##
==========================================
- Coverage   67.12%   64.28%   -2.85%     
==========================================
  Files         344      342       -2     
  Lines       43785    43776       -9     
  Branches     5469     5483      +14     
==========================================
- Hits        29391    28140    -1251     
- Misses      13648    14547     +899     
- Partials      746     1089     +343
Flag Coverage Δ
#smoketests ?
#unittests 64.28% <98.97%> (-0.21%) ⬇️
Impacted Files Coverage Δ
nipype/interfaces/spm/base.py 57.94% <ø> (-25.83%) ⬇️
nipype/interfaces/base/__init__.py 100% <ø> (ø) ⬆️
nipype/interfaces/base/specs.py 87.11% <100%> (-6.19%) ⬇️
nipype/interfaces/dipy/base.py 77.19% <100%> (+1.75%) ⬆️
nipype/interfaces/utility/base.py 86.36% <100%> (-1.14%) ⬇️
nipype/interfaces/afni/preprocess.py 82.01% <100%> (+0.23%) ⬆️
nipype/interfaces/afni/model.py 81.95% <100%> (ø) ⬆️
nipype/interfaces/nipy/model.py 25.37% <100%> (ø) ⬆️
nipype/interfaces/freesurfer/registration.py 78.19% <100%> (ø) ⬆️
nipype/algorithms/misc.py 45.57% <100%> (-0.12%) ⬇️
... and 76 more

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 81231c8...b0c80d7. Read the comment docs.

oesteban added a commit to oesteban/nipype that referenced this pull request Jul 19, 2019
- [x] Removed traits.api patches
- [x] Deduplicated code with a _recurse_on_path_traits proxy
      (nipy#2970 (comment))
- [x] Added the two proposed test cases
- [x] Optimized loop (see nipy#2970 (comment))
@effigies
Copy link
Member

Sorry for taking so long to get back to this one. I'm a little torn on the Tuple/Either issue. I see that the point of adding the inner_traits option is to have a uniform access method, but it does mean that our methods won't work with standard traits.Tuple and traits.Either, which is evidenced by the need to mass-replace those with the traits_extension variants.

Does it not make more sense to have an accessor function that doesn't require either monkey-patching or replacing? This way we're not breaking downstream tools that define their own interface.

If not, then I think monkey-patching the pre-existing traits will be necessary.

@oesteban
Copy link
Contributor Author

oesteban commented Jul 26, 2019

Sorry for taking so long to get back to this one. I'm a little torn on the Tuple/Either issue. I see that the point of adding the inner_traits option is to have a uniform access method, but it does mean that our methods won't work with standard traits.Tuple and traits.Either, which is evidenced by the need to mass-replace those with the traits_extension variants.

Correct, the original Tuple and Either won't work.

Does it not make more sense to have an accessor function that doesn't require either monkey-patching or replacing? This way we're not breaking downstream tools that define their own interface.

I tried, but accessing traits without their prescribed methods has a huge boilerplate. I finally opted for this solution of least changes. We should consider streaming them up to traits - at least for the Tuple (not so convinced about Either). Reading through their code, it seems to me that the inner_traits was left there to implement this behavior but they never finally did.

If not, then I think monkey-patching the pre-existing traits will be necessary.

That was my initial solution, but after reading your position about File, I went ahead and changed everything for these other two. Sorry if I misunderstood your previous comment.

@effigies
Copy link
Member

effigies commented Jul 26, 2019

That was my initial solution, but after reading your position about File, I went ahead and changed everything for these other two. Sorry if I misunderstood your previous comment.

Well, with File and Directory, we're creating them and throwing them into that namespace, which feels strange. Especially because we haven't done it before, so everybody who has been using them has been importing them from nipype.

While I would rather just create an accessor method to contain the boilerplate to one place, e.g.:

def get_inner_traits(trait_type):
    try:
        return trait_type.inner_traits
    except:
        pass
    # Tuple hack
    # Either hack
    # Other hacks?

If that's out of the question, and we're producing traits that are otherwise identical to the ones we're replacing, I think monkey-patching is a cleaner solution than forcing all downstream projects to change their import targets.

@oesteban
Copy link
Contributor Author

Well, with File and Directory, we're creating them and throwing them into that namespace, which feels strange.

https://github.com/enthought/traits/blob/master/traits/trait_types.py#L1659
https://github.com/enthought/traits/blob/master/traits/trait_types.py#L1762

I don't see the difference with Either and Tuple.

Especially because we haven't done it before, so everybody who has been using them has been importing them from nipype.

I disagree - f1f4cf2

@effigies
Copy link
Member

Huh. I didn't realize there already were File/Directory traits. Sorry about that.

So I don't know. It's annoying to push these changes downstream, but we haven't been monkey-patching traits, so this is a pretty big change to do that.

@oesteban
Copy link
Contributor Author

I would bring monkeypatching back, it is very likely that people have their interfaces defined using traits.(File|Directory|Tuple|Either), but keep all those conversions to nipype's definitions for the codebase. WDYT?

@effigies
Copy link
Member

That seems reasonable, but I feel like I want to get @satra's opinion on monkeypatching before I ask you to do anything big again...

@satra
Copy link
Member

satra commented Jul 26, 2019

@oesteban and @effigies - File/Directory were overwritten to provide better error messages. nothing about the functionality of File/Directory was changed. and ImageFile is a new trait, so that is unique to nipype itself.

the current change that we are making is to change the behavior of File to not only accept/provide Pathlib objects but also to create additional semantics. if we were to forget backwards compatibility we would simply consider two new nipype traits:

  1. PathX, string representing input/output files which need to be content hashed
  2. StrX, strings representing Paths/FileNames (typically outputs), which need to be string hashed (these would have the metadata hash_files=False.

all places where we use File could be replaced by one of these two traits.

the functionality of the new File trait that @oesteban implemented would mostly correspond to PathX. the names PathX and StrX can be decided to be something different.

this way we are not monkeypatching traits, and the introduced functionality is within the nipype context and people are not confused.

@oesteban
Copy link
Contributor Author

The problem I see @satra is that people having interfaces not contributed to nipype are potentially using traits.File and co. If we don't want to break compatibility with those users, we'll need to monkeypatch.

One thing you did not mention is what we do with the new Tuple/Either traits (so that they return their inner trait types).

@oesteban
Copy link
Contributor Author

That said, I would not revert back all those traits.File (at least we now have all of them from nipype, regardless we monkeypatch or not).

@oesteban
Copy link
Contributor Author

  1. I believe I've found the way so that not to shadow traits.Either and traits.Tuple - I'll revert back those changes (maybe opening a new PR?)

  2. Should we patch File and Directory back into traits? We were using traits.File, so it is likely users are using it themselves.

  3. The hash_files and the config use_relative_paths are tangential to this PR and FIX: Resolving/rebasing paths from/to results files #2971, but could be easily addressed with the new features implemented here.

@oesteban oesteban force-pushed the enh/resolve-rebase-paths branch from cfdb14c to a1eae5a Compare July 31, 2019 14:51
oesteban added a commit to oesteban/nipype that referenced this pull request Jul 31, 2019
- [x] Removed traits.api patches
- [x] Deduplicated code with a _recurse_on_path_traits proxy
      (nipy#2970 (comment))
- [x] Added the two proposed test cases
- [x] Optimized loop (see nipy#2970 (comment))
@oesteban oesteban force-pushed the enh/resolve-rebase-paths branch from a1eae5a to b2adade Compare July 31, 2019 15:02
oesteban added a commit to oesteban/nipype that referenced this pull request Jul 31, 2019
- [x] Removed traits.api patches
- [x] Deduplicated code with a _recurse_on_path_traits proxy
      (nipy#2970 (comment))
- [x] Added the two proposed test cases
- [x] Optimized loop (see nipy#2970 (comment))
@effigies
Copy link
Member

@oesteban I think you rebased on an out-of-date master.

@oesteban oesteban force-pushed the enh/resolve-rebase-paths branch from b2adade to 1a67e63 Compare July 31, 2019 15:22
oesteban added a commit to oesteban/nipype that referenced this pull request Jul 31, 2019
- [x] Removed traits.api patches
- [x] Deduplicated code with a _recurse_on_path_traits proxy
      (nipy#2970 (comment))
- [x] Added the two proposed test cases
- [x] Optimized loop (see nipy#2970 (comment))
@effigies
Copy link
Member

Sorry, can you remove the commits with @josephmje? I don't think we want them and they add a min_ver back in that had been removed from his PR.

@oesteban oesteban force-pushed the enh/resolve-rebase-paths branch from 1896f8b to e3a6fd3 Compare July 31, 2019 16:09
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.

Assuming tests pass, this looks reasonable. One minor suggestion, and one quick question about the tests.

@@ -100,7 +100,7 @@ def convert_to_traits_type(dipy_type, is_file=False):
elif "string" in dipy_type and not is_file:
return traits.Str, is_mandatory
Copy link
Member

Choose a reason for hiding this comment

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

While we're switching from traits.File:

Suggested change
return traits.Str, is_mandatory
return Str, is_mandatory

This will need an import.

@skoudoro Could you verify that this is fine and that you didn't explicitly intend to use traits.Str over nipype.interfaces.base.Str for some reason?

Copy link
Member

Choose a reason for hiding this comment

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

I just check it and everything is fine.

Copy link
Member

Choose a reason for hiding this comment

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

@oesteban Did we not want to change this?

@oesteban
Copy link
Contributor Author

Three questions remain open (only 1 is relevant to this PR):

  1. Whether to patch File and Directory back in traits - I guess @effigies' would be against (?)
  2. Whether we want to simplify/refactor the implementation of hash_files (ENH: Add resolve/rebase BasePath traits methods & tests #2970 (comment)): this PR is a drop-in replacement of traits that should allow FIX: Resolving/rebasing paths from/to results files #2971 to remain strictly scoped into reading/writing of results files (i.e., no need to rework hash_files).
  3. Whether we want to implement the config use_relative_paths, which I think fully pertains to the Interface level (i.e., it would be independent of the internal format of results files).

cc @satra

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.

LGTM. 🤞 for the tests.

oesteban and others added 12 commits July 31, 2019 23:28
Two new methods ``resolve_path_traits`` and ``rebase_path_traits`` are
being included.

They take trait instances from a spec (selected via
``spec.trait('traitname')``, the value and a base path.

These two functions will be usefull to progress towards nipy#2944.
Co-Authored-By: Chris Markiewicz <effigies@gmail.com>
Co-Authored-By: Chris Markiewicz <effigies@gmail.com>
- [x] Removed traits.api patches
- [x] Deduplicated code with a _recurse_on_path_traits proxy
      (nipy#2970 (comment))
- [x] Added the two proposed test cases
- [x] Optimized loop (see nipy#2970 (comment))
@oesteban oesteban force-pushed the enh/resolve-rebase-paths branch from a1d6301 to 699b6cf Compare August 1, 2019 06:28
@oesteban oesteban force-pushed the enh/resolve-rebase-paths branch from 699b6cf to b0c80d7 Compare August 1, 2019 06:31
@oesteban
Copy link
Contributor Author

oesteban commented Aug 1, 2019

Ready to go :)

@effigies effigies merged commit 5965d45 into nipy:master Aug 1, 2019
@oesteban oesteban deleted the enh/resolve-rebase-paths branch August 1, 2019 16:18
@effigies effigies added this to the 1.2.1 milestone Aug 16, 2019
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.

5 participants