Hey everyone!
Iâm thrilled to announce TSignal 0.4.0, a pure-Python signal/slot library that helps you build event-driven applications with ease. TSignal integrates smoothly with async/await, handles thread safety for you, and doesnât force you to install heavy frameworks.
Whatâs New in 0.4.0
Weak Reference Support
You can now connect a slot with weak=True. If the receiver object is garbage-collected, TSignal automatically removes the connection, preventing memory leaks or stale slots in long-lived applications:
```python
Set weak=True for individual connections
sender.event.connect(receiver, receiver.on_event, weak=True)
Or, set weak_default=True at class level (default is True)
@t_with_signals(weak_default=True)
class WeakRefSender:
@t_signal
def event(self):
pass
Now all connections from this sender will use weak references by default
No need to specify weak=True for each connect call
sender = WeakRefSender()
sender.event.connect(receiver, receiver.on_event) # Uses weak reference
Once receiver
is GCâd, TSignal cleans up automatically.
```
One-Shot Connections (Optional)
A new connection parameter, one_shot=True, lets you disconnect a slot right after its first call. Itâs handy for âlisten-onceâ or âsingle handshakeâ scenarios. Just set:
python
signal.connect(receiver, receiver.handler, one_shot=True)
The slot automatically goes away after the first emit.
Thread-Safety Improvements
TSignalâs internal locking and scheduling mechanisms have been refined to further reduce race conditions in high-concurrency environments. This ensures more robust behavior under demanding multi-thread loads.
From Basics to Practical Use Cases
Weâve expanded TSignalâ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.
Basic Signal/Slot Examples
Multi-Threading and Workers
- thread_basic.py and thread_worker.py
- walk you through multi-threaded setups, including background tasks and worker loops.
- Youâll see how signals emitted from a background thread are properly handled in the main event loop or another threadâs loop.
Stock Monitor (Console & GUI)
stock_monitor_simple.py
- A minimal stock monitor that periodically updates a display. Perfect for learning how TSignal can orchestrate real-time updates without blocking.
stock_monitor_console.py
- A CLI-based interface that lets you type commands to set alerts, list them, and watch stock data update in real time.
stock_monitor_ui.py
- A more elaborate Kivy-based UI example showcasing real-time stock monitoring. You'll see how TSignal updates the interface instantly without freezing the GUI. This example underscores how TSignalâs thread and event-loop management keeps your UI responsive and your background tasks humming.
Together, these examples highlight TSignalâs versatilityâcovering everything from quick demos to production-like patterns with threads, queues, and reactive UI updates.
Why TSignal?
Pure Python, No Heavy Frameworks
TSignal imposes no large dependencies; itâs a clean library you can drop into your existing code.
Async-Ready
Built for modern asyncio workflows; you can define async slots that are invoked without blocking your event loop.
Thread-Safe by Design
Signals are dispatched to the correct thread or event loop behind the scenes, so you donât have to manage locks.
Flexible Slots
Connect to class methods, standalone functions, or lambdas. Use strong references (the usual approach) or weak=True.
Robust Testing & Examples
Weâve invested heavily in test coverage, plus we have real-world examples (including a GUI!) to showcase best practices.
Quick Example
```python
from tsignal import t_with_signals, t_signal, t_slot
@twith_signals
class Counter:
def __init_(self):
self.count = 0
@t_signal
def count_changed(self):
pass
def increment(self):
self.count += 1
self.count_changed.emit(self.count)
@t_with_signals
class Display:
@t_slot
def on_count_changed(self, value):
print(f"Count is now: {value}")
counter = Counter()
display = Display()
counter.count_changed.connect(display, display.on_count_changed)
counter.increment()
Output: "Count is now: 1"
```
Get Started
- GitHub Repo: TSignal on GitHub
- Documentation & Examples: Explore how to define your own signals and slots, integrate with threads, or build a reactive UI.
- Issues & PRs: We welcome feedback, bug reports, and contributions.
If youâre building async or threaded Python apps that could benefit from a robust event-driven approach, give TSignal a try. Weâd love to know what you thinkâopen an issue or share your experience!
Thanks for checking out TSignal 0.4.0, and happy coding!