From 69dd2ec55eb5abb48c939003e97434dd6c89f84d Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Mon, 23 May 2022 10:12:10 +0200 Subject: [PATCH] Hello pipe 2.0. --- content/blog/2022-pipe-v2.md | 141 +++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 content/blog/2022-pipe-v2.md diff --git a/content/blog/2022-pipe-v2.md b/content/blog/2022-pipe-v2.md new file mode 100644 index 0000000..e7feeae --- /dev/null +++ b/content/blog/2022-pipe-v2.md @@ -0,0 +1,141 @@ +--- +Title: Releasing pipe v2.0 +Date: 2022-05-23 09:31:00 +Summary: Introducing partially parametrized pipes! +--- + +# Introducing partially parametrized pipes! + +[pipe](https://github.com/JulienPalard/Pipe) is a very old project of mine, proudly showing 1.3k stars on github! + +I don't maintain it a lot, but today I'm announcing a new release introducing a nice feature: partially parametrized pipes. + +If you're familiar with [currying](https://en.wikipedia.org/wiki/Currying) +or +[functools.partial](https://docs.python.org/3/library/functools.html#functools.partial) +you won't get lost. + + +## Show me! + +Before `pipe 2`, the following were already valid: + +```python +>>> from random import randint +>>> from pipe import where, sort +>>> +>>> negative = where(lambda x: x < 0) +>>> positive = where(lambda x: x > 0) +>>> +>>> numbers = [randint(-10, 10) for _ in range(10)] +>>> +>>> numbers | positive | sort +[7, 10] +>>> numbers | negative | sort +[-10, -9, -8, -7, -4, -4, -2] +``` + +It allows to **name things**, naming things make +code more readable so I wanted more of it. + +It was probably underrated, I link to do this kind of things: + +```python +>>> isort = sort(key=lambda x: x**2) +>>> numbers | isort +[0, -2, -4, -4, -7, 7, -8, -9, 10, -10] +``` + +But it failed as soon as you try go deeper: + +```python +>>> numbers | isort(reverse=True) +Traceback (most recent call last): + File "", line 1, in + File "pipe.py", line 100, in __ror__ + return self.function(other) + File "pipe.py", line 103, in + return Pipe(lambda x: self.function(x, *args, **kwargs)) +TypeError: Pipe.__call__..() got an unexpected keyword argument 'reverse' +``` + +Call it a bug, that's what's pipe 2 fixes: + +```python +>>> from pipe import where, sort +>>> from random import randint +>>> numbers = [randint(-10, 10) for _ in range(10)] +>>> +>>> isort = sort(key=lambda x: x**2) +>>> numbers | isort(reverse=True) +[-10, -9, 8, -6, 6, -4, 4, 4, 2, 1] +>>> +``` + +Or in the other way around: + +```python +>>> rsort = sort(reverse=True) +>>> numbers | rsort +[8, 6, 4, 4, 2, 1, -4, -6, -9, -10] +>>> numbers | rsort(key=lambda x: x**2) +[-10, -9, 8, -6, 6, -4, 4, 4, 2, 1] +``` + +From here you can build many specialized blocks from a single pipe, +here's a better example: + +```python +import re + +from pipe import Pipe + + +@Pipe +def grep(iterable, pattern, flags=0, invert=False): + """Mimics grep.""" + for line in iterable: + match = re.match(pattern, line, flags=flags) + if (match and not invert) or (not match and invert): + yield line +``` + +Build the small reusable blocks: + +```python +igrep = grep(flags=re.I) +vgrep = grep(invert=True) +vigrep = igrep(invert=True) +https = igrep("https://") +not_https = https(invert=True) +... +``` + +And they all do what you think they do: + +```python +>>> lines = ["https://python.org", "http://detectportal.firefox.com/", "Just no an URL", "HTTPS://afpy.org"] +>>> for url in lines | https: +... print(url) +... +https://python.org +HTTPS://afpy.org +``` + +```python +>>> for url in lines | not_https: +... print(url) +... +http://detectportal.firefox.com/ +Just no an URL +``` + +Remember I said currying? Yes you can abuse the syntax, but please don't: + +```python +>>> from pipe import sort +>>> lines | grep()(invert=True)()(flags=re.I)()("https://")() | sort +['Just no an URL', 'http://detectportal.firefox.com/'] +``` + +As I like to say: « It's not because it's possible than you should do it ».