author | Alberto Bertogli
<albertito@blitiri.com.ar> 2008-12-13 21:39:37 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2008-12-13 21:44:49 UTC |
parent | c2ba2eacf68af65375e32a3e47cfa80ab52e8c51 |
pickle_rpc.py | +49 | -7 |
samples/pickle_rpc/c1.py | +2 | -0 |
samples/pickle_rpc/s1.py | +14 | -0 |
diff --git a/pickle_rpc.py b/pickle_rpc.py index 1709183..f1c4ea6 100644 --- a/pickle_rpc.py +++ b/pickle_rpc.py @@ -84,12 +84,35 @@ class Server (object): socket.SO_REUSEADDR, 1) self.fds = [] self.functions = {} + self.objects = {} def register(self, func, name = None): if not name: name = func.__name__ self.functions[name] = func + def register_object(self, name, obj): + self.objects[name] = obj + + def find_method(self, chain): + chain = chain.split('.') + chain, fname = chain[:-1], chain[-1] + + # the first object is a special case because it comes from + # self.objects + if chain[0] not in self.objects: + return None + obj = self.objects[chain[0]] + + # walk through the object names + for oname in chain[1:]: + obj = getattr(obj, oname, None) + if obj is None: + return None + + # finally, return the function (if there is one) + return getattr(obj, fname, None) + def loop(self): self.sock.listen(15) while True: @@ -132,12 +155,20 @@ class Server (object): funcname = req[0] params = req[1] kwparams = req[2] - if funcname not in self.functions: + + if '.' in funcname: + # it's a method from (hopefully) one of our registered + # objects + func = self.find_method(funcname) + else: + func = self.functions.get(funcname, None) + + if func is None: self.send(fd, (replies.UNKNOWN,)) return try: - r = self.functions[funcname](*params, **kwparams) + r = func(*params, **kwparams) except: e, i, tb = sys.exc_info() strtb = traceback.format_exc() @@ -160,6 +191,20 @@ class Server (object): class UnknownFunction (Exception): pass + +class _ImObject (object): + "Intermediate object returned by Remote.__getattr__()" + def __init__(self, remote, name): + self.__remote = remote + self.__name = name + + def __call__(self, *args, **kwargs): + return self.__remote._rpc(self.__name, args, kwargs) + + def __getattr__(self, name): + return _ImObject(self.__remote, self.__name + '.' + name) + + class Remote (object): "Pickle-RPC client" def __init__(self, ip, port = default_port): @@ -174,12 +219,9 @@ class Remote (object): return self.__last_tb_str def __getattr__(self, name): - def stub_func(*args, **kwargs): - return self.__rpc(name, args, kwargs) - - return stub_func + return _ImObject(self, name) - def __rpc(self, name, args, kwargs): + def _rpc(self, name, args, kwargs): msg = (name, args, kwargs) pickle.dump(msg, self.__fd, -1) rep = pickle.load(self.__fd) diff --git a/samples/pickle_rpc/c1.py b/samples/pickle_rpc/c1.py index b7dc821..d03f002 100644 --- a/samples/pickle_rpc/c1.py +++ b/samples/pickle_rpc/c1.py @@ -10,6 +10,8 @@ try: except KeyError, info: print 'successfuly caught', KeyError, info +print cli.test2_i.t1.method("hi!", 1, 2, 3) + # the following causes an error unpickling on the server side, and it's useful # for testing that code path #class E(Exception): pass diff --git a/samples/pickle_rpc/s1.py b/samples/pickle_rpc/s1.py index c703071..25ffc38 100644 --- a/samples/pickle_rpc/s1.py +++ b/samples/pickle_rpc/s1.py @@ -14,9 +14,23 @@ def long(n): l.append((i, i + 1, i + 2, i + 3)) return l + +class Test1: + def __init__(self, n): + self.n = n + + def method(self, *args): + return (self.n, args) + +class Test2: + def __init__(self, t1): + self.t1 = t1 + + srv = pickle_rpc.Server('localhost') srv.register(f) srv.register(exc) srv.register(long) +srv.register_object("test2_i", Test2(Test1("inst1"))) srv.loop()