Skip to main content

Yet another python streams library

Project description

Tests Status Code Coverage Status PyPI version

tinystream / python-streams

This is a simple and lightweight Streams API inspired by Java Streams with support for type hinting.

This package is released as tinystream at pypi.

Basic API

from tinystream import Stream

stream = Stream([1, 2, 3, 4, 5])  # Stream.of_many(*), Stream.of_dict()

stream \
    .map(lambda x: x + 1) \       # flatmap(), peek(), map_key(), map_kwargs(), map_keys()
    .filter(lambda x: x > 2) \    # filter_key(), filter_type()
    .sorted(reverse=True) \       # sort()
    .reverse() \
    .limit(2) \
    .concat([4]) \
    .sum()                        # reduce(), max(), min(), collect(), count(), find()

Aggregators

Aggregators like sum(), count(), max() will collect() the data and end the stream. collect() also caches the data and can be called multiple times, since it returns only a list.

Built-in Optional support

Some aggregators like sum(), max() are Opt:

assert Stream((1, 2, 3, 4, 5)).sum().get() == 15

More features

Type hinting

You can typehint datatypes like:

from dataclasses import dataclass

@dataclass
class Node:
    name: str
    parent: "Node" = None

parent = Node(name="B")
child = Node(name="A", parent=parent)

for lambdas:

stream = Stream([child])
assert stream.map(lambda x: x.parent).type(Node).next().get().name == "B"

This is not necessary when you pass a mapping function:

def map_parent(n: Node):
    return n.parent

assert stream.map(map_parent).next().get().name == "B"

Typed dictionaries

Dictionaries are streamed as tuple(key, value)

children = {"a": Node(name="Child")} 
stream = Stream.of_dict(children)
for item in stream:
    # item[0] is known as str
    # item[1] is known as Node

This is the same like (but without known types):

stream = Stream(children)

Filter by existing key

items_with_name = Stream([child]).filter_key("name")

Filter by key value

items_with_name = Stream([child]).filter_key_value("name", "Child")

Filter by type

nodes_only = Stream([child]).filter_type(Node)

Map object name attribute

names = Stream([child]).map_key("name")

Deep mapping of name attributes

list = [
   {"node": Node(name="Node A")},
   {"node": Node(name="Node B")},
   {"node": Node(name="Node C")},
   {"node": Node(name="Node D")},
]
names = Stream(list).map_keys("node", "name")

Collected join

all_names = Stream([child]).map_key("name").join(", ")

Map kwargs

list = [
   {"name": "Node A"},
   {"name": "Node B"},
]
# Short cut for map(lambda x: Node(**x))
nodes = Stream(list).map_kwargs(Node)

Stream many

many = Stream.of_many([1, 2, 3], (4, 5, 6))
many = many.concat([7, 8, 9])

End of stream

stream = Stream(["a", "b", "c"]).on_end(lambda: print("Finished"))
char = stream.next().get()
if char == "a":
    stream.end()

Opt usage

Get next value as Opt:

assert Stream((1, 2, 3, 4, 5)).next().present

Mapping:

assert Opt("String").map(str.lower).len == 6

Get default value:

assert Opt(None).get(6) == 6
assert Opt(None).get(lambda: 6) == 6
assert Opt(None).if_absent(lambda: 3).present

Filter value:

assert Opt(0).filter(lambda x: x > 0).absent

You can also access optional index elements of the stream, but this will collect() and end the stream.

assert Stream([])[2].absent

Examples

Write better code with Stream

data = {
   "ranges": [
      {"days": 3},
      {"weeks": 1},
   ]
}

# With tinystream Stream
for range_data in Opt(data).map_key("ranges").stream().map_kwargs(timedelta):
   pass

# Vanilly Python
if "ranges" in data:
   range_data: timedelta
   for range_data in map(lambda x: timedelta(**x), data["ranges"]):
      pass

Write better code with Opt

# tinystream Opt
var = Opt(my_dict).kmap("key").filter(not_empty).get("default")

# Vanilla Python
var = my_dict["key"] if "key" in my_dict and not_empty(my_dict["key"]) else "default"

Comparison with other libraries

There are a couple of other implementation to fulfill similar requirements.

Run the tests

PYTHONPATH="." pytest --cov=tinystream -n 4 tests/

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tinystream-0.1.18.tar.gz (8.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tinystream-0.1.18-py3-none-any.whl (6.2 kB view details)

Uploaded Python 3

File details

Details for the file tinystream-0.1.18.tar.gz.

File metadata

  • Download URL: tinystream-0.1.18.tar.gz
  • Upload date:
  • Size: 8.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for tinystream-0.1.18.tar.gz
Algorithm Hash digest
SHA256 acd8ea3940f9b1d2613bee3627eda5f89a0d0e8e9660a95a075a9ce2f815ed3a
MD5 5b159503ebe41043a8fffd5af7600ded
BLAKE2b-256 261b6aaf86d182ca9b7fe0512637250a4e39e3675ceabc023c4fe556f87ce836

See more details on using hashes here.

File details

Details for the file tinystream-0.1.18-py3-none-any.whl.

File metadata

  • Download URL: tinystream-0.1.18-py3-none-any.whl
  • Upload date:
  • Size: 6.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for tinystream-0.1.18-py3-none-any.whl
Algorithm Hash digest
SHA256 b210b00a6a973a02a4c7c398e22b3b53cf1b5a4404760697e14eb8ae1abe8d7d
MD5 873b80c280402463630921f9ee01eab1
BLAKE2b-256 d87be063c211c67aa43001841be8eb5ec3b30bd83a7743151bcc7bff6006c54d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page