Skip to content

Commit 0f2d50e

Browse files
committed
README: shorten
1 parent 471370e commit 0f2d50e

File tree

1 file changed

+33
-54
lines changed

1 file changed

+33
-54
lines changed

README.md

Lines changed: 33 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,16 @@
88

99
- 🔗 ***Fluent*** chainable lazy operations
1010
- 🔀 ***Concurrent*** via *threads*/*processes*/`async`
11-
- 🇹 ***Typed***, fully annotated, `Stream[T]` is both an `Iterable[T]` and an `AsyncIterable[T]`
12-
- 🛡️ ***Tested*** extensively with **Python 3.7 to 3.14**
13-
- 🪶 ***Light***, no dependencies
14-
11+
- 🇹 Fully ***Typed***, `Stream[T]` is both an `Iterable[T]` and an `AsyncIterable[T]`
12+
- 🛡️ ***Battle-tested*** for prod, extensively tested with **Python 3.7 to 3.14**.
1513

1614

1715
## 1. install
1816

17+
> no dependencies
1918
```bash
2019
pip install streamable
21-
```
22-
*or*
23-
```bash
20+
# or
2421
conda install conda-forge::streamable
2522
```
2623

@@ -52,7 +49,7 @@ inverses: Stream[float] = (
5249

5350
## 5. iterate
5451

55-
Iterate over a `Stream[T]` just as you would over any other `Iterable[T]`/`AsyncIterable`, elements are processed *on-the-fly*:
52+
Iterate over a `Stream[T]` just as you would over any other `Iterable[T]` (or `AsyncIterable`), elements are processed *on-the-fly*:
5653

5754

5855
### as `Iterable[T]`
@@ -113,9 +110,7 @@ Iterate over a `Stream[T]` just as you would over any other `Iterable[T]`/`Async
113110

114111
# ↔ example: Extract-Transform-Load
115112

116-
Let's take an example showcasing most of the `Stream`'s operations:
117-
118-
**ETL scripts** can benefit from the expressiveness of this library. Below is a pipeline that extracts the 67 quadruped Pokémon from the first three generations using [PokéAPI](https://pokeapi.co/) and loads them into a CSV:
113+
Let's take an example showcasing most of the `Stream`'s operations: Below is a pipeline that extracts the 67 quadruped Pokémon from the first three generations using [PokéAPI](https://pokeapi.co/) and loads them into a CSV:
119114

120115
```python
121116
import csv
@@ -164,7 +159,7 @@ with open("./quadruped_pokemons.csv", mode="w") as file:
164159

165160
## or the `async` way
166161

167-
- use `.amap`: the `.map`'s `async` counterpart, see [`async` Operations](#-async-operations).
162+
- use the `.amap` operation: the `.map`'s `async` counterpart, see [`async` Operations](#-async-operations).
168163
- `await` the `Stream`: runs a full iteration over it as an `AsyncIterable[T]`.
169164

170165
```python
@@ -219,8 +214,6 @@ asyncio.run(main())
219214

220215
# 📒 ***Operations***
221216

222-
*A dozen expressive lazy operations and that’s it!*
223-
224217
## `.map`
225218

226219
> Applies a transformation on elements:
@@ -234,14 +227,9 @@ assert list(integer_strings) == ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9
234227
```
235228
</details>
236229

237-
### concurrency
238-
239-
> [!NOTE]
240-
> By default, all the concurrency modes presented below yield results in the upstream order (FIFO). Set the parameter `ordered=False` to yield results as they become available (***First Done, First Out***).
241-
242230
### thread-based concurrency
243231

244-
> Applies the transformation via `concurrency` threads:
232+
> Applies the transformation via `concurrency` threads, yielding results in the upstream order (FIFO), set the parameter `ordered=False` to yield results as they become available (*First Done, First Out*).
245233
246234
<details ><summary style="text-indent: 40px;">👀 show snippet</summary></br>
247235

@@ -260,10 +248,7 @@ assert list(pokemon_names) == ['bulbasaur', 'ivysaur', 'venusaur']
260248
</details>
261249

262250
> [!NOTE]
263-
> `concurrency` is also the size of the buffer containing not-yet-yielded results. **If the buffer is full, the iteration over the upstream is paused** until a result is yielded from the buffer.
264-
265-
> [!TIP]
266-
> The performance of thread-based concurrency in a CPU-bound script can be drastically improved by using a [Python 3.13+ free-threading build](https://docs.python.org/3/using/configure.html#cmdoption-disable-gil).
251+
> **Memory-efficient**: Only `concurrent` upstream elements are pulled for processing; the next upstream element is pulled only when a result is yielded downstream.
267252
268253
### process-based concurrency
269254

@@ -281,9 +266,9 @@ if __name__ == "__main__":
281266
```
282267
</details>
283268

284-
### `async`-based concurrency: [see `.amap`](#amap)
269+
### `async`-based concurrency: [`.amap`](#amap)
285270

286-
> [The `.amap` operation can apply an `async` function concurrently.](#amap)
271+
> The [`.amap`](#amap) operation can apply an `async` function concurrently.
287272
288273
### "starmap"
289274

@@ -304,7 +289,6 @@ assert list(zeros) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
304289
</details>
305290

306291

307-
308292
## `.foreach`
309293

310294
> Applies a side effect on elements:
@@ -326,7 +310,7 @@ assert state == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
326310
> - set the `concurrency` parameter for **thread-based concurrency**
327311
> - set `via="process"` for **process-based concurrency**
328312
> - set `ordered=False` for ***First Done First Out***
329-
> - [The `.aforeach` operation can apply an `async` effect concurrently.](#aforeach)
313+
> - The [`.aforeach`](#aforeach) operation can apply an `async` effect concurrently.
330314
331315
## `.group`
332316

@@ -590,7 +574,7 @@ assert list(status_codes_ignoring_resolution_errors) == [200, 404]
590574
> It has an optional `finally_raise: bool` parameter to raise the first exception caught (if any) when the iteration terminates.
591575
592576
> [!TIP]
593-
> Apply side effects when catching an exception by integrating them into `when`:
577+
> Leverage `when` to apply side effects on catch:
594578
595579
<details ><summary style="text-indent: 40px;">👀 show snippet</summary></br>
596580

@@ -675,7 +659,6 @@ assert list(integers + integers) == [0, 1, 2, 3 ,4, 5, 6, 7, 8, 9, 0, 1, 2, 3 ,4
675659

676660
## `zip`
677661

678-
> [!TIP]
679662
> Use the standard `zip` function:
680663
681664
<details ><summary style="text-indent: 40px;">👀 show snippet</summary></br>
@@ -694,8 +677,8 @@ assert list(cubes) == [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
694677

695678

696679
## Shorthands for consuming the stream
697-
> [!NOTE]
698-
> Although consuming the stream is beyond the scope of this library, it provides two basic shorthands to trigger an iteration:
680+
681+
Although consuming the stream is beyond the scope of this library, it provides two basic shorthands to trigger an iteration:
699682

700683
## `.count`
701684

@@ -723,7 +706,7 @@ assert state == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
723706

724707
## `.pipe`
725708

726-
> Calls a function, passing the stream as first argument, followed by `*args/**kwargs` if any:
709+
> Calls a function, passing the stream as first argument, followed by `*args/**kwargs` if any (inspired by the `.pipe` from [pandas](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.pipe.html) or [polars](https://docs.pola.rs/api/python/stable/reference/dataframe/api/polars.DataFrame.pipe.html)):
727710
728711
<details ><summary style="text-indent: 40px;">👀 show snippet</summary></br>
729712

@@ -739,24 +722,20 @@ import pandas as pd
739722
```
740723
</details>
741724

742-
> Inspired by the `.pipe` from [pandas](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.pipe.html) or [polars](https://docs.pola.rs/api/python/stable/reference/dataframe/api/polars.DataFrame.pipe.html).
743-
744725
---
745726
---
746727

747728
# 📒 ***`async` Operations***
748729

749-
Operations that accept a function as an argument have an `async` counterpart, which has the same signature but accepts `async` functions instead. These `async` operations are named the same as the original ones but with an `a` prefix.
730+
The operations accepting a function as an argument have an `async` counterpart operation, which has the same signature but accepts `async` functions instead.
750731

751-
> [!TIP]
752-
> One can mix regular and `async` operations on the same `Stream`, and then consume it as a regular `Iterable` or as an `AsyncIterable`.
732+
**inter-operability**: Both regular and `async` operations can be mixed on the same `Stream`, and it can then be consumed as regular `Iterable` or as `AsyncIterable`.
753733

754-
## `.amap`
734+
## `.amap`
755735

756736
> Applies an `async` transformation on elements:
757737
758-
759-
> consumed as an `Iterable[T]`:
738+
- consume as `Iterable[T]`:
760739

761740
<details ><summary style="text-indent: 40px;">👀 show snippet</summary></br>
762741

@@ -779,7 +758,7 @@ asyncio.run(http_async_client.aclose())
779758
```
780759
</details>
781760

782-
> or consumed as an `AsyncIterable[T]`:
761+
- consume as `AsyncIterable[T]`:
783762

784763
<details ><summary style="text-indent: 40px;">👀 show snippet</summary></br>
785764

@@ -802,29 +781,29 @@ asyncio.run(main())
802781
```
803782
</details>
804783

805-
## Other `async` operations
784+
## Others
806785

807-
> `.aforeach`: Applies an `async` side effect on elements. Supports `concurrency` like `.amap`.
786+
> **`.aforeach`**: Applies an `async` side effect on elements. Supports `concurrency` like `.amap`.
808787
809-
> `.agroup`: Groups into `List`s according to an `async` grouping function.
788+
> **`.agroup`**: Groups into `List`s according to an `async` grouping function.
810789
811-
> `.agroupby`: Groups into `(key, elements)` tuples, according to an `async` grouping function.
790+
> **`.agroupby`**: Groups into `(key, elements)` tuples, according to an `async` grouping function.
812791
813-
> `.aflatten`: Ungroups elements assuming that they are `AsyncIterable`s. Like for `.flatten` you can set the `concurrency` parameter.
792+
> **`.aflatten`**: Ungroups elements assuming that they are `AsyncIterable`s. Like for `.flatten` you can set the `concurrency` parameter.
814793
815-
> `.afilter`: Keeps only the elements that satisfy an `async` condition.
794+
> **`.afilter`**: Keeps only the elements that satisfy an `async` condition.
816795
817-
> `.adistinct`: Removes duplicates according to an `async` deduplication `key`.
796+
> **`.adistinct`**: Removes duplicates according to an `async` deduplication `key`.
818797
819-
> `.atruncate`: Ends iteration once a given number of elements have been yielded or `when` an `async` condition is satisfied.
798+
> **`.atruncate`**: Ends iteration once a given number of elements have been yielded or `when` an `async` condition is satisfied.
820799
821-
> `.askip`: Skips the specified number of elements or `until` an `async` predicate is satisfied.
800+
> **`.askip`**: Skips the specified number of elements or `until` an `async` predicate is satisfied.
822801
823-
> `.acatch`: Catches a given type of exception `when` an `async` condition is satisfied.
802+
> **`.acatch`**: Catches a given type of exception `when` an `async` condition is satisfied.
824803
825804
## Shorthands for consuming the stream as an `AsyncIterable[T]`
826805

827-
## `.acount`
806+
### `.acount`
828807

829808
> Iterates over the stream until exhaustion and returns the number of elements yielded:
830809
@@ -836,7 +815,7 @@ assert asyncio.run(integers.acount()) == 10
836815
</details>
837816

838817

839-
## `await`
818+
### `await`
840819

841820
> *Awaiting* the stream iterates over it until exhaustion and returns it:
842821

0 commit comments

Comments
 (0)