Skip to main content

danom

PyPI Downloads coverage CodSpeed Ruff ty

API Reference

danom API docs

Stream

An immutable lazy iterator with functional operations.

Why bother?

Readability counts, abstracting common operations helps reduce cognitive complexity when reading code.

Comparison

Take this imperative pipeline of operations, it iterates once over the data, skipping the value if it fails one of the filter checks:

>>> res = []
...
>>> for x in range(1_000_000):
...     item = triple(x)
...
...     if not is_gt_ten(item):
...         continue
...
...     item = min_two(item)
...
...     if not is_even_num(item):
...         continue
...
...     item = square(item)
...
...     if not is_lt_400(item):
...         continue
...
...     res.append(item)
>>> [100, 256]

number of tokens: 90

number of keywords: 11

keyword breakdown: {'for': 1, 'in': 1, 'if': 3, 'not': 3, 'continue': 3}

After a bit of experience with python you might use list comprehensions, however this is arguably less clear and iterates multiple times over the same data

>>> mul_three = [triple(x) for x in range(1_000_000)]
>>> gt_ten = [x for x in mul_three if is_gt_ten(x)]
>>> sub_two = [min_two(x) for x in gt_ten]
>>> is_even = [x for x in sub_two if is_even_num(x)]
>>> squared = [square(x) for x in is_even]
>>> lt_400 = [x for x in squared if is_lt_400(x)]
>>> [100, 256]

number of tokens: 92

number of keywords: 15

keyword breakdown: {'for': 6, 'in': 6, 'if': 3}

This still has a lot of tokens that the developer has to read to understand the code. The extra keywords add noise that cloud the actual transformations.

Using a Stream results in this:

>>> from danom import Stream
>>> (
...     Stream.from_iterable(range(1_000_000))
...     .map(triple)
...     .filter(is_gt_ten)
...     .map(min_two)
...     .filter(is_even_num)
...     .map(square)
...     .filter(is_lt_400)
...     .collect()
... )
>>> (100, 256)

number of tokens: 60

number of keywords: 0

keyword breakdown: {}

The business logic is arguably much clearer like this.

Result

Result monad. Consists of Ok and Err for successful and failed operations respectively. Each monad is a frozen instance to prevent further mutation. Err provides the details attribute which returns the full traceback as a list of dictionaries.

safe

safe

safe(func: collections.abc.Callable[[T], U]) -> collections.abc.Callable[[T], danom._result.Result]

Decorator for functions that wraps the function in a try except returns Ok on success else Err.

>>> from danom import safe
>>> @safe
... def add_one(a: int) -> int:
...     return a + 1

>>> add_one(1) == Ok(inner=2)

safe_method

safe_method

safe_method(func: collections.abc.Callable[[T], U]) -> collections.abc.Callable[[T], danom._result.Result]

The same as safe except it forwards on the self of the class instance to the wrapped function.

>>> from danom import safe_method
>>> class Adder:
...     def __init__(self, result: int = 0) -> None:
...         self.result = result
...
...     @safe_method
...     def add_one(self, a: int) -> int:
...         return self.result + 1

>>> Adder.add_one(1) == Ok(inner=1)

compose

compose

compose(*fns: collections.abc.Callable[[T], U]) -> collections.abc.Callable[[T], U]

Compose multiple functions into one.

The functions will be called in sequence with the result of one being used as the input for the next.

>>> from danom import compose
>>> add_two = compose(add_one, add_one)
>>> add_two(0) == 2
>>> add_two_is_even = compose(add_one, add_one, is_even)
>>> add_two_is_even(0) == True

all_of

all_of

all_of(*fns: collections.abc.Callable[[T], bool]) -> collections.abc.Callable[[T], bool]

True if all of the given functions return True.

>>> from danom import all_of
>>> is_valid_user = all_of(is_subscribed, is_active, has_2fa)
>>> is_valid_user(user) == True

any_of

any_of

any_of(*fns: collections.abc.Callable[[T], bool]) -> collections.abc.Callable[[T], bool]

True if any of the given functions return True.

>>> from danom import any_of
>>> is_eligible = any_of(has_coupon, is_vip, is_staff)
>>> is_eligible(user) == True

identity

identity

identity(x: T) -> T

Basic identity function.

>>> from danom import identity
>>> identity("abc") == "abc"
>>> identity(1) == 1
>>> identity(ComplexDataType(a=1, b=2, c=3)) == ComplexDataType(a=1, b=2, c=3)

invert

invert

invert(func: collections.abc.Callable[[T], bool]) -> collections.abc.Callable[[T], bool]

Invert a boolean function so it returns False where it would've returned True.

>>> from danom import invert
>>> invert(has_len)("abc") == False
>>> invert(has_len)("") == True

new_type

new_type

new_type(name: 'str', base_type: 'type', validators: 'Callable | Sequence[Callable] | None' = None, converters: 'Callable | Sequence[Callable] | None' = None, *, frozen: 'bool' = True)

Create a NewType based on another type.

>>> from danom import new_type
>>> def is_positive(value):
...     return value >= 0

>>> ValidBalance = new_type("ValidBalance", float, validators=[is_positive])
>>> ValidBalance("20") == ValidBalance(inner=20.0)

Unlike an inherited class, the type will not return True for an isinstance check.

>>> isinstance(ValidBalance(20.0), ValidBalance) == True
>>> isinstance(ValidBalance(20.0), float) == False

The methods of the given base_type will be forwarded to the specialised type. Alternatively the map method can be used to return a new type instance with the transformation.

>>> from danom import new_type
>>> def has_len(email: str) -> bool:
... return len(email) > 0

>>> Email = new_type("Email", str, validators=[has_len])
>>> Email("some_email@domain.com").upper() == "SOME_EMAIL@DOMAIN.COM"
>>> Email("some_email@domain.com").map(str.upper) == Email(inner='SOME_EMAIL@DOMAIN.COM')

::

Repo map

├── dev_tools
│   ├── create_examples
│   │   ├── collection
│   │   │   ├── __init__.py
│   │   │   ├── example.py
│   │   │   ├── record.py
│   │   │   └── recorder.py         # User entrypoint `example` and it's inner class `Example`
│   │   ├── transformation
│   │   │   ├── __init__.py
│   │   │   ├── ast_editing.py
│   │   │   ├── format_examples.py
│   │   │   └── transform.py
│   │   └── __init__.py
│   ├── __init__.py
│   ├── update_cov.py
│   └── update_readme.py
├── docs
│   ├── docs-build
│   │   ├── doctest
│   │   ├── doctrees
│   │   └── html
│   │       ├── _sources
│   │       └── _static
│   ├── source
│   │   └── conf.py
│   └── Makefile
├── rust
├── src
│   └── danom
│       ├── _monads
│       │   ├── __init__.py
│       │   ├── _either.py          # A simple Either monad, includes the base Either, Right and Left.
│       │   ├── _option.py
│       │   ├── _result_v2.py
│       │   └── _safe.py            # decorators that except given exception types and return a monad of the result
│       ├── _stream
│       │   ├── __init__.py
│       │   ├── _async.py
│       │   ├── _base.py            # the base class for Stream
│       │   ├── _par.py
│       │   └── _sync.py
│       ├── __init__.py
│       ├── _new_type.py            # function to create a new type, probably worth deprecating soon
│       └── _utils.py               # random junk I can't think of place to put. compose, all_of, any_of, etc
├── tests
│   ├── monads
│   │   ├── __init__.py
│   │   ├── test_either.py
│   │   ├── test_monad_laws.py
│   │   ├── test_option.py
│   │   └── test_result_v2.py
│   ├── stream
│   │   ├── __init__.py
│   │   ├── _common.py
│   │   ├── test_async.py
│   │   ├── test_par.py
│   │   └── test_sync.py
│   ├── __init__.py
│   ├── conftest.py
│   ├── test_api.py
│   ├── test_benchmarks.py
│   ├── test_new_type.py
│   ├── test_safe.py
│   └── test_utils.py
├── LICENSE
├── README.md
├── pyproject.toml
├── ruff.toml
└── uv.lock

(generated with repo-mapper-rs)
::

Metadata

Release files for danom 0.17.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for danom 0.17.1
File Size Uploaded Provenance Actions
danom-0.17.1.tar.gz 21.6 kB With provenance Details for danom-0.17.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for danom 0.17.1
File Interpreter ABI Platform Actions
danom-0.17.1-py3-none-any.whl Python 3 none any Details for danom-0.17.1-py3-none-any.whl

Total release size: 49.9 kB

Release files / danom-0.17.1.tar.gz

Download URL danom-0.17.1.tar.gz
Size 21.6 kB
Tags Source
SHA-256 checksum
How to use checksums
fc9de9ad4767937a134e7ae0502272ba9c3edc0f378a00baa7e0fe456bfac55e
BLAKE2b-256 checksum
How to use checksums
aeabeb99e8b8047c253d943c064c102b1984ae54c6f4d2bf9882047b43f7631b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / danom-0.17.1-py3-none-any.whl

Download URL danom-0.17.1-py3-none-any.whl
Size 28.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6fefa564cce40d5e9ab060162eafb3e9400bf9f80e1462492cf7f2bd8f511d8d
BLAKE2b-256 checksum
How to use checksums
04b8d158d957cd4facf8f226739921bbd98b0d876d95aa792b877e55b6f826bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Security for danom 0.17.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for danom-0.17.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.17.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page