[svn r80] DEV-9309: Support python object copy through saranwrap. Also tweaked comment on event.send to better reflect actual semantics.
This commit is contained in:
@@ -83,8 +83,8 @@ class event(object):
|
|||||||
0, greenlib.switch, waiter, None, Cancelled())
|
0, greenlib.switch, waiter, None, Cancelled())
|
||||||
|
|
||||||
def send(self, result=None, exc=None):
|
def send(self, result=None, exc=None):
|
||||||
"""Resume all previous and further
|
"""Makes arrangements for the waiters to be woken with the
|
||||||
calls to wait() with result.
|
result and then returns immediately to the parent.
|
||||||
"""
|
"""
|
||||||
assert self._result is NOT_USED
|
assert self._result is NOT_USED
|
||||||
self._result = result
|
self._result = result
|
||||||
|
@@ -397,6 +397,19 @@ not need to deal with this class directly."""
|
|||||||
# see description for __repr__, len(obj) is the same.
|
# see description for __repr__, len(obj) is the same.
|
||||||
return self.__len__()
|
return self.__len__()
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo=None):
|
||||||
|
"""Copies the entire external object and returns its
|
||||||
|
value. Will only work if the remote object is pickleable."""
|
||||||
|
my_cp = self.__local_dict['_cp']
|
||||||
|
my_id = self.__local_dict['_id']
|
||||||
|
request = Request('copy', {'id':my_id})
|
||||||
|
return my_cp.make_request(request)
|
||||||
|
|
||||||
|
# since the remote object is being serialized whole anyway,
|
||||||
|
# there's no semantic difference between copy and deepcopy
|
||||||
|
__copy__ = __deepcopy__
|
||||||
|
|
||||||
|
|
||||||
def proxied_type(self):
|
def proxied_type(self):
|
||||||
if type(self) is not ObjectProxy:
|
if type(self) is not ObjectProxy:
|
||||||
return type(self)
|
return type(self)
|
||||||
@@ -444,60 +457,60 @@ when the id is None."""
|
|||||||
self._next_id = 1
|
self._next_id = 1
|
||||||
self._objects = {}
|
self._objects = {}
|
||||||
|
|
||||||
def handle_status(self, object, req):
|
def handle_status(self, obj, req):
|
||||||
return {
|
return {
|
||||||
'object_count':len(self._objects),
|
'object_count':len(self._objects),
|
||||||
'next_id':self._next_id,
|
'next_id':self._next_id,
|
||||||
'pid':os.getpid()}
|
'pid':os.getpid()}
|
||||||
|
|
||||||
def handle_getattr(self, object, req):
|
def handle_getattr(self, obj, req):
|
||||||
try:
|
try:
|
||||||
return getattr(object, req['attribute'])
|
return getattr(obj, req['attribute'])
|
||||||
except AttributeError, e:
|
except AttributeError, e:
|
||||||
if hasattr(object, "__getitem__"):
|
if hasattr(obj, "__getitem__"):
|
||||||
return object[req['attribute']]
|
return obj[req['attribute']]
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
#_log('getattr: %s' % str(response))
|
#_log('getattr: %s' % str(response))
|
||||||
|
|
||||||
def handle_setattr(self, object, req):
|
def handle_setattr(self, obj, req):
|
||||||
try:
|
try:
|
||||||
return setattr(object, req['attribute'], req['value'])
|
return setattr(obj, req['attribute'], req['value'])
|
||||||
except AttributeError, e:
|
except AttributeError, e:
|
||||||
if hasattr(object, "__setitem__"):
|
if hasattr(obj, "__setitem__"):
|
||||||
return object.__setitem__(req['attribute'], req['value'])
|
return obj.__setitem__(req['attribute'], req['value'])
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def handle_getitem(self, object, req):
|
def handle_getitem(self, obj, req):
|
||||||
return object[req['key']]
|
return obj[req['key']]
|
||||||
|
|
||||||
def handle_setitem(self, object, req):
|
def handle_setitem(self, obj, req):
|
||||||
object[req['key']] = req['value']
|
obj[req['key']] = req['value']
|
||||||
return None # *TODO figure out what the actual return value of __setitem__ should be
|
return None # *TODO figure out what the actual return value of __setitem__ should be
|
||||||
|
|
||||||
def handle_eq(self, object, req):
|
def handle_eq(self, obj, req):
|
||||||
#_log("__eq__ %s %s" % (object, req))
|
#_log("__eq__ %s %s" % (obj, req))
|
||||||
rhs = None
|
rhs = None
|
||||||
try:
|
try:
|
||||||
rhs = self._objects[req['rhs']]
|
rhs = self._objects[req['rhs']]
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
return False
|
return False
|
||||||
return (object == rhs)
|
return (obj == rhs)
|
||||||
|
|
||||||
def handle_call(self, object, req):
|
def handle_call(self, obj, req):
|
||||||
#_log("calling %s " % (req['name']))
|
#_log("calling %s " % (req['name']))
|
||||||
try:
|
try:
|
||||||
fn = getattr(object, req['name'])
|
fn = getattr(obj, req['name'])
|
||||||
except AttributeError, e:
|
except AttributeError, e:
|
||||||
if hasattr(object, "__setitem__"):
|
if hasattr(obj, "__setitem__"):
|
||||||
fn = object[req['name']]
|
fn = obj[req['name']]
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
return fn(*req['args'],**req['kwargs'])
|
return fn(*req['args'],**req['kwargs'])
|
||||||
|
|
||||||
def handle_del(self, object, req):
|
def handle_del(self, obj, req):
|
||||||
id = req['id']
|
id = req['id']
|
||||||
_log("del %s from %s" % (id, self._objects))
|
_log("del %s from %s" % (id, self._objects))
|
||||||
|
|
||||||
@@ -505,11 +518,14 @@ when the id is None."""
|
|||||||
del self._objects[id]
|
del self._objects[id]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def handle_type(self, object, req):
|
def handle_type(self, obj, req):
|
||||||
return type(object)
|
return type(obj)
|
||||||
|
|
||||||
def handle_nonzero(self, object, req):
|
def handle_nonzero(self, obj, req):
|
||||||
return bool(object)
|
return bool(obj)
|
||||||
|
|
||||||
|
def handle_copy(self, obj, req):
|
||||||
|
return obj
|
||||||
|
|
||||||
def loop(self):
|
def loop(self):
|
||||||
"""@brief Loop forever and respond to all requests."""
|
"""@brief Loop forever and respond to all requests."""
|
||||||
@@ -524,20 +540,20 @@ when the id is None."""
|
|||||||
_log("request: %s (%s)" % (request, self._objects))
|
_log("request: %s (%s)" % (request, self._objects))
|
||||||
req = request
|
req = request
|
||||||
id = None
|
id = None
|
||||||
object = None
|
obj = None
|
||||||
try:
|
try:
|
||||||
id = req['id']
|
id = req['id']
|
||||||
if id:
|
if id:
|
||||||
id = int(id)
|
id = int(id)
|
||||||
object = self._objects[id]
|
obj = self._objects[id]
|
||||||
#_log("id, object: %d %s" % (id, object))
|
#_log("id, object: %d %s" % (id, obj))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
#_log("Exception %s" % str(e))
|
#_log("Exception %s" % str(e))
|
||||||
pass
|
pass
|
||||||
if object is None or id is None:
|
if obj is None or id is None:
|
||||||
id = None
|
id = None
|
||||||
object = self._export
|
obj = self._export
|
||||||
#_log("found object %s" % str(object))
|
#_log("found object %s" % str(obj))
|
||||||
|
|
||||||
# Handle the request via a method with a special name on the server
|
# Handle the request via a method with a special name on the server
|
||||||
handler_name = 'handle_%s' % request.action()
|
handler_name = 'handle_%s' % request.action()
|
||||||
@@ -547,11 +563,11 @@ when the id is None."""
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise BadRequest, request.action()
|
raise BadRequest, request.action()
|
||||||
|
|
||||||
response = handler(object, request)
|
response = handler(obj, request)
|
||||||
|
|
||||||
# figure out what to do with the response, and respond
|
# figure out what to do with the response, and respond
|
||||||
# apprpriately.
|
# apprpriately.
|
||||||
if request.action() in ['status', 'type']:
|
if request.action() in ['status', 'type', 'copy']:
|
||||||
# have to handle these specially since we want to
|
# have to handle these specially since we want to
|
||||||
# pickle up the actual value and not return a proxy
|
# pickle up the actual value and not return a proxy
|
||||||
self.respond(['value', response])
|
self.respond(['value', response])
|
||||||
@@ -627,7 +643,7 @@ def main():
|
|||||||
description="Simple saranwrap.Server wrapper")
|
description="Simple saranwrap.Server wrapper")
|
||||||
parser.add_option(
|
parser.add_option(
|
||||||
'-c', '--child', default=False, action='store_true',
|
'-c', '--child', default=False, action='store_true',
|
||||||
help='Wrap an object serialed via setattr.')
|
help='Wrap an object serialized via setattr.')
|
||||||
parser.add_option(
|
parser.add_option(
|
||||||
'-m', '--module', type='string', dest='module', default=None,
|
'-m', '--module', type='string', dest='module', default=None,
|
||||||
help='a module to load and export.')
|
help='a module to load and export.')
|
||||||
|
@@ -281,6 +281,19 @@ sys_path = sys.path""")
|
|||||||
for waiter in waiters:
|
for waiter in waiters:
|
||||||
waiter.wait()
|
waiter.wait()
|
||||||
|
|
||||||
|
def test_copy(self):
|
||||||
|
import copy
|
||||||
|
compound_object = {'a':[1,2,3]}
|
||||||
|
prox = saranwrap.wrap(compound_object)
|
||||||
|
def make_assertions(copied):
|
||||||
|
self.assert_(isinstance(copied, dict))
|
||||||
|
self.assert_(isinstance(copied['a'], list))
|
||||||
|
self.assertEquals(copied, compound_object)
|
||||||
|
self.assertNotEqual(id(compound_object), id(copied))
|
||||||
|
|
||||||
|
make_assertions(copy.copy(prox))
|
||||||
|
make_assertions(copy.deepcopy(prox))
|
||||||
|
|
||||||
def test_list_of_functions(self):
|
def test_list_of_functions(self):
|
||||||
return # this test is known to fail, we can implement it sometime in the future if we wish
|
return # this test is known to fail, we can implement it sometime in the future if we wish
|
||||||
from eventlet import saranwrap_test
|
from eventlet import saranwrap_test
|
||||||
|
Reference in New Issue
Block a user