From 3e61311772133fd4f3645dab01de836e04a97bf8 Mon Sep 17 00:00:00 2001 From: Frederik Hennig <frederik.hennig@fau.de> Date: Fri, 5 Apr 2024 12:58:32 +0200 Subject: [PATCH] Weakened type uniquing: Pickle may now create its own instances --- src/pystencils/types/meta.py | 33 +++++++++++++----------------- tests/nbackend/types/test_types.py | 1 - 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/pystencils/types/meta.py b/src/pystencils/types/meta.py index 198abf0ec..02c2f5a3b 100644 --- a/src/pystencils/types/meta.py +++ b/src/pystencils/types/meta.py @@ -27,7 +27,7 @@ For this to work, all instantiable subclasses of `PsType` must implement the fol arguments in their canonical order. This method is used by `PsTypeMeta` to identify instances, and to catch the various different possibilities Python offers for passing function arguments. - The ``__args__`` method, when called on an instance of the type, must return a tuple containing the constructor - arguments required to create that exact instance. This is used for pickling and unpickling of type objects, + arguments required to create that exact instance. This is used for comparing type objects as well as const-conversion. As a rule, ``MyType.__canonical_args__(< arguments >)`` and ``MyType(< arguments >).__args__()`` must always return @@ -81,27 +81,11 @@ class PsType(metaclass=PsTypeMeta): # Internals: Object creation, pickling and unpickling # ------------------------------------------------------------------------------------------- - def __new__(cls, *args, _pickle=False, **kwargs): - if _pickle: - # force unpickler to use metaclass uniquing mechanism - return cls(*args, **kwargs) - else: - return super().__new__(cls) - - def __getnewargs_ex__(self): - args = self.__args__() - kwargs = {"const": self._const, "_pickle": True} - return args, kwargs - - def __getstate__(self): - # To make sure pickle does not unnecessarily override the instance dictionary - return None - @abstractmethod def __args__(self) -> tuple[Any, ...]: """Return the arguments used to create this instance, in canonical order, excluding the const-qualifier. - The tuple returned by this method is used to serialize, deserialize, and const-convert types. + The tuple returned by this method is used to identify, check equality, and const-convert types. For each instantiable subclass ``MyType`` of ``PsType``, the following must hold:: t = MyType(< arguments >) @@ -115,7 +99,18 @@ class PsType(metaclass=PsTypeMeta): """Return a tuple containing the positional and keyword arguments of ``__init__`` in their canonical order.""" - # __eq__ and __hash__ unimplemented because due to uniquing, types are equal iff their instances are equal + def __eq__(self, other: object) -> bool: + if self is other: + return True + + if type(self) is not type(other): + return False + + other = cast(PsType, other) + return self.const == other.const and self.__args__() == other.__args__() + + def __hash__(self) -> int: + return hash((type(self), self.const, self.__args__())) # ------------------------------------------------------------------------------------------- # Constructor and properties diff --git a/tests/nbackend/types/test_types.py b/tests/nbackend/types/test_types.py index 65cbf9d08..39f89e6fe 100644 --- a/tests/nbackend/types/test_types.py +++ b/tests/nbackend/types/test_types.py @@ -163,4 +163,3 @@ def test_pickle(): for t1, t2 in zip(types, restored): assert t1 == t2 - assert t1 is t2 -- GitLab