diff --git a/gustaf/_base.py b/gustaf/_base.py index ec8fd0ca..6062e1d4 100644 --- a/gustaf/_base.py +++ b/gustaf/_base.py @@ -10,7 +10,7 @@ class GustafBase: methods are defined as classmethods.. """ - __slots__ = () + __slots__ = ("__weakref__",) def __init_subclass__(cls, *args, **kwargs): """ diff --git a/gustaf/helpers/__init__.py b/gustaf/helpers/__init__.py index 92687df7..33d42cd7 100644 --- a/gustaf/helpers/__init__.py +++ b/gustaf/helpers/__init__.py @@ -1,7 +1,8 @@ -from gustaf.helpers import data, options, raise_if +from gustaf.helpers import _base, data, options, raise_if __all__ = [ "data", "options", "raise_if", + "_base", ] diff --git a/gustaf/helpers/_base.py b/gustaf/helpers/_base.py new file mode 100644 index 00000000..cac37fcb --- /dev/null +++ b/gustaf/helpers/_base.py @@ -0,0 +1,29 @@ +"""gustaf/gustaf/helpers/_base.py + +Base class for helper +""" + +from weakref import ref + +from gustaf._base import GustafBase + + +class HelperBase(GustafBase): + """ + Minimal base layer for helper classes to avoid cyclic referencing. + Instead of saving a pure reference to helpee object, this will create a + weakref instead. This class defines `_helpee` setters and getters, so that + existing code can remain untouched. + """ + + __slots__ = ("_helpee_weak_ref",) + + @property + def _helpee(self): + """Returns dereferenced weak ref. Setter will create and save weakref + of a helpee.""" + return self._helpee_weak_ref() + + @_helpee.setter + def _helpee(self, helpee): + self._helpee_weak_ref = ref(helpee) diff --git a/gustaf/helpers/data.py b/gustaf/helpers/data.py index 8cd708c6..cdc4e1d6 100644 --- a/gustaf/helpers/data.py +++ b/gustaf/helpers/data.py @@ -9,7 +9,7 @@ import numpy as np -from gustaf._base import GustafBase +from gustaf.helpers._base import HelperBase class TrackedArray(np.ndarray): @@ -195,11 +195,8 @@ def make_tracked_array(array, dtype=None, copy=True): return tracked -class DataHolder(GustafBase): - __slots__ = ( - "_helpee", - "_saved", - ) +class DataHolder(HelperBase): + __slots__ = ("_saved",) def __init__(self, helpee): """Base class for any data holder. Behaves similar to dict. diff --git a/gustaf/helpers/options.py b/gustaf/helpers/options.py index 89e39cc3..30d049ba 100644 --- a/gustaf/helpers/options.py +++ b/gustaf/helpers/options.py @@ -4,6 +4,7 @@ """ from copy import deepcopy +from gustaf.helpers._base import HelperBase from gustaf.helpers.raise_if import ModuleImportRaiser @@ -224,7 +225,7 @@ def make_valid_options(*options): return valid_options -class ShowOption: +class ShowOption(HelperBase): """ Behaves similar to dict, but will only accept a set of options that's applicable to the helpee class. Intended use is to create a @@ -234,7 +235,7 @@ class ShowOption: specific common routines. ShowOption and ShowManager in a sense. """ - __slots__ = ("_helpee", "_options") + __slots__ = ("_options",) _valid_options = {}