Author: Armin Rigo <[email protected]>
Branch: continulet-pickle
Changeset: r47279:46308e5543ff
Date: 2011-09-14 21:50 +0200
http://bitbucket.org/pypy/pypy/changeset/46308e5543ff/
Log: Finished pickling :-)
diff --git a/pypy/module/_continuation/interp_pickle.py
b/pypy/module/_continuation/interp_pickle.py
--- a/pypy/module/_continuation/interp_pickle.py
+++ b/pypy/module/_continuation/interp_pickle.py
@@ -4,6 +4,7 @@
from pypy.module._continuation.interp_continuation import State, global_state
from pypy.module._continuation.interp_continuation import build_sthread
from pypy.module._continuation.interp_continuation import post_switch
+from pypy.module._continuation.interp_continuation import get_result
def getunpickle(space):
@@ -18,13 +19,12 @@
# Doing the right thing looks involved, though...
space = self.space
if self.sthread is None:
- raise geterror(space, "cannot pickle (yet) a continulet that is "
- "not initialized")
- if self.sthread.is_empty_handle(self.h):
- raise geterror(space, "cannot pickle (yet) a continulet that is "
- "already finished")
+ w_frame = space.w_False
+ elif self.sthread.is_empty_handle(self.h):
+ w_frame = space.w_None
+ else:
+ w_frame = space.wrap(self.bottomframe)
w_continulet_type = space.type(space.wrap(self))
- w_frame = space.wrap(self.bottomframe)
w_dict = self.getdict(space) or space.w_None
args = [getunpickle(space),
space.newtuple([w_continulet_type]),
@@ -38,16 +38,19 @@
"initialized continulet")
space = self.space
w_frame, w_dict = space.fixedview(w_args, expected_length=2)
- self.bottomframe = space.interp_w(PyFrame, w_frame)
if not space.is_w(w_dict, space.w_None):
- self.setdict(w_dict)
+ self.setdict(space, w_dict)
+ if space.is_w(w_frame, space.w_False):
+ return # not initialized
+ sthread = build_sthread(self.space)
+ self.sthread = sthread
+ self.bottomframe = space.interp_w(PyFrame, w_frame, can_be_None=True)
#
global_state.origin = self
- sthread = build_sthread(self.space)
- sthread.frame2continulet.set(self.bottomframe, self)
- self.sthread = sthread
+ if self.bottomframe is not None:
+ sthread.frame2continulet.set(self.bottomframe, self)
self.h = sthread.new(resume_trampoline_callback)
- global_state.origin = None
+ get_result() # propagate the eventual MemoryError
# ____________________________________________________________
@@ -55,42 +58,46 @@
self = global_state.origin
self.h = h
space = self.space
+ sthread = self.sthread
try:
- sthread = self.sthread
- h = sthread.switch(self.h)
- try:
- w_result = post_switch(sthread, h)
- operr = None
- except OperationError, operr:
- pass
- #
- while True:
- ec = sthread.ec
- frame = ec.topframeref()
- assert frame is not None # XXX better error message
- exit_continulet = sthread.frame2continulet.get(frame)
- #
- continue_after_call(frame)
- #
- # small hack: unlink frame out of the execution context, because
- # execute_frame will add it there again
- ec.topframeref = frame.f_backref
- #
+ global_state.clear()
+ if self.bottomframe is None:
+ w_result = space.w_None
+ else:
+ h = sthread.switch(self.h)
try:
- w_result = frame.execute_frame(w_result, operr)
+ w_result = post_switch(sthread, h)
operr = None
except OperationError, operr:
pass
- if exit_continulet is not None:
- self = exit_continulet
- break
- if operr:
- raise operr
+ #
+ while True:
+ ec = sthread.ec
+ frame = ec.topframeref()
+ assert frame is not None # XXX better error message
+ exit_continulet = sthread.frame2continulet.get(frame)
+ #
+ continue_after_call(frame)
+ #
+ # small hack: unlink frame out of the execution context,
+ # because execute_frame will add it there again
+ ec.topframeref = frame.f_backref
+ #
+ try:
+ w_result = frame.execute_frame(w_result, operr)
+ operr = None
+ except OperationError, operr:
+ pass
+ if exit_continulet is not None:
+ self = exit_continulet
+ break
+ sthread.ec.topframeref = jit.vref_None
+ if operr:
+ raise operr
except Exception, e:
global_state.propagate_exception = e
else:
global_state.w_value = w_result
- sthread.ec.topframeref = jit.vref_None
global_state.origin = self
global_state.destination = self
return self.h
diff --git a/pypy/module/_continuation/test/test_zpickle.py
b/pypy/module/_continuation/test/test_zpickle.py
--- a/pypy/module/_continuation/test/test_zpickle.py
+++ b/pypy/module/_continuation/test/test_zpickle.py
@@ -86,6 +86,20 @@
assert not co.is_pending()
''' in mod.__dict__
+ def test_copy_continulet_already_finished(self):
+ from _continuation import continulet, error
+ import copy
+ lst = []
+ co = continulet(lst.append)
+ co.switch()
+ co2 = copy.deepcopy(co)
+ assert not co.is_pending()
+ assert not co2.is_pending()
+ raises(error, co.__init__, lst.append)
+ raises(error, co2.__init__, lst.append)
+ raises(error, co.switch)
+ raises(error, co2.switch)
+
class AppTestPickle:
version = 0
@@ -110,7 +124,6 @@
cls.w_version = cls.space.wrap(cls.version)
def test_pickle_continulet_empty(self):
- skip("pickle a not-initialized continulet")
from _continuation import continulet
lst = [4]
co = continulet.__new__(continulet)
@@ -129,7 +142,6 @@
assert result == [5, co2]
def test_pickle_continulet_empty_subclass(self):
- skip("pickle a not-initialized continulet")
from test_pickle_continulet import continulet, A
lst = [4]
co = continulet.__new__(A)
@@ -201,6 +213,46 @@
assert not co.is_pending()
''' in mod.__dict__
+ def test_pickle_continulet_real_subclass(self):
+ import new, sys
+ mod = new.module('test_pickle_continulet_real_subclass')
+ sys.modules['test_pickle_continulet_real_subclass'] = mod
+ mod.version = self.version
+ exec '''if 1:
+ from _continuation import continulet
+ import pickle
+ class A(continulet):
+ def __init__(self):
+ crash
+ def f(co):
+ co.switch(co.x + 1)
+ co.switch(co.x + 2)
+ return co.x + 3
+ co = A.__new__(A)
+ continulet.__init__(co, f)
+ co.x = 40
+ res = co.switch()
+ assert res == 41
+ pckl = pickle.dumps(co, version)
+ print repr(pckl)
+ co2 = pickle.loads(pckl)
+ #
+ assert type(co2) is A
+ res = co2.switch()
+ assert res == 42
+ assert co2.is_pending()
+ res = co2.switch()
+ assert res == 43
+ assert not co2.is_pending()
+ #
+ res = co.switch()
+ assert res == 42
+ assert co.is_pending()
+ res = co.switch()
+ assert res == 43
+ assert not co.is_pending()
+ ''' in mod.__dict__
+
class AppTestPickle_v1(AppTestPickle):
version = 1
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit