Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -760,3 +760,24 @@ processing at value 3
processing at value 4
[0, 2]
```

# Chaining pipes

You can combine multiple pipes into a new one:

```python
class ErrorDatabase:
def __init__(self):
self.lines = []

def filter_lines_by(self, predicate):
filtered_lines = list(self.lines | predicate)
# further processing of filtered_lines
# ...
return filtered_lines

db = ErrorDatabase()
# here we combine pipes into a new one to pass it to a function call
expired_reports = has_error_code | reported_by_end_customer | older_than_days(30)
errors = db.filter_lines_by(expired_reports)
```
9 changes: 8 additions & 1 deletion pipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ def __init__(self, function):
def __ror__(self, other):
return self.function(other)

def __or__(self, other):
return self.__class__(
lambda iterable, *args2, **kwargs2: other.function(
self.function(iterable, *args2, **kwargs2)
)
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I am just wondering, what if other is a pipeable object but not an instance of Pipe ?!?
Would it not be better to use:

def __or__(self, other):
    cls = self.__class__
    if isinstance(other, Pipe):
        return cls(lambda iterable, *args2, **kwargs2: (
                   other.function(self.function(iterable, *args2, **kwargs2))))

    # -- CASE: other is pipeable only
    return cls(lambda iterable, *args2, **kwargs2: (
               self.function(iterable, *args2, **kwargs2) | other))


def __call__(self, *args, **kwargs):
return Pipe(
return self.__class__(
lambda iterable, *args2, **kwargs2: self.function(
iterable, *args, *args2, **kwargs, **kwargs2
)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_pipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,15 @@ def test_enumerate():
data = [4, "abc", {"key": "value"}]
expected = [(5, 4), (6, "abc"), (7, {"key": "value"})]
assert list(data | pipe.enumerate(start=5)) == expected


def test_concatenate_pipes():
data = range(10)
is_even = pipe.where(lambda x: x % 2 == 0)
higher_than_4 = pipe.where(lambda x: x > 4)
expected = [6,8]
# standard behavior
assert list(data | is_even | higher_than_4) == expected
# concatenated pipes
is_even_and_higher_than_4 = is_even | higher_than_4
assert list(data | is_even_and_higher_than_4) == expected