3 import cPickle as pickle
\r
4 from weakref import WeakValueDictionary
\r
5 from Lib import ImmDict
\r
6 from NetProxy import NetProxy, SyncNetProxy
\r
9 class BoxingError(Exception):
\r
11 class NestedException(Exception):
\r
14 PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
\r
19 TYPE_LOCAL_PROXY = 4
\r
31 def dump_exception(typ, val, tb):
\r
32 """dumps the given exception using pickle (since not all exceptions are picklable)"""
\r
33 tbtext = "".join(traceback.format_exception(typ, val, tb))
\r
34 sys.last_type, sys.last_value, sys.last_traceback = typ, val, tb
\r
36 pickled_exc = pickle.dumps((typ, val, tbtext), PICKLE_PROTOCOL)
\r
37 except pickle.PicklingError, ex:
\r
38 newval = NestedException("pickling error %s\nexception type: %r\nexception object: %s" % (ex, typ, val))
\r
39 pickled_exc = pickle.dumps((NestedException, newval, tbtext), PICKLE_PROTOCOL)
\r
42 def load_exception(package):
\r
43 """returns an exception object"""
\r
45 return pickle.loads(package)
\r
46 except pickle.PicklingError, ex:
\r
47 return NestedException("failed to unpickle remote exception -- %r" % (ex,))
\r
50 """a box is where local objects are stored, and remote proxies are created"""
\r
51 def __init__(self, conn):
\r
54 self.proxy_cache = WeakValueDictionary()
\r
59 del self.proxy_cache
\r
61 def __getitem__(self, oid):
\r
62 return self.objects[oid][1]
\r
64 def _box(self, obj):
\r
65 if isinstance(obj, simple_types):
\r
66 return TYPE_SIMPLE, obj
\r
67 elif isinstance(obj, slice):
\r
68 return TYPE_SLICE, (obj.start, obj.stop, obj.step)
\r
69 elif isinstance(obj, NetProxy) and obj.__dict__["____conn"] is self.conn:
\r
70 return TYPE_LOCAL_PROXY, obj.__dict__["____oid"]
\r
71 elif isinstance(obj, tuple):
\r
73 return TYPE_TUPLE, [self._box(subobj) for subobj in obj]
\r
75 return TYPE_SIMPLE, ()
\r
76 elif isinstance(obj, ImmDict):
\r
78 return TYPE_SIMPLE, {}
\r
80 return TYPE_IMMDICT, [(self._box(k), self._box(v)) for k, v in obj.items()]
\r
83 if oid not in self.objects:
\r
84 self.objects[oid] = [0, obj]
\r
85 return TYPE_PROXY, oid
\r
87 def _unbox(self, (type, value)):
\r
88 if type == TYPE_SIMPLE:
\r
90 elif type == TYPE_TUPLE:
\r
91 return tuple([self._unbox(subobj) for subobj in value])
\r
92 elif type == TYPE_SLICE:
\r
93 return slice(*value)
\r
94 elif type == TYPE_LOCAL_PROXY:
\r
96 elif type == TYPE_IMMDICT:
\r
97 return dict([(self._unbox(k), self._unbox(v)) for k, v in value])
\r
98 elif type == TYPE_PROXY:
\r
99 if value in self.proxy_cache:
\r
100 proxy = self.proxy_cache[value]
\r
102 proxy = SyncNetProxy(self.conn, value)
\r
103 self.proxy_cache[value] = proxy
\r
106 raise BoxingError("invalid boxed object type", type, value)
\r
108 def incref(self, oid):
\r
109 self.objects[oid][0] += 1
\r
111 def decref(self, oid):
\r
112 self.objects[oid][0] -= 1
\r
113 if self.objects[oid][0] <= 0:
\r
114 del self.objects[oid]
\r
116 def pack(self, obj):
\r
117 """packs an object (returns a package)"""
\r
118 return pickle.dumps(self._box(obj), PICKLE_PROTOCOL)
\r
120 def unpack(self, package):
\r
121 """unpacks a package (returns an object)"""
\r
122 return self._unbox(pickle.loads(package))
\r