Your one-stop-shop for observer synchronization.
Project description
Munin
The observer pattern implementation with a cool name.
Features:
- Simple observer implementation with Observer (
Protocol) and ObservableMixin. - Concept of "discretion" to break infinite call-back loops.
- Simple, No python wizardry!
- Easily control behaviour with decorators
@notifyand@discrete.
Goals:
- Simplicity: Limit python wizardry
- Concise: SLOC should never reach thousands
- Flexible: Should be able to cover every Pythonista's observing needs.
- Typed: Keep
munintyped and type-safe to the furthest extent possible. - Well tested: Code coverage should be "at least" 100%.
Walk-through
Say we have a text field from some GUI-framework, FrameworkTextField. It's common for
GUI-frameworks to offer some synchronization mechanism of their own to handle certain events
(user input in a text field, for example), be it signals, call-backs or black magic.
class FrameworkTextField:
def __init__(self):
self.content: str = "<Placeholder text>"
self.content_changed_callbacks: List[Callable[str, ...]] = []
def set_content(self, new_content):
self.content = new_content
self.on_content_changed()
def on_content_changed(self):
for callback in self.content_changed_callbacks:
callback(self.content)
One is easily tempted to use the framework's synchronization mechanisms to keep their model synced, but as in Uncle Bob's words; "We should be sceptic of frameworks" and most important of all: We should not depend on them.
To separate view and model, you can do something like this with munin:
from munin import Observer, ObservableMixin
class MyTextModel(ObservableMixin):
"""
Basically an observable str.
"""
def __init__(self):
super().__init__()
self.text: str = ""
def set_text(self, new_text: str):
self.text = new_text
self.notify() # alternatively decorator `@notify`
# Implemented in ObservableMixin:
#
# * def add_observer(self, observer): ...
# * def notify(self): ...
class MyTextField(FrameworkTextField, Observer[MyTextModel]):
def __init__(self, model):
FrameworkTextField.__init__(self)
model.add_observer(self)
self.content_changed_callbacks.append(model.set_text)
def act(self, observable: MyTextModel):
"""
act() is munin's "update"-function.
When an Observable notify:s, the Observable passes itself through this function to
all its Observers.
"""
self.set_content(observable.content)
model = MyTextModel()
MyTextField(model)
The keen reader sees that a call to MyTextField.set_content(...) will start an infinite loop.
This can be combatted with "Discretion", litteraly.
"Discretion" is the munin-way to temporarily turn off the observer synchronization.
from munin import discretion, discrete, ...
class MyTextField(FrameworkTextField, Observer[MyTextModel]):
...
@discrete # "Discretion" with a decorator
def act(self, observable: MyTextModel):
# "Discretion" with a context manager
with discretion:
self.set_content(observable.content)
Some GUI frameworks (PySide for example) experience metaclass conflicts when doing
multiple inheritance like in this example. Luckily, Observer is a Protocol, which means that
the inheritance can be omitted without any repercussions.
class MyTextField(FrameworkTextField):
def act(self, observable: MyTextModel):
"""Still satisfies the Observer Protocol"""
pass
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 munin-observers-0.2.1.tar.gz.
File metadata
- Download URL: munin-observers-0.2.1.tar.gz
- Upload date:
- Size: 5.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.11.0 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c80ccacea5cb7d2e26779fc9ee41c182376e69ba3e45f9436f66a3bd208d187
|
|
| MD5 |
8aa03e1b1bf26bbb0fc16a3c639de14f
|
|
| BLAKE2b-256 |
61b6ecdf903faf857f182d9a1dd58c896a7ad52934c17d486729e1f0b99f0e79
|
File details
Details for the file munin_observers-0.2.1-py3-none-any.whl.
File metadata
- Download URL: munin_observers-0.2.1-py3-none-any.whl
- Upload date:
- Size: 5.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.11.0 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7628c66e9302e8738932a955c4083c9b7f5678b271486f045bed9d3b84939be9
|
|
| MD5 |
07daf24c50b9a12c316d985235bcee79
|
|
| BLAKE2b-256 |
00ed8c234b3d81898ada08757b42c75110ea58acb38ef0d0256ced18d57b3cf5
|