A Pythonic implementation of the observer pattern
Project description
beaconpy
A Pythonic implementation of the observer pattern with robust memory management and error handling.
Features
- Weak references to callbacks so you don't have remove an observer (even though you can)
- Support for various callback types (functions, static methods, class methods, instance methods)
- Context managers for to allow for different ways of making changes to the observed object:
- Changes wit a notification
- Batch operations with a single notification
- Changes with no notifications
- Asynchronous scheduling of callbacks, with a synchronous fallback
- Automatic cleanup of stale observers
- Robust error handling that ensures all observers get notified even if some raise exceptions
Installation
pip install beaconpy
Usage
Basic Usage
from beaconpy import Beacon
# Create a class that extends Beacon
class Counter(Beacon):
def __init__(self):
super().__init__()
self._count = 0
@property
def count(self):
return self._count
def increment(self):
# Use the context manager to trigger notifications
with self.changing_state():
self._count += 1
# Create an observer function
def on_counter_changed(sender):
print(f"Counter changed! New value: {sender.count}")
# Create a counter and register the observer
counter = Counter()
counter.add_observer(on_counter_changed)
# Increment the counter - this will trigger the observer
counter.increment() # Prints: "Counter changed! New value: 1"
# Remove the observer when no longer needed
# If you forget about this and the observer is garbage collected,
# beaconpy will stop sending notifications to it.
counter.remove_observer(on_counter_changed)
Context Managers
The library provides three context managers for different notification behaviors:
# Normal state change with notification
with beacon.changing_state():
# Make changes to state here
# Observers will be notified after the block
# Change state without notification
with beacon.changing_state_without_notification():
# Make silent changes to state here
# No observers will be notified
# Batch changes with a single notification
with beacon.batch_changing_state():
# Make multiple changes to state here
# Only one notification will be sent after all changes
Supported Callback Types
beaconpy supports various types of callbacks:
# Regular functions
def function_callback(sender):
print("Function called")
# Static methods
class ExampleClass:
@staticmethod
def static_method_callback(sender):
print("Static method called")
# Class methods
class ExampleClass:
@classmethod
def class_method_callback(cls, sender):
print(f"Class method called on {cls.__name__}")
# Instance methods
class ExampleClass:
def instance_method_callback(self, sender):
print("Instance method called")
# Add as observers
example = ExampleClass()
beacon.add_observer(function_callback)
beacon.add_observer(ExampleClass.static_method_callback)
beacon.add_observer(ExampleClass.class_method_callback)
beacon.add_observer(example.instance_method_callback)
Important Limitations
- Lambda functions are not supported as callbacks because they may be unexpectedly garbage collected
functools.partialobjects, dynamically created functions, and factory-created functions should be avoided for similar reasons
Error Handling
- All callbacks are repsonsible for handling their exceptions.
- In sync mode (no runloop) if a callback throws an exception, it won't prevent other callbacks from being notified. All exceptions will be captured by beaconpy and stored in a list of Tuples (callback, exception)
- Once all have been notified, this list will be passed to the
on_sync_errorsmethod.
- Once all have been notified, this list will be passed to the
- In async mode, the run loop will handle the uncaught exceptions
You can override the on_sync_errors method to customize error handling:
class CustomBeacon(Beacon):
def __init__(self):
super().__init__()
self.errors = []
def on_sync_errors(self, errors):
# Store errors for later analysis
self.errors.extend(errors)
# You can also call the parent implementation if needed
# super().on_sync_errors(errors)
License
MIT
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 beaconpy-0.1.1.tar.gz.
File metadata
- Download URL: beaconpy-0.1.1.tar.gz
- Upload date:
- Size: 15.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f5ab1f3e7f611f46b3373150b979290922841a3f1b800b575e1df02efacb3eb
|
|
| MD5 |
9a5becd3be4caafe3e77184925e6cb80
|
|
| BLAKE2b-256 |
b984e0d01d73dbc4b81c2ff36b5677144b7edda1886a2c6fb47cee34e198a7ae
|
File details
Details for the file beaconpy-0.1.1-py3-none-any.whl.
File metadata
- Download URL: beaconpy-0.1.1-py3-none-any.whl
- Upload date:
- Size: 15.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8a4db1aeaca9c1f3180ff31d53c799077ab6c3f6461e67d8ee7e8ef591313a9
|
|
| MD5 |
e59d707e6c2138c701ad34002181d939
|
|
| BLAKE2b-256 |
aa12b1b883ff0c145382e8ef0ac93656f72b03f8af206c4c10e8c8ed24453f7f
|