Metadata-Version: 2.4
Name: aeventkit
Version: 3.0.0
Summary: Event-driven data pipelines
Keywords: python,asyncio,event,driven,data,pipelines
Author: Ewald R. de Wit
License-Expression: BSD-3-Clause
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Dist: numpy>=2.4.4,<3.0.0 ; extra == 'numpy'
Requires-Python: >=3.11
Project-URL: Homepage, https://github.com/ib-api-reloaded/eventkit
Project-URL: Repository, https://github.com/ib-api-reloaded/eventkit
Project-URL: Bug Tracker, https://github.com/ib-api-reloaded/eventkit/issues
Provides-Extra: numpy
Description-Content-Type: text/x-rst

|Build| |PyVersion| |Status| |PyPiVersion| |License| |Docs|

Introduction
------------

The primary use cases of eventkit are

* to send events between loosely coupled components;
* to compose all kinds of event-driven data pipelines.

The interface is kept as Pythonic as possible,
with familiar names from Python and its libraries where possible.
For scheduling asyncio is used and there is seamless integration with it.

See the examples and the
`introduction notebook <https://github.com/ib-api-reloaded/eventkit/tree/main/notebooks/eventkit_introduction.ipynb>`_
to get a true feel for the possibilities.

Note: the package is published as ``aeventkit`` and imported as ``eventkit``.

Installation
------------

::

    pip install aeventkit

    pip install aeventkit[numpy]  # with the Array operators

Python_ 3.11 or later is required (tested on CPython 3.11 to 3.15 and
PyPy 3.11).

Upgrading from 2.x? See `Upgrading to 3.0
<https://eventkit.readthedocs.io/en/latest/upgrading.html>`_ and the
`changelog <https://eventkit.readthedocs.io/en/latest/changelog.html>`_.


Examples
--------

**Create an event and connect two listeners**

.. code-block:: python

    import eventkit as ev

    def f(a, b):
        print(a * b)

    def g(a, b):
        print(a / b)

    event = ev.Event()
    event += f
    event += g
    event.emit(10, 5)

**Create a simple pipeline**

.. code-block:: python

    import eventkit as ev

    event = (
        ev.Sequence('abcde')
        .map(str.upper)
        .enumerate()
    )

    print(event.run())  # in Jupyter: await event.list()

Output::

    [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')]

**Create a pipeline to get a running average and standard deviation**

(with the numpy extra: ``pip install aeventkit[numpy]``)

.. code-block:: python

    import random
    import eventkit as ev

    source = ev.Range(1000).map(lambda i: random.gauss(0, 1))

    event = source.array(500)[ev.ArrayMean, ev.ArrayStd].zip()

    print(event.last().run())  # in Jupyter: await event.last()

Output::

    [(0.00790957852672618, 1.0345673260655333)]

**Combine async iterators together**

.. code-block:: python

    import asyncio
    import eventkit as ev

    async def ait(r):
        for i in r:
            await asyncio.sleep(0.1)
            yield i

    async def main():
        async for t in ev.Zip(ait('XYZ'), ait('123')):
            print(t)

    asyncio.run(main())  # in Jupyter: await main()

Output::

    ('X', '1')
    ('Y', '2')
    ('Z', '3')

**Real-time video analysis pipeline**

.. code-block:: python

    self.video = VideoStream(conf.CAM_ID)
    scene = self.video | FaceTracker | SceneAnalyzer
    lastScene = scene.aiter(skip_to_last=True)
    async for frame, persons in lastScene:
        ...

`Full source code <https://github.com/erdewit/heartwave/blob/100e1a89d18756e141f9dcfbb73c55a1009debf4/heartwave/app.py#L88>`_

Parallel processing
-------------------

``poolmap`` runs a function on the values of an event in a
``concurrent.futures`` executor: a process pool for CPU-bound work on all
cores, an interpreter pool (Python 3.14+), or a thread pool for blocking
I/O. Results stay in order unless ``ordered=False``, and ``chunksize``
batches small tasks:

.. code-block:: python

    import bz2
    from concurrent.futures import ProcessPoolExecutor

    import eventkit as ev

    if __name__ == "__main__":
        data = [b"A" * 1_000_000] * 1000
        with ProcessPoolExecutor() as pool:
            sizes = ev.Sequence(data).poolmap(pool, bz2.compress, chunksize=10).map(len)
            print(sizes.mean().last().run())


Inspired by:
------------

    * `Qt Signals & Slots <https://doc.qt.io/qt-5/signalsandslots.html>`_
    * `itertools <https://docs.python.org/3/library/itertools.html>`_
    * `aiostream <https://github.com/vxgmichel/aiostream>`_
    * `Bacon <https://baconjs.github.io/index.html>`_
    * `aioreactive <https://github.com/dbrattli/aioreactive>`_
    * `Reactive extensions <http://reactivex.io/documentation/operators.html>`_
    * `underscore.js <https://underscorejs.org>`_
    * `.NET Events <https://docs.microsoft.com/en-us/dotnet/standard/events>`_

Documentation
-------------

The complete `API documentation <https://eventkit.readthedocs.io/en/latest/api.html>`_.



.. _Python: http://www.python.org
.. _`Interactive Brokers Python API`: http://interactivebrokers.github.io

.. |Build| image:: https://github.com/ib-api-reloaded/eventkit/actions/workflows/build-n-test.yml/badge.svg
   :alt: Build
   :target: https://github.com/ib-api-reloaded/eventkit/actions

.. |PyPiVersion| image:: https://img.shields.io/pypi/v/aeventkit.svg
   :alt: PyPi
   :target: https://pypi.org/project/aeventkit/


.. |PyVersion| image:: https://img.shields.io/badge/python-3.11+-blue.svg
   :alt:

.. |Status| image:: https://img.shields.io/badge/status-stable-green.svg
   :alt:

.. |License| image:: https://img.shields.io/badge/license-BSD-blue.svg
   :alt:

.. |Docs| image:: https://readthedocs.org/projects/eventkit/badge/?version=latest
   :alt: Documentation
   :target: https://eventkit.readthedocs.io
