Strongly-typed event decorator
Project description
typed-event
Strongly-typed events for Python via an @event decorator.
typed-event lets you define an event from a function/method prototype, then
subscribe listeners with += and unsubscribe with -=.
Installation
pip install typed-event
Quick start
Module-level event
from typed_event import event
@event
def counter_changed(new_value: int, /):
"""Fired whenever the counter changes."""
def print_value(new_value: int):
print("new value:", new_value)
counter_changed += print_value
counter_changed(42)
counter_changed -= print_value
Note that by default, @event requires you to make it explicit whether values
are passed positionally or as keyword.
Class events
from typed_event import event
class Counter:
def __init__(self):
self._value = 0
@event
def changed(value: int, /):
"""Fired when value changes."""
def set_value(self, value: int):
self._value = value
self.changed(value) # fire the event
c1 = Counter()
c2 = Counter()
def on_c1(value: int):
print("c1:", value)
def on_c2(value: int):
print("c2:", value)
c1.changed += on_c1
c2.changed += on_c2
c1.set_value(1) # prints "c1: 1"
c2.set_value(2) # prints "c2: 2"
Each instance gets its own bound event with its own listener list.
Defining event prototypes
Prototype restrictions:
- No default argument values.
- No
*args/**kwargsin the event prototype. - Strict mode (enabled by default) requires parameters to be explicitly positional-only (
/) or keyword-only (*). Opt-out by using@event(strict=False).
Example with explicit keyword-only parameters:
from typed_event import event
@event
def changed(*, a: int, b: int):
pass
changed(a=1, b=2) # ok
# changed(1, 2) # TypeError
Notes:
- Listener signatures are not validated at subscription time; a mismatch only fails when invoked.
- Type annotations are not runtime-enforced — the name refers to static typing support, not runtime checks.
Cancellation
Raise CancelEvent in a listener to stop processing remaining listeners:
from typed_event import event, CancelEvent
@event
def changed(value: int, /):
pass
def first(value: int):
raise CancelEvent()
def second(value: int):
print("never called")
changed += first
changed += second
changed(1)
Exception handling policy
Set via @event(exceptions=...):
"default"(default): passes exceptions tosys.excepthook."log": logs exceptions vialogging.exception."raise": re-raises immediately and stops further listeners. I.e. no "handling" at all."group": runs all listeners, then raisesExceptionGroupif any failed.
CancelEvent is handled separately and is never treated as an error.
Return values
At most one non-None return value is allowed across prototype + listeners.
If multiple handlers return a value, a RuntimeError is raised.
Changing event settings on module / project level
To define many events with changed settings (e.g. different default for exception), make an alias decorator like so:
from typed_event import event
my_event = event(strict=False, exceptions="log")
@my_event
def event1(): ...
@my_event
def event2(): ...
To apply project-wide, define the alias in a helper module and import from there.
Changelog
Version 1.1.0 (28.03.2026)
Make the library compatible with Python 3.10 (oldest version which is not EOL'ed yet.)
Version 1.0 (23.03.2026)
First release of the library as standalone project. Previously it was part of ASCII Designer.
Minor changes happened (strict mode as default, using sys.excepthook instead of print). Besides that, comprehensive testing and documentation was added.
License
Provided under MIT license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file typed_event-1.1.0.tar.gz.
File metadata
- Download URL: typed_event-1.1.0.tar.gz
- Upload date:
- Size: 41.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
569c71b16adf496aff311d174c082c7b5d15edd68522e165888017aa54a65cbc
|
|
| MD5 |
202cb0c68a7c29b18ad1c97df0c542bd
|
|
| BLAKE2b-256 |
9a3217629d40c05ed5613d4fc4747e34d3d5fbc223d4373a0d1e7b999dc20aa0
|
File details
Details for the file typed_event-1.1.0-py3-none-any.whl.
File metadata
- Download URL: typed_event-1.1.0-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
385e9b0fbccbc162832260c50de33a712a8144e44dadde4e7a3f5f617faeb147
|
|
| MD5 |
3f47825c743966e10fe865f17c51f6a3
|
|
| BLAKE2b-256 |
0b156ada4f58f615315b9946e224bf8a4c57bab8c98816568633278f0cf07ed0
|