From b4a65f8dfb557c9b3cfaff8075d16c625bde808e Mon Sep 17 00:00:00 2001 From: rednafi Date: Thu, 23 Jul 2020 14:44:00 +0600 Subject: [PATCH 1/3] Added type hints to observer pattern --- patterns/behavioral/observer.py | 37 ++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/patterns/behavioral/observer.py b/patterns/behavioral/observer.py index 49075facb..ea32e3ca0 100644 --- a/patterns/behavioral/observer.py +++ b/patterns/behavioral/observer.py @@ -8,54 +8,61 @@ Django Signals: https://docs.djangoproject.com/en/2.1/topics/signals/ Flask Signals: http://flask.pocoo.org/docs/1.0/signals/ """ +from __future__ import annotations + +from typing import List, Optional, Protocol + + +# define a generic observer type +class Observer(Protocol): + def update(self, subject: Subject) -> None: + pass class Subject: - def __init__(self): - self._observers = [] + def __init__(self) -> None: + self._observers: List[Observer] = [] - def attach(self, observer): + def attach(self, observer: Observer) -> None: if observer not in self._observers: self._observers.append(observer) - def detach(self, observer): + def detach(self, observer: Observer) -> None: try: self._observers.remove(observer) except ValueError: pass - def notify(self, modifier=None): + def notify(self, modifier: Optional[Observer] = None) -> None: for observer in self._observers: if modifier != observer: observer.update(self) class Data(Subject): - def __init__(self, name=""): - Subject.__init__(self) + def __init__(self, name: str = "") -> None: + super().__init__() self.name = name self._data = 0 @property - def data(self): + def data(self) -> int: return self._data @data.setter - def data(self, value): + def data(self, value: int) -> None: self._data = value self.notify() class HexViewer: - def update(self, subject): - print( - "HexViewer: Subject {} has data 0x{:x}".format(subject.name, subject.data) - ) + def update(self, subject: Data) -> None: + print(f"HexViewer: Subject {subject.name} has data 0x{subject.data:x}") class DecimalViewer: - def update(self, subject): - print("DecimalViewer: Subject %s has data %d" % (subject.name, subject.data)) + def update(self, subject: Data) -> None: + print(f"DecimalViewer: Subject {subject.name} has data {subject.data}") def main(): From 27115a87cac1e79581635aacda345a824260afe6 Mon Sep 17 00:00:00 2001 From: rednafi Date: Thu, 23 Jul 2020 14:47:45 +0600 Subject: [PATCH 2/3] Updated signal links --- patterns/behavioral/observer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patterns/behavioral/observer.py b/patterns/behavioral/observer.py index ea32e3ca0..9c930389c 100644 --- a/patterns/behavioral/observer.py +++ b/patterns/behavioral/observer.py @@ -5,8 +5,8 @@ Maintains a list of dependents and notifies them of any state changes. *Examples in Python ecosystem: -Django Signals: https://docs.djangoproject.com/en/2.1/topics/signals/ -Flask Signals: http://flask.pocoo.org/docs/1.0/signals/ +Django Signals: https://docs.djangoproject.com/en/3.1/topics/signals/ +Flask Signals: https://flask.palletsprojects.com/en/1.1.x/signals/ """ from __future__ import annotations From daa2219f00c993c8697ceb20a704b9d5c4a50808 Mon Sep 17 00:00:00 2001 From: rednafi Date: Thu, 23 Jul 2020 17:48:05 +0600 Subject: [PATCH 3/3] Handle unnamed exception with contextlib.suppress --- patterns/behavioral/observer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/patterns/behavioral/observer.py b/patterns/behavioral/observer.py index 9c930389c..b2d503b77 100644 --- a/patterns/behavioral/observer.py +++ b/patterns/behavioral/observer.py @@ -8,8 +8,10 @@ Django Signals: https://docs.djangoproject.com/en/3.1/topics/signals/ Flask Signals: https://flask.palletsprojects.com/en/1.1.x/signals/ """ + from __future__ import annotations +from contextlib import suppress from typing import List, Optional, Protocol @@ -28,10 +30,8 @@ def attach(self, observer: Observer) -> None: self._observers.append(observer) def detach(self, observer: Observer) -> None: - try: + with suppress(ValueError): self._observers.remove(observer) - except ValueError: - pass def notify(self, modifier: Optional[Observer] = None) -> None: for observer in self._observers: