Skip to main content

Nice and clean iterator patterns for python

Project description

FluentIter

Nicer iterator patterns for Python! Chain map, filter, zip, unzip, cycle, skip and scan like there is no tomorrow.

Install with

pip install fluentiter

Straight to the API docs 👉

TLDR:

With fluentiter you can do this

lines = iterator(haystack_csv.split("\n"))
header = [x for x in lines.next().split(",") if x.strip(" ")]
needle = (
    lines.map(lambda line: line.split(","))
    .map(lambda values: {k: v for k, v in zip(header, values)})
    .filter(lambda value_dct: value_dct["material"] != "hay")
    .find(lambda value_dct: value_dct["type"] == "needle")
)

instead of this

lines = iter(some_csv.split("\n"))
header = [x for x in next(lines).split(",") if x.strip()]
needle = next(
    filter(
        lambda value_dct: value_dct["material"] != "hay",
        filter(
            lambda value_dct: value_dct["type"] == "needle",
            map(
                lambda values: {k: v for k, v in zip(header, values)},
                map(lambda line: line.split(","), lines),
            ),
        ),
    )
)

See the this example for a more complete version.

Motivation

To me Pythons iterator functions (i.e. map, filter, zip, etc.) always seemed backward. While generator expressions and list/dict/set comprehensions give you nice left-to-right readability, map and filter force you to read "inside-out":

[func(x) for x in something if x == y]
map(func, filter(lambda x: x == y, something))

This is not an issue for short an simple statements, as they can be written concisely using expressions, but chaining multiple operations, will result in either many intermediate variable assignements or serious spaghettification.

How to use

Any Iterable can be turned into a FluentIterator by just passing it to the iterator function:

from fluentiter import iterator
bugs = ["john", "paul", "ringo", "george"]

fluent = iterator(bugs)
# you can now do
# fluent.map(...).filter(...).cycle(...).scan(...) and so on

The FluentIterator provides a rich set of methods you can call and chain together to your liking:

Of course there are the classic map, filter, and reduce functions, but also some more really useful features like cycle to repeat an iterator forever, find to find an element, into to collect into containers, or apply to transform and continue chaining. There's even partition to turn your iterator into two.

In total FluentIterator provides 38 methods to compose beautiful and easy to follow iteration patterns. Check the API docs to see them all.

Features

  • 38 cool fresh iterator methods
  • 100% Type annotated e.g. iterator(["foo", "bar"]).map(len).to_list() gets correctly inferred as list[int]
  • 100% Test coverage
  • 0 dependencies outside the Python standard library[^0]

Contributing

The simplest way to contribute is to open an issue. If you would like to see some feature implemented or found a bug, head over to the issues section.

Developing

  1. Clone the repository
  2. Install uv
  3. Install development dependencies with uv sync --all-extras

Guidelines

Your PR should include relevant tests for the changes you are contributing and be fully type annotated. If you are unsure or stuck, please open the PR anyway and we can work it out together.

By opening a PR you agree to your code becoming part of the fluentiter package and being published under fluentiters license.

Running formatting, tests, and linting

  • Formatting: uv run poe format
  • Linting: uv run poe lint
  • Tests: uv run poe test

All of the above: uv run poe all

Viewing the coverage report

Running uv run coverage html will create a file htmlcov/index.html you can open to view the test coverage report

Changelog

  • 1.0.0
    • initial release
  • 1.0.1
    • fixed errors int readme
  • 1.1.0
    • add into(...) method
  • 1.1.1
    • add py.typed marker file
  • 1.2.0
    • add tumbling_window function
    • fix mypy inference on .flatten() and .flat_map
    • fix more_itertools being installed automatically
  • 1.2.1
    • fix parameter key not being respected in .min and .max
  • 1.3.0
    • add apply(...) method
    • drop support for Python 3.9

Special Thanks

Thank you to all Rust maintainers for creating the Iterator trait, which served as the main source of inspiration.

[^0]: Some functions may require the more extra which has more-itertools as a dependency

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

fluentiter-1.3.0.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

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

fluentiter-1.3.0-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file fluentiter-1.3.0.tar.gz.

File metadata

  • Download URL: fluentiter-1.3.0.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fluentiter-1.3.0.tar.gz
Algorithm Hash digest
SHA256 579b3a58bc3736a31f1f85406b72c9bee80f2fcdc5584a069f9c7355d58adfc2
MD5 d0b2b80818852a6f7d63b616c40c9a34
BLAKE2b-256 092db227769700c64c6e431abfb559baa9ff630f02c5556a955771302de32a8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for fluentiter-1.3.0.tar.gz:

Publisher: publish-pypi.yml on damiondoesthings/fluentiter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fluentiter-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: fluentiter-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 14.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fluentiter-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d3aa07f3c4c182feb4c73c734653b60d3d9cfb09257c2d0557776fda290c70e
MD5 8c041f590930de732f0bbe9e418b2501
BLAKE2b-256 613dd2b8337f9053006e099117c1ee1f85199d3193091a1c4d88fce126b78c54

See more details on using hashes here.

Provenance

The following attestation bundles were made for fluentiter-1.3.0-py3-none-any.whl:

Publisher: publish-pypi.yml on damiondoesthings/fluentiter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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