Name | eventsystem JSON |
Version |
1.0.0
JSON |
| download |
home_page | None |
Summary | Convenient Event System |
upload_time | 2022-12-06 17:00:40 |
maintainer | None |
docs_url | None |
author | None |
requires_python | None |
license | None |
keywords |
pymitter
event
system
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Convenient Event System
Create, subscribe and fire events with one line of code. Unlike alternative packages this one provides static typed predefined events with documented signature of event handlers.
**Both ordinary and async event handlers are supported.**
# Usage examples
Briefly, you need to perform two steps:
1. decide between two options: group events in class derived from `EventDispatcher` or just define functions,
2. then decorate each event with `@event`.
----
Let's see how to use the library in more details. Imagine we write some user interface stuff for our super-duper program.
### Single event example
**Step 1: define click event.**
```python
@event
def click(x: int, y: int)->None:
"""
Occures when user clicks on our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
... # no implementation required
```
**Step 2: subscribe click event.**
```python
@click
def on_click(x: int, y: int)->None:
"""
Process mouse click.
"""
print(f'You have clicked at ({x}; {y}).')
```
**Step 3: fire click event.**
```python
click.trigger(12, 34) # You have clicked at (12; 34).
```
### Events group example
**Step 1: define mouse events group.**
```python
class Mouse(EventDispatcher):
@event
def click(x: int, y: int)->None:
"""
Occures when user clicks on our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
... # no implementation required
@event
def move(x: int, y: int)->None:
"""
Occures when user moves cursor over our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
...
```
**Step 2: subscribe click event.**
```python
mouse = Mouse()
@mouse.click
def on_click(x: int, y: int)->None:
"""
Process mouse click.
"""
print(f'You have clicked at ({x}; {y}).')
```
**Step 3: fire click event.**
```python
mouse.click.trigger(12, 34) # You have clicked at (12; 34).
```
# How to create events?
Event are created by using `event` decorator. It can be used with or without parameters.
The event can have arbitrary body that is not actually called. Main feature is to defined event signature hence during subscribing **developer can see help message and type hints with intended event handler signature**.
### Single event bound to default event emitter
The simplest case is to just create an event. So default event emitter is used to manage this event.
```python
@event
def click(x: int, y: int)->None:
"""
Occures when user clicks on our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
...
```
### Single event bound to custom event emitter
Otherwise, you can specify different event emitter passing as argument.
```python
my_event_emitter = EventEmitter()
@event(my_event_emitter)
def click(x: int, y: int)->None:
"""
Occures when user clicks on our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
...
```
### Events group bound to dedicated event emitter
Moreover, you can combine events in group by using classes. There are two different approaches: using default event emitter or dedicate one per each class.
**Creating dedicated event emitter per each event group is recommended.**
Considering the preferred approach you can group event in class derived from `EventDispatcher`. This ensures creation of new event emitter per each class instance.
**Notice that using `event` decorator stays the same way as for non-class functions.**
```python
class Mouse(EventDispatcher):
@event
def click(x: int, y: int)->None:
"""
Occures when user clicks on our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
... # no implementation required
@event(my_event_emitter) # given event emitter is prior to Mouse one
def move(x: int, y: int)->None:
"""
Occures when user moves cursor over our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
...
```
Then you can instantiate `Mouse` class and access dedicated event emitter for e.g. further low-level tuning.
```python
mouse = Mouse()
mouse.emitter.max_listeners = 2 # allows up to two handlers
```
When using `event` decorator on `EventDispatcher` subclass method with specified event emitter it takes priority over the one dedicated per class instance.
### Events group bound to default event emitter
In case you do not want to create dedicated event emitter per class instance (*not recommended*) you can just omit deriving from `EventDispatcher`.
In following code default event emitter is used for all events in group.
```python
class Mouse:
@event
def click(x: int, y: int)->None:
"""
Occures when user clicks on our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
... # no implementation required
@event(my_event_emitter) # given event emitter is prior to default one
def move(x: int, y: int)->None:
"""
Occures when user moves cursor over our interface.
:param x: mouse horizontal position relative to top left corner.
:param y: mouse vertical position relative to top left corner.
"""
...
```
# How to subscribe events?
Event is subscribed by decorating handler. **Handler can be any ordinary or async function (callable).** Decorator also can be used with or without parameters.
**Notice, when using event your IDE can show help message and type hints of intended handler signature.**
### Unlimited event handler
The simplest case is to just decorate handler with event. So handler will be called when event triggers.
```python
@click
def on_click(x: int, y: int)->None:
"""
Process mouse click.
"""
print(f'You have clicked at ({x}; {y}).')
```
**There is no difference between usage of single events or ones from event groups.** Hence, according to `Mouse` class example the above code can be rewritten in:
```python
@mouse.click
def on_click(x: int, y: int)->None:
"""
Process mouse click.
"""
print(f'You have clicked at ({x}; {y}).')
```
### Event handler with executions limit
Otherwise, you can specify number of times to handle event. When event fires more times, no further calls will be made to the handler.
```python
@click(2)
def on_click(x: int, y: int)->None:
"""
Process mouse click two first times.
"""
print(f'You have clicked at ({x}; {y}).')
```
In above case `on_click` will be called only for the first two times.
# How to fire events?
To fire, emit, trigger event you can use `.trigger(...)` method where should pass exactly the same arguments that are defined in event signature.
**Notice, when using event your IDE can show help message and type hints of intended arguments.**
Basically, to trigger an event you can just call `trigger` method. Each active handler will be called with given arguments. You can use any set of arguments, including positional, universal, named, packed and even named packed.
```python
click.trigger(12, 34)
```
Alternatively considering `Mouse` class example:
```python
mouse.click.trigger(12, 34)
```
# Reference
**eventsystem.event(...)**
Event descriptor decorator. Can be used on functions or class methods. Can be used with or without parameters.
When used with single parameter `emitter:EventEmitter` binds given event emitter to decorated event.
When used without parameters (brackets): if method belongs to `EventDispatcher` derived class instance then uses its event emitter, else uses default emitter.
**eventsystem.EventDispatcher(emitter: EventEmitter | None = None)**
Base class to provide event group. Events are described as methods. Each event should have signature of `EventHandler` and decorated with `@event`.
Constructor parameters:
* **emitter** - event emitter to use. If not given creates a new one.
Fields:
* **emitter** - event emitter bound to dispatcher subclass instance.
**eventsystem.Event**
Event interface. Intended to be used as decorator or parametrized decorator for handlers. *Should not be instantiated directly.*
Fields:
* **name** - read only property of event name
Methods:
* **get_emitter() → EventEmitter | None** - get bound event emitter. In most cases, event will have event emitter bound. But in rare cases it can be `None` when no handler descriptor has been decorated yet.
* **trigger(...) → None** - fire the event. All arguments are passed to each handler. Signature must match handler descriptor.
**eventsystem.emitter**
Default event emitter.
**eventsystem.dispatcher**
Default event dispatcher bound to default event emitter.
**eventsystem.EventHandler**
Base event and event handler signature (type annotations). Signature of handler must copy signature of event.
# What event emitter is?
This library us build on top of [pymitter](https://pypi.org/project/pymitter). `EventEmitter` - is a basic building block of that library which actually dispatches events, manages priority, limitations and queues.
Using `EventEmitter` directly you can unsubscribe handlers, get all active handlers or limit them. For detailed tuning read pymitter documentation.
Raw data
{
"_id": null,
"home_page": null,
"name": "eventsystem",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "pymitter,event,system",
"author": null,
"author_email": "baterflyrity <baterflyrity@yandex.ru>",
"download_url": "https://files.pythonhosted.org/packages/14/8c/ec87ae2be6fac24a8207eff88a61bbab4eb2b178c79d0408c6cea4d0b050/eventsystem-1.0.0.tar.gz",
"platform": null,
"description": "# Convenient Event System\n\nCreate, subscribe and fire events with one line of code. Unlike alternative packages this one provides static typed predefined events with documented signature of event handlers.\n\n**Both ordinary and async event handlers are supported.**\n\n# Usage examples\n\nBriefly, you need to perform two steps:\n\n1. decide between two options: group events in class derived from `EventDispatcher` or just define functions,\n2. then decorate each event with `@event`.\n\n----\n\nLet's see how to use the library in more details. Imagine we write some user interface stuff for our super-duper program.\n\n### Single event example\n\n**Step 1: define click event.**\n\n```python\n@event\ndef click(x: int, y: int)->None:\n\t\"\"\"\n\tOccures when user clicks on our interface.\n\t\n\t:param x: mouse horizontal position relative to top left corner.\n\t:param y: mouse vertical position relative to top left corner.\n\t\"\"\"\n\t... # no implementation required\n```\n\n**Step 2: subscribe click event.**\n\n```python\n@click\ndef on_click(x: int, y: int)->None:\n\t\"\"\"\n\tProcess mouse click.\n\t\"\"\"\n\tprint(f'You have clicked at ({x}; {y}).')\n```\n\n**Step 3: fire click event.**\n\n```python\nclick.trigger(12, 34) # You have clicked at (12; 34).\n```\n\n### Events group example\n\n**Step 1: define mouse events group.**\n\n```python\nclass Mouse(EventDispatcher):\n\t@event\n\tdef click(x: int, y: int)->None:\n\t\t\"\"\"\n\t\tOccures when user clicks on our interface.\n\t\t\n\t\t:param x: mouse horizontal position relative to top left corner.\n\t\t:param y: mouse vertical position relative to top left corner.\n\t\t\"\"\"\n\t\t... # no implementation required\n\t@event\n\tdef move(x: int, y: int)->None:\n\t\t\"\"\"\n\t\tOccures when user moves cursor over our interface.\n\t\t\n\t\t:param x: mouse horizontal position relative to top left corner.\n\t\t:param y: mouse vertical position relative to top left corner.\n\t\t\"\"\"\n\t\t...\n```\n\n**Step 2: subscribe click event.**\n\n```python\nmouse = Mouse()\n\n@mouse.click\ndef on_click(x: int, y: int)->None:\n\t\"\"\"\n\tProcess mouse click.\n\t\"\"\"\n\tprint(f'You have clicked at ({x}; {y}).')\n```\n\n**Step 3: fire click event.**\n\n```python\nmouse.click.trigger(12, 34) # You have clicked at (12; 34).\n```\n\n# How to create events?\n\nEvent are created by using `event` decorator. It can be used with or without parameters.\n\nThe event can have arbitrary body that is not actually called. Main feature is to defined event signature hence during subscribing **developer can see help message and type hints with intended event handler signature**.\n\n### Single event bound to default event emitter\n\nThe simplest case is to just create an event. So default event emitter is used to manage this event.\n\n```python\n@event\ndef click(x: int, y: int)->None:\n\t\"\"\"\n\tOccures when user clicks on our interface.\n\t\n\t:param x: mouse horizontal position relative to top left corner.\n\t:param y: mouse vertical position relative to top left corner.\n\t\"\"\"\n\t...\n```\n\n### Single event bound to custom event emitter\n\nOtherwise, you can specify different event emitter passing as argument.\n\n```python\nmy_event_emitter = EventEmitter()\n\n@event(my_event_emitter)\ndef click(x: int, y: int)->None:\n\t\"\"\"\n\tOccures when user clicks on our interface.\n\t\n\t:param x: mouse horizontal position relative to top left corner.\n\t:param y: mouse vertical position relative to top left corner.\n\t\"\"\"\n\t...\n```\n\n### Events group bound to dedicated event emitter\n\nMoreover, you can combine events in group by using classes. There are two different approaches: using default event emitter or dedicate one per each class.\n\n**Creating dedicated event emitter per each event group is recommended.**\n\nConsidering the preferred approach you can group event in class derived from `EventDispatcher`. This ensures creation of new event emitter per each class instance.\n\n**Notice that using `event` decorator stays the same way as for non-class functions.**\n\n```python\nclass Mouse(EventDispatcher):\n\t@event\n\tdef click(x: int, y: int)->None:\n\t\t\"\"\"\n\t\tOccures when user clicks on our interface.\n\t\t\n\t\t:param x: mouse horizontal position relative to top left corner.\n\t\t:param y: mouse vertical position relative to top left corner.\n\t\t\"\"\"\n\t\t... # no implementation required\n\t@event(my_event_emitter) # given event emitter is prior to Mouse one \n\tdef move(x: int, y: int)->None:\n\t\t\"\"\"\n\t\tOccures when user moves cursor over our interface.\n\t\t\n\t\t:param x: mouse horizontal position relative to top left corner.\n\t\t:param y: mouse vertical position relative to top left corner.\n\t\t\"\"\"\n\t\t...\n```\n\nThen you can instantiate `Mouse` class and access dedicated event emitter for e.g. further low-level tuning.\n\n```python\nmouse = Mouse()\n\nmouse.emitter.max_listeners = 2 # allows up to two handlers\n```\n\nWhen using `event` decorator on `EventDispatcher` subclass method with specified event emitter it takes priority over the one dedicated per class instance.\n\n### Events group bound to default event emitter\n\nIn case you do not want to create dedicated event emitter per class instance (*not recommended*) you can just omit deriving from `EventDispatcher`.\n\nIn following code default event emitter is used for all events in group.\n\n```python\nclass Mouse:\n\t@event\n\tdef click(x: int, y: int)->None:\n\t\t\"\"\"\n\t\tOccures when user clicks on our interface.\n\t\t\n\t\t:param x: mouse horizontal position relative to top left corner.\n\t\t:param y: mouse vertical position relative to top left corner.\n\t\t\"\"\"\n\t\t... # no implementation required\n\t@event(my_event_emitter) # given event emitter is prior to default one \n\tdef move(x: int, y: int)->None:\n\t\t\"\"\"\n\t\tOccures when user moves cursor over our interface.\n\t\t\n\t\t:param x: mouse horizontal position relative to top left corner.\n\t\t:param y: mouse vertical position relative to top left corner.\n\t\t\"\"\"\n\t\t...\n```\n\n# How to subscribe events?\n\nEvent is subscribed by decorating handler. **Handler can be any ordinary or async function (callable).** Decorator also can be used with or without parameters.\n\n**Notice, when using event your IDE can show help message and type hints of intended handler signature.**\n\n### Unlimited event handler\n\nThe simplest case is to just decorate handler with event. So handler will be called when event triggers.\n\n```python\n@click\ndef on_click(x: int, y: int)->None:\n\t\"\"\"\n\tProcess mouse click.\n\t\"\"\"\n\tprint(f'You have clicked at ({x}; {y}).')\n```\n\n**There is no difference between usage of single events or ones from event groups.** Hence, according to `Mouse` class example the above code can be rewritten in:\n\n```python\n@mouse.click\ndef on_click(x: int, y: int)->None:\n\t\"\"\"\n\tProcess mouse click.\n\t\"\"\"\n\tprint(f'You have clicked at ({x}; {y}).')\n```\n\n### Event handler with executions limit\n\nOtherwise, you can specify number of times to handle event. When event fires more times, no further calls will be made to the handler.\n\n```python\n@click(2)\ndef on_click(x: int, y: int)->None:\n\t\"\"\"\n\tProcess mouse click two first times.\n\t\"\"\"\n\tprint(f'You have clicked at ({x}; {y}).')\n```\n\nIn above case `on_click` will be called only for the first two times.\n\n# How to fire events?\n\nTo fire, emit, trigger event you can use `.trigger(...)` method where should pass exactly the same arguments that are defined in event signature.\n\n**Notice, when using event your IDE can show help message and type hints of intended arguments.**\n\nBasically, to trigger an event you can just call `trigger` method. Each active handler will be called with given arguments. You can use any set of arguments, including positional, universal, named, packed and even named packed.\n\n```python\nclick.trigger(12, 34)\n```\n\nAlternatively considering `Mouse` class example:\n\n```python\nmouse.click.trigger(12, 34)\n```\n\n# Reference\n\n**eventsystem.event(...)**\n\nEvent descriptor decorator. Can be used on functions or class methods. Can be used with or without parameters.\n\nWhen used with single parameter `emitter:EventEmitter` binds given event emitter to decorated event.\n\nWhen used without parameters (brackets): if method belongs to `EventDispatcher` derived class instance then uses its event emitter, else uses default emitter.\n\n**eventsystem.EventDispatcher(emitter: EventEmitter | None = None)**\n\nBase class to provide event group. Events are described as methods. Each event should have signature of `EventHandler` and decorated with `@event`.\n\nConstructor parameters:\n\n* **emitter** - event emitter to use. If not given creates a new one.\n\nFields:\n\n* **emitter** - event emitter bound to dispatcher subclass instance.\n\n**eventsystem.Event**\n\nEvent interface. Intended to be used as decorator or parametrized decorator for handlers. *Should not be instantiated directly.*\n\nFields:\n\n* **name** - read only property of event name\n\nMethods:\n\n* **get_emitter() \u2192 EventEmitter | None** - get bound event emitter. In most cases, event will have event emitter bound. But in rare cases it can be `None` when no handler descriptor has been decorated yet.\n\n* **trigger(...) \u2192 None** - fire the event. All arguments are passed to each handler. Signature must match handler descriptor.\n\n**eventsystem.emitter**\n\nDefault event emitter.\n\n**eventsystem.dispatcher**\n\nDefault event dispatcher bound to default event emitter.\n\n**eventsystem.EventHandler**\n\nBase event and event handler signature (type annotations). Signature of handler must copy signature of event.\n\n# What event emitter is?\n\nThis library us build on top of [pymitter](https://pypi.org/project/pymitter). `EventEmitter` - is a basic building block of that library which actually dispatches events, manages priority, limitations and queues.\n\nUsing `EventEmitter` directly you can unsubscribe handlers, get all active handlers or limit them. For detailed tuning read pymitter documentation.\n",
"bugtrack_url": null,
"license": null,
"summary": "Convenient Event System",
"version": "1.0.0",
"split_keywords": [
"pymitter",
"event",
"system"
],
"urls": [
{
"comment_text": null,
"digests": {
"md5": "c18da2c260465aa6a5e299d477ea6689",
"sha256": "e8fe46137afffa8db4a65fa8890862795b2491fda7bd16d470775b9be2ca24a0"
},
"downloads": -1,
"filename": "eventsystem-1.0.0-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "c18da2c260465aa6a5e299d477ea6689",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 5634,
"upload_time": "2022-12-06T17:00:32",
"upload_time_iso_8601": "2022-12-06T17:00:32.856426Z",
"url": "https://files.pythonhosted.org/packages/ec/89/23ff35324a14b49f237c36db438c2ab40a0946dc3d4918912c19f0f5166a/eventsystem-1.0.0-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"md5": "f2c908159a8bb75e63df7729e935e56b",
"sha256": "3e8214a67641afbfff6b1892d784bd3f74b3f5d8e625b994c879b71329dbaa6a"
},
"downloads": -1,
"filename": "eventsystem-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "f2c908159a8bb75e63df7729e935e56b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 5493,
"upload_time": "2022-12-06T17:00:40",
"upload_time_iso_8601": "2022-12-06T17:00:40.403701Z",
"url": "https://files.pythonhosted.org/packages/14/8c/ec87ae2be6fac24a8207eff88a61bbab4eb2b178c79d0408c6cea4d0b050/eventsystem-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2022-12-06 17:00:40",
"github": false,
"gitlab": false,
"bitbucket": false,
"lcname": "eventsystem"
}