#15207: SageObject breaks pickling circular structures
--------------------------+-------------------------
Reporter: nbruin | Owner:
Type: defect | Status: new
Priority: major | Milestone: sage-5.13
Component: misc | Resolution:
Keywords: | Merged in:
Authors: | Reviewers:
Report Upstream: N/A | Work issues:
Branch: | Commit:
Dependencies: | Stopgaps:
--------------------------+-------------------------
Comment (by nbruin):
A slightly different approach for `CategoryObject`: it caches its hash
already, so all we need to do is pickle it as well and ensure the cache is
reinitialized by the constructor, not by setstate. If we add the following
to `sage.structure.category_object.CategoryObject`:
{{{
def __reduce__(self):
if not isinstance(self,CategoryObject):
raise TypeError("this only works for CategoryObject")
cdef CategoryObject Cco=self
try:
getstate = self.__getstate__
except AttributeError:
if getattr(self, "__slots__", None):
raise TypeError("a class that defines __slots__ without "
"defining __getstate__ cannot be pickled")
try:
dict = self.__dict__
except AttributeError:
dict = None
else:
dict = getstate()
if Cco._hash_value == -1:
reconstructor = reconstruct_CategoryObject_without_hash
args=(self.__class__)
else:
reconstructor = reconstruct_CategoryObject_with_hash
args=(self.__class__,Cco._hash_value,)
if dict:
return reconstructor, args, dict
else:
return reconstructor, args
}}}
as well as:
{{{
def reconstruct_CategoryObject_with_hash(cls,hash,*args):
C=cls.__new__(cls,*args)
if not isinstance(C,CategoryObject):
raise TypeError("this only works for CategoryObject")
cdef CategoryObject Cco=C
Cco._hash_value=hash
return C
def reconstruct_CategoryObject_without_hash(cls,*args):
return cls.__new__(cls,*args)
}}}
we can do:
{{{
sage: L=LaurentPolynomialRing(QQ,'t')
sage: L.d={L:1}
sage: C=loads(dumps(L))
}}}
which otherwise would fail. There are some doctests in
`src/sage/structure/factory.pyx` that fail, so this approach needs a bit
of adjustment, but I think something along these lines would help a lot.
Of course, we just kick the can a little further. It's easy to create two
non-identical rings with the same hash, so that equality testing really
becomes important for the dictionary lookup:
{{{
sage: L1=LaurentPolynomialRing(QQ,'u,v',order="deglex")
sage: L2=LaurentPolynomialRing(QQ,'u,v',order="lex")
sage: L1.d={L1:1,L2:2}
sage: L2.d={L1:1,L2:2}
sage: loads(dumps(L1))
AttributeError: 'LaurentPolynomialRing_mpair_with_category' object has no
attribute '_R'
}}}
because although the rings hash OK, their `_R` attribute, required in the
`__cmp__` implementation, is not initialized.
--
Ticket URL: <http://trac.sagemath.org/ticket/15207#comment:6>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica,
and MATLAB
--
You received this message because you are subscribed to the Google Groups
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/groups/opt_out.