From 9b1939deafca041ecaf6573dd81e4372a04906c2 Mon Sep 17 00:00:00 2001 From: Daniel Werner Date: Thu, 31 Aug 2023 10:46:10 +0200 Subject: [PATCH] Fix dead objects being called through weakrefs When events (such as 'tensorlib_changed') are called, a bug occured previously where objects (i.e. the `TensorViewer`) are already dead. In this case an error occured when member functions where using attributes such as `self._sorted_indices`. This bug is fixed by catching the cases, in which the object is invalidated by earlier callbacks. --- src/pyhf/events.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/pyhf/events.py b/src/pyhf/events.py index f28d0a7563..d61e91a8ad 100644 --- a/src/pyhf/events.py +++ b/src/pyhf/events.py @@ -64,12 +64,19 @@ def _flush(self): self._callbacks = _callbacks def __call__(self, *args, **kwargs): - for func, arg in self.callbacks: + for func, arg in self._callbacks: # weakref: needs to be de-ref'd first before calling if arg is not None: - func()(arg(), *args, **kwargs) + arg_ref = arg() + if arg_ref is not None: + func()(arg_ref, *args, **kwargs) else: func()(*args, **kwargs) + # We have to flush after calling all the callbacks, not before. That's + # beacause, earlier callbacks might cause new dead arg weakrefs in + # later callbacks. So we check for dead weakrefs in each iteration + # and then we flush at the end. + self._flush() def __iter__(self): return iter(self.callbacks)