pymitter


Namepymitter JSON
Version 0.5.0 PyPI version JSON
download
home_page
SummaryPython port of the extended Node.js EventEmitter 2 approach providing namespaces, wildcards and TTL.
upload_time2023-11-22 14:31:03
maintainer
docs_urlNone
author
requires_python>=3.7
licenseCopyright (c) 2014-2023, Marcel Rieger All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
keywords event emitter eventemitter wildcard node nodejs
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <!-- marker-before-logo -->

<p align="center">
  <img src="https://media.githubusercontent.com/media/riga/pymitter/master/assets/logo.png" width="400" />
</p>

<!-- marker-after-logo -->

<!-- marker-before-badges -->

<p align="center">
  <a href="http://pymitter.readthedocs.io">
    <img alt="Documentation status" src="https://readthedocs.org/projects/pymitter/badge/?version=latest" />
  </a>
  <img alt="Python version" src="https://img.shields.io/badge/Python-%E2%89%A53.7-blue" />
  <a href="https://pypi.python.org/pypi/pymitter">
    <img alt="Package version" src="https://img.shields.io/pypi/v/pymitter.svg?style=flat" />
  </a>
  <a href="https://pypi.python.org/pypi/pymitter">
    <img alt="Package downloads" src="https://img.shields.io/pypi/dm/pymitter.svg" />
  </a>
  <a href="https://codecov.io/gh/riga/pymitter">
    <img alt="Code coverge" src="https://codecov.io/gh/riga/pymitter/branch/master/graph/badge.svg?token=MePbStZF7U" />
  </a>
  <a href="https://github.com/riga/pymitter/actions/workflows/lint_and_test.yml">
    <img alt="Build status" src="https://github.com/riga/pymitter/actions/workflows/lint_and_test.yml/badge.svg" />
  </a>
  <a href="https://github.com/riga/pymitter/blob/master/LICENSE">
    <img alt="License" src="https://img.shields.io/github/license/riga/pymitter.svg" />
  </a>
</p>

<!-- marker-after-badges -->

<!-- marker-before-header -->

Python port of the extended Node.js EventEmitter 2 approach of https://github.com/asyncly/EventEmitter2 providing namespaces, wildcards and TTL.

Original source hosted at [GitHub](https://github.com/riga/pymitter).

<!-- marker-after-header -->

<!-- marker-before-body -->

## Features

- Namespaces with wildcards
- Times to listen (TTL)
- Usage via decorators or callbacks
- Coroutine support
- Lightweight implementation, good performance


## Installation

Simply install via [pip](https://pypi.python.org/pypi/pymitter):

```shell
pip install pymitter
```

The last version with Python 2 support was [v0.3.2](https://github.com/riga/pymitter/tree/v0.3.2) ([PyPI](https://pypi.org/project/pymitter/0.3.2)).


## Examples

### Basic usage

```python
from pymitter import EventEmitter


ee = EventEmitter()


# decorator usage
@ee.on("my_event")
def handler1(arg):
    print("handler1 called with", arg)


# callback usage
def handler2(arg):
    print("handler2 called with", arg)


ee.on("my_other_event", handler2)


# support for coroutine functions
@ee.on("my_third_event")
async def handler3(arg):
    print("handler3 called with", arg)


# emit
ee.emit("my_event", "foo")
# -> "handler1 called with foo"

ee.emit("my_other_event", "bar")
# -> "handler2 called with bar"

ee.emit("my_third_event", "baz")
# -> "handler3 called with baz"
```


### Coroutines

Wrapping `async` functions outside an event loop will start an internal event loop and calls to `emit` return synchronously.

```python
from pymitter import EventEmitter


ee = EventEmitter()


# register an async function
@ee.on("my_event")
async def handler1(arg):
    print("handler1 called with", arg)


# emit
ee.emit("my_event", "foo")
# -> "handler1 called with foo"
```

Wrapping `async` functions inside an event loop will use the same loop and `emit_async` is awaitable.

```python
from pymitter import EventEmitter


ee = EventEmitter()


async def main():
    # emit_async
    awaitable = ee.emit_async("my_event", "foo")
    # -> nothing printed yet

    await awaitable
    # -> "handler1 called with foo"
```

Use `emit_future` to not return awaitable objects but to place them at the end of the existing event loop (using `asyncio.ensure_future` internally).


### TTL (times to listen)

```python
from pymitter import EventEmitter


ee = EventEmitter()


@ee.once("my_event")
def handler1():
    print("handler1 called")


@ee.on("my_event", ttl=2)
def handler2():
    print("handler2 called")


ee.emit("my_event")
# -> "handler1 called"
# -> "handler2 called"

ee.emit("my_event")
# -> "handler2 called"

ee.emit("my_event")
# nothing called anymore
```


### Wildcards

```python
from pymitter import EventEmitter


ee = EventEmitter(wildcard=True)


@ee.on("my_event.foo")
def handler1():
    print("handler1 called")


@ee.on("my_event.bar")
def handler2():
    print("handler2 called")


@ee.on("my_event.*")
def hander3():
    print("handler3 called")


ee.emit("my_event.foo")
# -> "handler1 called"
# -> "handler3 called"

ee.emit("my_event.bar")
# -> "handler2 called"
# -> "handler3 called"

ee.emit("my_event.*")
# -> "handler1 called"
# -> "handler2 called"
# -> "handler3 called"
```


## API

### `EventEmitter(*, wildcard=False, delimiter=".", new_listener=False, max_listeners=-1)`

EventEmitter constructor. **Note**: always use *kwargs* for configuration.
When *wildcard* is *True*, wildcards are used as shown in [this example](#wildcards).
*delimiter* is used to seperate namespaces within events.
If *new_listener* is *True*, the *"new_listener"* event is emitted every time a new listener is registered.
Functions listening to this event are passed `(func, event=None)`.
*max_listeners* defines the maximum number of listeners per event.
Negative values mean infinity.

- #### `on(event, func=None, ttl=-1)`
    Registers a function to an event.
    When *func* is *None*, decorator usage is assumed.
    *ttl* defines the times to listen. Negative values mean infinity.
    Returns the function.

- #### `once(event, func=None)`
    Registers a function to an event with `ttl = 1`.
    When *func* is *None*, decorator usage is assumed.
    Returns the function.

- #### `on_any(func=None)`
    Registers a function that is called every time an event is emitted.
    When *func* is *None*, decorator usage is assumed.
    Returns the function.

- #### `off(event, func=None)`
    Removes a function that is registered to an event.
    When *func* is *None*, decorator usage is assumed.
    Returns the function.

- #### `off_any(func=None)`
    Removes a function that was registered via `on_any()`.
    When *func* is *None*, decorator usage is assumed.
    Returns the function.

- #### `off_all()`
    Removes all functions of all events.

- #### `listeners(event)`
    Returns all functions that are registered to an event.
    Wildcards are not applied.

- #### `listeners_any()`
    Returns all functions that were registered using `on_any()`.

- #### `listeners_all()`
    Returns all registered functions.

- #### `emit(event, *args, **kwargs)`
    Emits an event.
    All functions of events that match *event* are invoked with *args* and *kwargs* in the exact order of their registeration.
    Async functions are called in a new event loop.
    There is no return value.

- #### `(async) emit_async(event, *args, **kwargs)`
    Emits an event.
    All functions of events that match *event* are invoked with *args* and *kwargs* in the exact order of their registeration.
    Awaitable objects returned by async functions are awaited in the outer event loop.
    Returns an `Awaitable`.

- #### `emit_future(event, *args, **kwargs)`
    Emits an event.
    All functions of events that match *event* are invoked with *args* and *kwargs* in the exact order of their registeration.
    Awaitable objects returned by async functions are placed at the end of the event loop using `asyncio.ensure_future`.
    There is no return value.


## Development

- Source hosted at [GitHub](https://github.com/riga/pymitter)
- Python module hosted at [PyPI](https://pypi.python.org/pypi/pymitter)
- Report issues, questions, feature requests on [GitHub Issues](https://github.com/riga/pymitter/issues)

<!-- marker-after-body -->

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "pymitter",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "event,emitter,eventemitter,wildcard,node,nodejs",
    "author": "",
    "author_email": "Marcel Rieger <github.riga@icloud.com>",
    "download_url": "https://files.pythonhosted.org/packages/21/64/b8a681e0a73dd493595112157e37d7014ad1b0f4ce67c1405892be51cd69/pymitter-0.5.0.tar.gz",
    "platform": null,
    "description": "<!-- marker-before-logo -->\n\n<p align=\"center\">\n  <img src=\"https://media.githubusercontent.com/media/riga/pymitter/master/assets/logo.png\" width=\"400\" />\n</p>\n\n<!-- marker-after-logo -->\n\n<!-- marker-before-badges -->\n\n<p align=\"center\">\n  <a href=\"http://pymitter.readthedocs.io\">\n    <img alt=\"Documentation status\" src=\"https://readthedocs.org/projects/pymitter/badge/?version=latest\" />\n  </a>\n  <img alt=\"Python version\" src=\"https://img.shields.io/badge/Python-%E2%89%A53.7-blue\" />\n  <a href=\"https://pypi.python.org/pypi/pymitter\">\n    <img alt=\"Package version\" src=\"https://img.shields.io/pypi/v/pymitter.svg?style=flat\" />\n  </a>\n  <a href=\"https://pypi.python.org/pypi/pymitter\">\n    <img alt=\"Package downloads\" src=\"https://img.shields.io/pypi/dm/pymitter.svg\" />\n  </a>\n  <a href=\"https://codecov.io/gh/riga/pymitter\">\n    <img alt=\"Code coverge\" src=\"https://codecov.io/gh/riga/pymitter/branch/master/graph/badge.svg?token=MePbStZF7U\" />\n  </a>\n  <a href=\"https://github.com/riga/pymitter/actions/workflows/lint_and_test.yml\">\n    <img alt=\"Build status\" src=\"https://github.com/riga/pymitter/actions/workflows/lint_and_test.yml/badge.svg\" />\n  </a>\n  <a href=\"https://github.com/riga/pymitter/blob/master/LICENSE\">\n    <img alt=\"License\" src=\"https://img.shields.io/github/license/riga/pymitter.svg\" />\n  </a>\n</p>\n\n<!-- marker-after-badges -->\n\n<!-- marker-before-header -->\n\nPython port of the extended Node.js EventEmitter 2 approach of https://github.com/asyncly/EventEmitter2 providing namespaces, wildcards and TTL.\n\nOriginal source hosted at [GitHub](https://github.com/riga/pymitter).\n\n<!-- marker-after-header -->\n\n<!-- marker-before-body -->\n\n## Features\n\n- Namespaces with wildcards\n- Times to listen (TTL)\n- Usage via decorators or callbacks\n- Coroutine support\n- Lightweight implementation, good performance\n\n\n## Installation\n\nSimply install via [pip](https://pypi.python.org/pypi/pymitter):\n\n```shell\npip install pymitter\n```\n\nThe last version with Python 2 support was [v0.3.2](https://github.com/riga/pymitter/tree/v0.3.2) ([PyPI](https://pypi.org/project/pymitter/0.3.2)).\n\n\n## Examples\n\n### Basic usage\n\n```python\nfrom pymitter import EventEmitter\n\n\nee = EventEmitter()\n\n\n# decorator usage\n@ee.on(\"my_event\")\ndef handler1(arg):\n    print(\"handler1 called with\", arg)\n\n\n# callback usage\ndef handler2(arg):\n    print(\"handler2 called with\", arg)\n\n\nee.on(\"my_other_event\", handler2)\n\n\n# support for coroutine functions\n@ee.on(\"my_third_event\")\nasync def handler3(arg):\n    print(\"handler3 called with\", arg)\n\n\n# emit\nee.emit(\"my_event\", \"foo\")\n# -> \"handler1 called with foo\"\n\nee.emit(\"my_other_event\", \"bar\")\n# -> \"handler2 called with bar\"\n\nee.emit(\"my_third_event\", \"baz\")\n# -> \"handler3 called with baz\"\n```\n\n\n### Coroutines\n\nWrapping `async` functions outside an event loop will start an internal event loop and calls to `emit` return synchronously.\n\n```python\nfrom pymitter import EventEmitter\n\n\nee = EventEmitter()\n\n\n# register an async function\n@ee.on(\"my_event\")\nasync def handler1(arg):\n    print(\"handler1 called with\", arg)\n\n\n# emit\nee.emit(\"my_event\", \"foo\")\n# -> \"handler1 called with foo\"\n```\n\nWrapping `async` functions inside an event loop will use the same loop and `emit_async` is awaitable.\n\n```python\nfrom pymitter import EventEmitter\n\n\nee = EventEmitter()\n\n\nasync def main():\n    # emit_async\n    awaitable = ee.emit_async(\"my_event\", \"foo\")\n    # -> nothing printed yet\n\n    await awaitable\n    # -> \"handler1 called with foo\"\n```\n\nUse `emit_future` to not return awaitable objects but to place them at the end of the existing event loop (using `asyncio.ensure_future` internally).\n\n\n### TTL (times to listen)\n\n```python\nfrom pymitter import EventEmitter\n\n\nee = EventEmitter()\n\n\n@ee.once(\"my_event\")\ndef handler1():\n    print(\"handler1 called\")\n\n\n@ee.on(\"my_event\", ttl=2)\ndef handler2():\n    print(\"handler2 called\")\n\n\nee.emit(\"my_event\")\n# -> \"handler1 called\"\n# -> \"handler2 called\"\n\nee.emit(\"my_event\")\n# -> \"handler2 called\"\n\nee.emit(\"my_event\")\n# nothing called anymore\n```\n\n\n### Wildcards\n\n```python\nfrom pymitter import EventEmitter\n\n\nee = EventEmitter(wildcard=True)\n\n\n@ee.on(\"my_event.foo\")\ndef handler1():\n    print(\"handler1 called\")\n\n\n@ee.on(\"my_event.bar\")\ndef handler2():\n    print(\"handler2 called\")\n\n\n@ee.on(\"my_event.*\")\ndef hander3():\n    print(\"handler3 called\")\n\n\nee.emit(\"my_event.foo\")\n# -> \"handler1 called\"\n# -> \"handler3 called\"\n\nee.emit(\"my_event.bar\")\n# -> \"handler2 called\"\n# -> \"handler3 called\"\n\nee.emit(\"my_event.*\")\n# -> \"handler1 called\"\n# -> \"handler2 called\"\n# -> \"handler3 called\"\n```\n\n\n## API\n\n### `EventEmitter(*, wildcard=False, delimiter=\".\", new_listener=False, max_listeners=-1)`\n\nEventEmitter constructor. **Note**: always use *kwargs* for configuration.\nWhen *wildcard* is *True*, wildcards are used as shown in [this example](#wildcards).\n*delimiter* is used to seperate namespaces within events.\nIf *new_listener* is *True*, the *\"new_listener\"* event is emitted every time a new listener is registered.\nFunctions listening to this event are passed `(func, event=None)`.\n*max_listeners* defines the maximum number of listeners per event.\nNegative values mean infinity.\n\n- #### `on(event, func=None, ttl=-1)`\n    Registers a function to an event.\n    When *func* is *None*, decorator usage is assumed.\n    *ttl* defines the times to listen. Negative values mean infinity.\n    Returns the function.\n\n- #### `once(event, func=None)`\n    Registers a function to an event with `ttl = 1`.\n    When *func* is *None*, decorator usage is assumed.\n    Returns the function.\n\n- #### `on_any(func=None)`\n    Registers a function that is called every time an event is emitted.\n    When *func* is *None*, decorator usage is assumed.\n    Returns the function.\n\n- #### `off(event, func=None)`\n    Removes a function that is registered to an event.\n    When *func* is *None*, decorator usage is assumed.\n    Returns the function.\n\n- #### `off_any(func=None)`\n    Removes a function that was registered via `on_any()`.\n    When *func* is *None*, decorator usage is assumed.\n    Returns the function.\n\n- #### `off_all()`\n    Removes all functions of all events.\n\n- #### `listeners(event)`\n    Returns all functions that are registered to an event.\n    Wildcards are not applied.\n\n- #### `listeners_any()`\n    Returns all functions that were registered using `on_any()`.\n\n- #### `listeners_all()`\n    Returns all registered functions.\n\n- #### `emit(event, *args, **kwargs)`\n    Emits an event.\n    All functions of events that match *event* are invoked with *args* and *kwargs* in the exact order of their registeration.\n    Async functions are called in a new event loop.\n    There is no return value.\n\n- #### `(async) emit_async(event, *args, **kwargs)`\n    Emits an event.\n    All functions of events that match *event* are invoked with *args* and *kwargs* in the exact order of their registeration.\n    Awaitable objects returned by async functions are awaited in the outer event loop.\n    Returns an `Awaitable`.\n\n- #### `emit_future(event, *args, **kwargs)`\n    Emits an event.\n    All functions of events that match *event* are invoked with *args* and *kwargs* in the exact order of their registeration.\n    Awaitable objects returned by async functions are placed at the end of the event loop using `asyncio.ensure_future`.\n    There is no return value.\n\n\n## Development\n\n- Source hosted at [GitHub](https://github.com/riga/pymitter)\n- Python module hosted at [PyPI](https://pypi.python.org/pypi/pymitter)\n- Report issues, questions, feature requests on [GitHub Issues](https://github.com/riga/pymitter/issues)\n\n<!-- marker-after-body -->\n",
    "bugtrack_url": null,
    "license": "Copyright (c) 2014-2023, Marcel Rieger All rights reserved.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:  * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.  * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ",
    "summary": "Python port of the extended Node.js EventEmitter 2 approach providing namespaces, wildcards and TTL.",
    "version": "0.5.0",
    "project_urls": {
        "Documentation": "https://pymitter.readthedocs.io",
        "Homepage": "https://github.com/riga/pymitter",
        "Repository": "https://github.com/riga/pymitter.git"
    },
    "split_keywords": [
        "event",
        "emitter",
        "eventemitter",
        "wildcard",
        "node",
        "nodejs"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a5a5a47582075e51663cfe9f7e14845b12c5f8a573207d139091dd5f5089d597",
                "md5": "8fae040439d300ddf323116565c634cd",
                "sha256": "ac5d9721ed2572924f1d3dae5ee5d8dafac5465dc1e3ecb38542d10592110aca"
            },
            "downloads": -1,
            "filename": "pymitter-0.5.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8fae040439d300ddf323116565c634cd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 9048,
            "upload_time": "2023-11-22T14:31:01",
            "upload_time_iso_8601": "2023-11-22T14:31:01.981430Z",
            "url": "https://files.pythonhosted.org/packages/a5/a5/a47582075e51663cfe9f7e14845b12c5f8a573207d139091dd5f5089d597/pymitter-0.5.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2164b8a681e0a73dd493595112157e37d7014ad1b0f4ce67c1405892be51cd69",
                "md5": "b7096651d8fde6d5feb07ab73da5afb4",
                "sha256": "a500747ff30b57f9a38e867936b3e8842330e7f8e3438b0566a09c908588db40"
            },
            "downloads": -1,
            "filename": "pymitter-0.5.0.tar.gz",
            "has_sig": false,
            "md5_digest": "b7096651d8fde6d5feb07ab73da5afb4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 9709,
            "upload_time": "2023-11-22T14:31:03",
            "upload_time_iso_8601": "2023-11-22T14:31:03.242211Z",
            "url": "https://files.pythonhosted.org/packages/21/64/b8a681e0a73dd493595112157e37d7014ad1b0f4ce67c1405892be51cd69/pymitter-0.5.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-22 14:31:03",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "riga",
    "github_project": "pymitter",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "pymitter"
}
        
Elapsed time: 0.20323s