#15156: Pickling with __reduce__() loops creates invalid pickles
-------------------------------------+-------------------------------------
Reporter: vbraun | Owner:
Type: defect | Status: needs_info
Priority: major | Milestone: sage-6.3
Component: misc | Resolution:
Keywords: | Merged in:
Authors: SimonKing, | Reviewers:
jkeitel, novoselt, nbruin | Work issues:
Report Upstream: N/A | Commit:
Branch: | 82ba456b8c828700d28ac36822b300f00d8b1308
u/saraedum/ticket/15156 | Stopgaps:
Dependencies: #15692 |
-------------------------------------+-------------------------------------
Comment (by saraedum):
Replying to [comment:17 nbruin]:
> Replying to [comment:16 saraedum]:
> > I'm not sure what you mean by "instantiation phase".
> Unpickling an object happens in two phases: first, the object is
instantiated using the first set of parameters given by `__reduce__`.
There can't be circularities here, because that would mean passing an
object that hasn't been instantiated yet to the routine that does the
instantiating.
>
> The second phase is done by `__setstate__` and allows further
modification of the state to obtain the desired one. Here, circularities
are not a problem. The pickler carefully ensures that all objects involved
in circularities have been instantiated (how would you pass them
otherwise?)
> The trick here is that during `__setstate__` you may encounter objects
that haven't had a chance to run their own `__setstate__` yet.
I don't think that's really what happens. Maybe I misunderstand what you
are saying but I don't think that all objects in the pickle are
instantiated and then all object's `__setstate__` is called.
Have a look at the example I posted above. There, to unpickle `b`, `a` is
created, its `__setstate__` is called (which fails), and only then `b` is
created and its `__setstate__` is called.
> > There is of course lots of space for improvement, but what do you
think about this idea?
> I think it's a bad idea because it doesn't solve the problem where it
needs to be solved. Homsets fundamentally need domain and codomain for
their construction. It's part of their hash. If a parent wants to include
a homset in its construction parameter rather than in the `__setstate__`
then it is introducing an unavoidable cycle.
This is not what happens. Here is a real-world example:
{{{
sage: class A(Parent):
def __reduce__(self):
return A,(),self.homset
def __setstate__(self, homset):
self.homset = homset
....:
sage: P=A()
sage: H=Hom(P,P)
sage: P.homset = H
sage: import pickle
sage: pickle.dumps(H)
AssertionError
}}}
> If the domain and codomain want to store a homset involving them
somewhere, then their unpickling should do so via `__setstate__`, i.e.,
their `__reduce__` should include the homset in the second return value,
not the first.
That's what happens above and does not work. I'm also confused because I
always assumed that it would be enough to break the circularity on the
first parameter in a single place. Somehow this does not seem to work.
--
Ticket URL: <http://trac.sagemath.org/ticket/15156#comment:18>
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/d/optout.