Coverage for /builds/ase/ase/ase/gui/observer.py: 75.00%
28 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
1import warnings
2import weakref
5class Observers:
6 def __init__(self):
7 self.observer_weakrefs = []
9 def register(self, observer):
10 if hasattr(observer, '__self__'): # observer is an instance method
11 # Since bound methods are shortlived we need to store the instance
12 # it is bound to and use getattr() later:
13 obj = observer.__self__
14 name = observer.__name__
15 else:
16 obj = observer
17 name = None
18 self.observer_weakrefs.append((weakref.ref(obj), name))
20 def notify(self):
21 # We should probably add an event class to these callbacks.
22 weakrefs_still_alive = []
23 for weak_ref, name in self.observer_weakrefs:
24 observer = weak_ref()
25 if observer is not None:
26 weakrefs_still_alive.append((weak_ref, name))
27 if name is not None:
28 # If the observer is an instance method we stored
29 # self, for garbage collection reasons, and now need to
30 # get the actual method:
31 observer = getattr(observer, name)
33 try:
34 observer()
35 except Exception as ex:
36 import traceback
38 tb = ''.join(traceback.format_exception(ex))
39 warnings.warn(
40 f'Suppressed exception in observer {observer}: {tb}'
41 )
42 continue
44 self.observer_weakrefs = weakrefs_still_alive