PynneX is a lightweight, pure-Python signal/slot library that provides thread-safe, asyncio-compatible event handling. It enables clean decoupling of components, seamless thread-to-thread communication, and flexible asynchronous/synchronous slot handling.
@nx_with_signals
, @nx_signal
, @nx_slot
, @nx_with_worker
) are also available without the nx_
prefix for convenience (i.e., you can use @with_signals
, @signal
, @slot
, @with_worker
). This makes the code more concise and familiar to users of similar frameworks.@nx_property
decorator provides thread-safe property access with automatic signal emission on changes.weak=True
when connecting a slot, the library holds a weak reference to the receiver object. This allows the receiver to be garbage-collected if there are no other strong references to it. Once garbage-collected, the connection is automatically removed, preventing stale references.Modern Python applications often rely on asynchronous operations and multi-threading. Traditional event frameworks either require large external dependencies or lack seamless async/thread support. PynneX provides:
Async-Ready
Thread-Safe by Design
Flexible Slots
Robust Testing & Examples
PynneX requires Python 3.10 or higher. This requirement ensures stable asyncio operations, as Python 3.10 introduced important improvements including:
git clone https://github.com/nexconnectio/pynnex.git
cd pynnex
pip install -e .
For development (includes tests and linting tools):
pip install -e ".[dev]
from pynnex import with_signals, signal, slot
@with_signals
class Counter:
def __init__(self):
self.count = 0
@signal
def count_changed(self):
pass
def increment(self):
self.count += 1
self.count_changed.emit(self.count)
@with_signals
class Display:
@slot
async def on_count_changed(self, value):
print(f"Count is now: {value}")
# Connect and use
counter = Counter()
display = Display()
counter.count_changed.connect(display, display.on_count_changed)
counter.increment() # Will print: "Count is now: 1"
@with_signals
class AsyncDisplay:
@slot
async def on_count_changed(self, value):
await asyncio.sleep(1) # Simulate async operation
print(f"Count updated to: {value}")
# Usage in async context
async def main():
counter = Counter()
display = AsyncDisplay()
counter.count_changed.connect(display, display.on_count_changed)
counter.increment()
# Wait for async processing
await asyncio.sleep(1.1)
asyncio.run(main())
@signal
. Signals are attributes of a class that can be emitted to notify interested parties.@slot
. Slots are methods that respond to signals. Slots can be synchronous or async functions.signal.connect(receiver, slot)
to link signals to slots. Connections can also be made directly to functions or lambdas.PynneX automatically detects whether the signal emission and slot execution occur in the same thread or different threads:
This mechanism frees you from manually dispatching calls across threads.
For background work, PynneX provides a @nx_with_worker
decorator that:
Worker Example
from pynnex import with_worker, signal
@with_worker
class DataProcessor:
@signal
def processing_done(self):
"""Emitted when processing completes"""
async def run(self, *args, **kwargs):
# The main entry point for the worker thread’s event loop
# Wait for tasks or stopping signal
await self.wait_for_stop()
async def process_data(self, data):
# Perform heavy computation in the worker thread
result = await heavy_computation(data)
self.processing_done.emit(result)
processor = DataProcessor()
processor.start()
# Queue a task to run in the worker thread:
processor.queue_task(processor.process_data(some_data))
# Stop the worker gracefully
processor.stop()
We’ve expanded PynneX’s examples to guide you from simple demos to full-fledged applications. Each example has its own GitHub link with fully commented code.
For detailed explanations, code walkthroughs, and architecture diagrams of these examples, check out our Examples Documentation.
Stock Monitor Console: Real-time price updates, alert configuration, and notification history in action
Stock Monitor UI: Real-time price updates, alert configuration, and notification history in action
Together, these examples highlight PynneX’s versatility—covering everything from quick demos to production-like patterns with threads, queues, and reactive UI updates.
PynneX is licensed under the MIT License. See LICENSE for details.