-
Notifications
You must be signed in to change notification settings - Fork 9
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
Add support for pipelines with multiple inputs #30
Conversation
Still missing: - docs - tests - Python 2 compatibility
Here is a first working (at least on Python 3.6) implementation. Key features are
Example: @pipeline(argc="all")
def add(a1, a2):
return a1 + a2
i1 = pims.open("img1.tif")
i2 = pims.open("img2.tif")
i12 = add(i1, i2) |
Since there were no objections, I finished and tested the implementation. I'd love to see this merged. |
Thanks a lot @lschr and sorry for the lack of attention to this project. I will review this within the next week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lschr Thanks for this fantastic generalization of the pipelines! I left some minor notes in the review, and also one use case that your code (probably) does not cover yet.
slicerator/__init__.py
Outdated
it specifies the index of the ancestor (in `ancestors`). If it is | ||
'first', go through all ancestors starting with the first one until | ||
one is found that has the attribute. If it is 'last', go through | ||
the ancestors in reverse order. Defaults to 0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to stick to int
here and using negative integers for indexing from the end of the ancestors
list. So 0
equals 'first'
and -1
equals 'last'
. Probably the implementation will simplify because this is normal Python list indexing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I now understand the necessity of this implementation, please ignore my comment.
slicerator/__init__.py
Outdated
|
||
def __len__(self): | ||
return self._ancestor.__len__() | ||
return min(a.__len__() for a in self._ancestors) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not len(a)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess because it was self._ancestor.__len__()
orginally. Since I did not know why, I did not change it.
slicerator/__init__.py
Outdated
If True, don't modify `func`'s doc string to say that it has been | ||
made lazy. Defaults to False | ||
argc : int or 'all', optional | ||
Number of arguments that are relevant for the pipeline. For instance, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit unclear to me, may be something like 'Number of arguments that are indexed by the pipeline'
, and the name itself, argc
, could be turned into the more comprehensive indexed_arg_count
? Or ancestor_count
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed the doc and went with ancestor_count to keep it reasonably short.
slicerator/__init__.py
Outdated
|
||
Returns | ||
------- | ||
Pipeline | ||
Lazy function evaluation :py:class:`Pipeline` for `func`. | ||
""" | ||
if isinstance(argc, str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There could be a Py2/3 issue here. Maybe better: if argc == 'all':
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
else: | ||
# Fall back on normal behavior of func, interpreting input | ||
# as a single image. | ||
return cls([obj], *args, **kwargs)[0] | ||
return cls(*(tuple([a] for a in ancestors) + args), **kwargs)[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably doesn't cover the case of 1 indexable and 1 non-indexable ancestor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is (currently) not supported and also I think it would be non-trivial to implement. A user requiring such a thing could either set ancestor_count=1
(with reduced flexibility with respect to the second ancestor) or manually turn the second ancestor into a Slicerator
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, this is some kind of array casting. I am 👍 to make the absence of array casting explicit and not allow ancestor
s with unequal lengths inside a Pipeline
. So that would include adding a check at the __init__
and adapting the __len__
. What do you think?
slicerator/__init__.py
Outdated
or isinstance(obj, Pipeline): | ||
def proc_func(x): | ||
return func(x, *args, **kwargs) | ||
if isinstance(argc, str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@lschr See my line comment. @danielballan do you want to check this as well before merging? |
@caspervdw I think you are right. Let the user deal with differently-sized ancestors himself since he is the only one knowing how to do so properly anyways. |
Thanks @lschr, good to merge from my side. @danielballan ? |
I would like to look at this before merging. Swamped today, will try to look this weekend. |
I haven't had a chance to look at this, but I don't want to keep blocking progress, so I will trust @caspervdw and push the green button. Sorry for the hold-up! |
Implementation of the feature discussed in #29.