Skip to content

Commit 9231a5a

Browse files
authored
Merge pull request #21 from caspervdw/pipeline-properties
ENH Property-changing pipelines
2 parents ba2ffd7 + c665a31 commit 9231a5a

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

slicerator.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,57 @@ def wrapper(f):
519519
return wrapper(func)
520520

521521

522-
def _pipeline(func, retain_doc=False):
522+
def _pipeline(func_or_class, **kwargs):
523+
try:
524+
is_class = issubclass(func_or_class, Pipeline)
525+
except TypeError:
526+
is_class = False
527+
if is_class:
528+
return _pipeline_fromclass(func_or_class, **kwargs)
529+
else:
530+
return _pipeline_fromfunc(func_or_class, **kwargs)
531+
532+
533+
def _pipeline_fromclass(cls, retain_doc=False):
534+
"""Actual `pipeline` implementation
535+
536+
Parameters
537+
----------
538+
func : class
539+
Class for lazy evaluation
540+
retain_doc : bool
541+
If True, don't modify `func`'s doc string to say that it has been
542+
made lazy
543+
544+
Returns
545+
-------
546+
Pipeline
547+
Lazy function evaluation :py:class:`Pipeline` for `func`.
548+
"""
549+
@wraps(cls)
550+
def process(obj, *args, **kwargs):
551+
if hasattr(obj, '_slicerator_flag') or isinstance(obj, Slicerator) \
552+
or isinstance(obj, Pipeline):
553+
return cls(obj, *args, **kwargs)
554+
else:
555+
# Fall back on normal behavior of func, interpreting input
556+
# as a single image.
557+
return cls([obj], *args, **kwargs)[0]
558+
559+
if not retain_doc:
560+
if process.__doc__ is None:
561+
process.__doc__ = ''
562+
process.__doc__ = ("This function has been made lazy. When passed\n"
563+
"a Slicerator, it will return a \n"
564+
"Pipeline of the results. When passed \n"
565+
"any other objects, its behavior is "
566+
"unchanged.\n\n") + process.__doc__
567+
process.__name__ = cls.__name__
568+
return process
569+
570+
571+
572+
def _pipeline_fromfunc(func, retain_doc=False):
523573
"""Actual `pipeline` implementation
524574
525575
Parameters
@@ -541,6 +591,7 @@ def process(obj, *args, **kwargs):
541591
or isinstance(obj, Pipeline):
542592
def proc_func(x):
543593
return func(x, *args, **kwargs)
594+
544595
return Pipeline(obj, proc_func)
545596
else:
546597
# Fall back on normal behavior of func, interpreting input

tests.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from six import BytesIO
1010
import pickle
1111
from nose.tools import assert_true, assert_false, assert_equal, assert_raises
12-
from slicerator import Slicerator, pipeline, index_attr, propagate_attr
12+
from numpy.testing import assert_array_equal
13+
from slicerator import Slicerator, Pipeline, pipeline, index_attr, propagate_attr
1314

1415
path, _ = os.path.split(os.path.abspath(__file__))
1516
path = os.path.join(path, 'data')
@@ -350,6 +351,29 @@ def test_composed_pipelines():
350351
assert_letters_equal(composed, 'zbCdefghij')
351352

352353

354+
def test_pipeline_class():
355+
sli = Slicerator(np.empty((10, 32, 64)))
356+
357+
@pipeline
358+
class crop(Pipeline):
359+
def __init__(self, reader, bbox):
360+
self.bbox = bbox
361+
Pipeline.__init__(self, reader, None)
362+
363+
def _get(self, key):
364+
bbox = self.bbox
365+
return self._ancestor[key][bbox[0]:bbox[2], bbox[1]:bbox[3]]
366+
367+
@property
368+
def frame_shape(self):
369+
bbox = self.bbox
370+
return (bbox[2] - bbox[0], bbox[3] - bbox[1])
371+
372+
cropped = crop(sli, (5, 5, 10, 20))
373+
assert_array_equal(cropped[0], sli[0][5:10, 5:20])
374+
assert_array_equal(cropped.frame_shape, (5, 15))
375+
376+
353377
def test_serialize():
354378
# dump Slicerator
355379
stream = BytesIO()

0 commit comments

Comments
 (0)