--- /dev/null
+import sys\r
+import traceback\r
+import cPickle as pickle\r
+from weakref import WeakValueDictionary\r
+from Lib import ImmDict\r
+from NetProxy import NetProxy, SyncNetProxy\r
+\r
+\r
+class BoxingError(Exception):\r
+ pass\r
+class NestedException(Exception): \r
+ pass\r
+\r
+PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL\r
+TYPE_SIMPLE = 0\r
+TYPE_PROXY = 1\r
+TYPE_TUPLE = 2\r
+TYPE_SLICE = 3\r
+TYPE_LOCAL_PROXY = 4\r
+TYPE_IMMDICT = 5\r
+simple_types = (\r
+ bool, \r
+ int, \r
+ long, \r
+ float, \r
+ complex, \r
+ basestring, \r
+ type(None),\r
+)\r
+\r
+def dump_exception(typ, val, tb):\r
+ """dumps the given exception using pickle (since not all exceptions are picklable)"""\r
+ tbtext = "".join(traceback.format_exception(typ, val, tb))\r
+ sys.last_type, sys.last_value, sys.last_traceback = typ, val, tb\r
+ try:\r
+ pickled_exc = pickle.dumps((typ, val, tbtext), PICKLE_PROTOCOL)\r
+ except pickle.PicklingError, ex:\r
+ newval = NestedException("pickling error %s\nexception type: %r\nexception object: %s" % (ex, typ, val))\r
+ pickled_exc = pickle.dumps((NestedException, newval, tbtext), PICKLE_PROTOCOL)\r
+ return pickled_exc\r
+\r
+def load_exception(package):\r
+ """returns an exception object"""\r
+ try:\r
+ return pickle.loads(package)\r
+ except pickle.PicklingError, ex:\r
+ return NestedException("failed to unpickle remote exception -- %r" % (ex,))\r
+\r
+class Box(object):\r
+ """a box is where local objects are stored, and remote proxies are created"""\r
+ def __init__(self, conn):\r
+ self.conn = conn\r
+ self.objects = {}\r
+ self.proxy_cache = WeakValueDictionary()\r
+\r
+ def close(self):\r
+ del self.conn\r
+ del self.objects\r
+ del self.proxy_cache\r
+ \r
+ def __getitem__(self, oid):\r
+ return self.objects[oid][1]\r
+\r
+ def _box(self, obj):\r
+ if isinstance(obj, simple_types):\r
+ return TYPE_SIMPLE, obj\r
+ elif isinstance(obj, slice):\r
+ return TYPE_SLICE, (obj.start, obj.stop, obj.step)\r
+ elif isinstance(obj, NetProxy) and obj.__dict__["____conn"] is self.conn:\r
+ return TYPE_LOCAL_PROXY, obj.__dict__["____oid"]\r
+ elif isinstance(obj, tuple):\r
+ if obj:\r
+ return TYPE_TUPLE, [self._box(subobj) for subobj in obj]\r
+ else:\r
+ return TYPE_SIMPLE, ()\r
+ elif isinstance(obj, ImmDict):\r
+ if not obj.dict:\r
+ return TYPE_SIMPLE, {}\r
+ else:\r
+ return TYPE_IMMDICT, [(self._box(k), self._box(v)) for k, v in obj.items()]\r
+ else:\r
+ oid = id(obj)\r
+ if oid not in self.objects:\r
+ self.objects[oid] = [0, obj]\r
+ return TYPE_PROXY, oid\r
+ \r
+ def _unbox(self, (type, value)):\r
+ if type == TYPE_SIMPLE:\r
+ return value\r
+ elif type == TYPE_TUPLE:\r
+ return tuple([self._unbox(subobj) for subobj in value])\r
+ elif type == TYPE_SLICE:\r
+ return slice(*value)\r
+ elif type == TYPE_LOCAL_PROXY:\r
+ return self[value]\r
+ elif type == TYPE_IMMDICT:\r
+ return dict([(self._unbox(k), self._unbox(v)) for k, v in value])\r
+ elif type == TYPE_PROXY:\r
+ if value in self.proxy_cache:\r
+ proxy = self.proxy_cache[value]\r
+ else:\r
+ proxy = SyncNetProxy(self.conn, value)\r
+ self.proxy_cache[value] = proxy\r
+ return proxy\r
+ else:\r
+ raise BoxingError("invalid boxed object type", type, value)\r
+ \r
+ def incref(self, oid):\r
+ self.objects[oid][0] += 1\r
+\r
+ def decref(self, oid):\r
+ self.objects[oid][0] -= 1\r
+ if self.objects[oid][0] <= 0:\r
+ del self.objects[oid]\r
+ \r
+ def pack(self, obj):\r
+ """packs an object (returns a package)"""\r
+ return pickle.dumps(self._box(obj), PICKLE_PROTOCOL)\r
+\r
+ def unpack(self, package):\r
+ """unpacks a package (returns an object)"""\r
+ return self._unbox(pickle.loads(package))\r
+\r
+\r