#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.

Reply via email to