Module peprock.patterns.observer

Subject notifies observers of state changes.

See https://en.wikipedia.org/wiki/Observer_pattern

Examples

>>> class MyObserver(Observer):
...     def notify(self, __subject, message):
...         print(f"My observer notified by {type(subject).__name__}: {message}")
...
>>> observer = MyObserver()
>>> subject = Subject()
>>> subject.register_observer(observer)
>>> subject.notify_observers("Hello, world!")
My observer notified by Subject: Hello, world!
Expand source code
"""Subject notifies observers of state changes.

See https://en.wikipedia.org/wiki/Observer_pattern

Examples
--------
>>> class MyObserver(Observer):
...     def notify(self, __subject, message):
...         print(f"My observer notified by {type(subject).__name__}: {message}")
...
>>> observer = MyObserver()
>>> subject = Subject()
>>> subject.register_observer(observer)
>>> subject.notify_observers("Hello, world!")
My observer notified by Subject: Hello, world!

"""

from __future__ import annotations

import abc
import functools
import typing
import weakref

_P = typing.ParamSpec("_P")


class Subject(typing.Generic[_P]):
    """Notify subjects of state changes and manage observer registration."""

    @functools.cached_property
    def _observers(self: Subject[_P]) -> weakref.WeakSet[Observer[_P]]:
        return weakref.WeakSet()

    def register_observer(self: Subject[_P], __observer: Observer[_P], /) -> None:
        """Register observer."""
        self._observers.add(__observer)

    def unregister_observer(self: Subject[_P], __observer: Observer[_P], /) -> None:
        """Unregister observer."""
        self._observers.discard(__observer)

    def is_registered_observer(self: Subject[_P], __observer: Observer[_P], /) -> bool:
        """Check if observer is registered and return as bool."""
        return __observer in self._observers

    def notify_observers(
        self: Subject[_P],
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> None:
        """Notify registered observers by calling their notify() method."""
        for observer in self._observers:
            # noinspection PyTypeChecker
            observer.notify(self, *args, **kwargs)


class Observer(typing.Generic[_P], metaclass=abc.ABCMeta):
    """Receive notifications from subjects after registration."""

    @abc.abstractmethod
    def notify(
        self: Observer[_P],
        __subject: Subject[_P],
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> None:
        """Notify of state change of subject."""
        ...


__all__ = [
    "Subject",
    "Observer",
]

Classes

class Observer

Receive notifications from subjects after registration.

Expand source code
class Observer(typing.Generic[_P], metaclass=abc.ABCMeta):
    """Receive notifications from subjects after registration."""

    @abc.abstractmethod
    def notify(
        self: Observer[_P],
        __subject: Subject[_P],
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> None:
        """Notify of state change of subject."""
        ...

Ancestors

  • typing.Generic

Methods

def notify(self: Observer[_P], _Observer__subject: Subject[_P], *args: _P.args, **kwargs: _P.kwargs) ‑> None

Notify of state change of subject.

Expand source code
@abc.abstractmethod
def notify(
    self: Observer[_P],
    __subject: Subject[_P],
    *args: _P.args,
    **kwargs: _P.kwargs,
) -> None:
    """Notify of state change of subject."""
    ...
class Subject

Notify subjects of state changes and manage observer registration.

Expand source code
class Subject(typing.Generic[_P]):
    """Notify subjects of state changes and manage observer registration."""

    @functools.cached_property
    def _observers(self: Subject[_P]) -> weakref.WeakSet[Observer[_P]]:
        return weakref.WeakSet()

    def register_observer(self: Subject[_P], __observer: Observer[_P], /) -> None:
        """Register observer."""
        self._observers.add(__observer)

    def unregister_observer(self: Subject[_P], __observer: Observer[_P], /) -> None:
        """Unregister observer."""
        self._observers.discard(__observer)

    def is_registered_observer(self: Subject[_P], __observer: Observer[_P], /) -> bool:
        """Check if observer is registered and return as bool."""
        return __observer in self._observers

    def notify_observers(
        self: Subject[_P],
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> None:
        """Notify registered observers by calling their notify() method."""
        for observer in self._observers:
            # noinspection PyTypeChecker
            observer.notify(self, *args, **kwargs)

Ancestors

  • typing.Generic

Methods

def is_registered_observer(self: Subject[_P], _Subject__observer: Observer[_P], /) ‑> bool

Check if observer is registered and return as bool.

Expand source code
def is_registered_observer(self: Subject[_P], __observer: Observer[_P], /) -> bool:
    """Check if observer is registered and return as bool."""
    return __observer in self._observers
def notify_observers(self: Subject[_P], *args: _P.args, **kwargs: _P.kwargs) ‑> None

Notify registered observers by calling their notify() method.

Expand source code
def notify_observers(
    self: Subject[_P],
    *args: _P.args,
    **kwargs: _P.kwargs,
) -> None:
    """Notify registered observers by calling their notify() method."""
    for observer in self._observers:
        # noinspection PyTypeChecker
        observer.notify(self, *args, **kwargs)
def register_observer(self: Subject[_P], _Subject__observer: Observer[_P], /) ‑> None

Register observer.

Expand source code
def register_observer(self: Subject[_P], __observer: Observer[_P], /) -> None:
    """Register observer."""
    self._observers.add(__observer)
def unregister_observer(self: Subject[_P], _Subject__observer: Observer[_P], /) ‑> None

Unregister observer.

Expand source code
def unregister_observer(self: Subject[_P], __observer: Observer[_P], /) -> None:
    """Unregister observer."""
    self._observers.discard(__observer)