clearer names for actions, and infer actions better
[monitor.git] / monitor / Rpyc / NetProxy.py
1 from Lib import ImmDict\r
2 \r
3 \r
4 def fully_dynamic_metaclass(name, bases, dict):\r
5     """\r
6     a meta class that enables special methods to be accessed like regular names \r
7     (via __getattr__), like it used to be in old-style classes.\r
8     """\r
9 \r
10     special_methods = [\r
11         "__hash__", "__len__", "__iter__", "next", "__reversed__",\r
12         "__add__", "__iadd__", "__radd__", "__sub__", "__isub__", "__rsub__", "__mul__",\r
13         "__imul__", "__rmul__", "__div__", "__idiv__", "__rdiv__", "__truediv__", \r
14         "__itruediv__", "__rtruediv__",  "__floordiv__", "__ifloordiv__", "__rfloorfiv__", \r
15         "__pow__", "__ipow__", "__rpow__", "__lshift__", "__ilshift__", "__rlshift__",\r
16         "__rshift__", "__irshift__", "__rrshift__", "__and__", "__iand__", "__rand__",\r
17         "__or__", "__ior__", "__ror__", "__xor__", "__ixor__", "__rxor__", "__mod__", \r
18         "__imod__", "__rmod__", "__divmod__", "__idivmod__", "__rdivmod__", "__pos__", \r
19         "__neg__", "__int__", "__float__", "__long__", "__oct__", "__hex__", "__coerce__",\r
20         "__eq__", "__ne__", "__le__", "__ge__", "__lt__", "__gt__", "__cmp__",\r
21     ]\r
22     \r
23     # i added '__class__' to the special attributes, but it broke some things \r
24     # (like dir), so we'll have to live without it\r
25     special_attributes = ["__doc__", "__module__"] \r
26 \r
27     def make_method(name):\r
28         def caller(self, *a, **k):\r
29             return self.__getattr__(name)(*a, **k)\r
30         return caller\r
31 \r
32     def make_property(name):\r
33         def getter(self):\r
34             return self.__getattr__(name)\r
35         def setter(self, value):\r
36             self.__setattr__(name, value)\r
37         def deller(self):\r
38             self.__delattr__(name)\r
39         return property(getter, setter, deller)\r
40 \r
41     classdict = {}\r
42     for sn in special_methods:\r
43         classdict[sn] = make_method(sn)\r
44     classdict.update(dict)\r
45     for sa in special_attributes:\r
46         classdict[sa] = make_property(sa)\r
47     return type(name, bases, classdict)\r
48 \r
49 class NetProxy(object):\r
50     """NetProxy - convey local operations to the remote object. this is an abstract class"""\r
51     __metaclass__ = fully_dynamic_metaclass\r
52     \r
53     def __init__(self, conn, oid):\r
54         self.__dict__["____conn"] = conn\r
55         self.__dict__["____oid"] = oid\r
56 \r
57     def __request__(self, handler, *args):\r
58         raise NotImplementedError()\r
59 \r
60     def __call__(self, *args, **kwargs):\r
61         return self.__request__("handle_call", args, ImmDict(kwargs))\r
62 \r
63     def __delattr__(self, *args):\r
64         return self.__request__("handle_delattr", *args)\r
65     def __getattr__(self, *args):\r
66         return self.__request__("handle_getattr", *args)\r
67     def __setattr__(self, *args):\r
68         return self.__request__("handle_setattr", *args)\r
69     \r
70     def __delitem__(self, *args):\r
71         return self.__request__("handle_delitem", *args)\r
72     def __getitem__(self, *args):\r
73         return self.__request__("handle_getitem", *args)\r
74     def __setitem__(self, *args):\r
75         return self.__request__("handle_setitem", *args)\r
76     \r
77     # special cases\r
78     def __repr__(self, *args):\r
79         return self.__request__("handle_repr", *args)\r
80     def __str__(self, *args):\r
81         return self.__request__("handle_str", *args)\r
82     def __nonzero__(self, *args):\r
83         return self.__request__("handle_bool", *args)\r
84 \r
85 class NetProxyWrapper(NetProxy):\r
86     """a netproxy that wraps an inner netproxy"""\r
87     __doc__ = NetProxy.__doc__\r
88 \r
89     def __init__(self, proxy):\r
90         NetProxy.__init__(self, proxy.__dict__["____conn"], proxy.__dict__["____oid"])\r
91         # we must keep the original proxy alive\r
92         self.__dict__["____original_proxy"] = proxy \r
93 \r
94 def _dummy_callback(*args, **kw):\r
95     pass\r
96 \r
97 class SyncNetProxy(NetProxy):\r
98     """the default, synchronous netproxy"""\r
99     __doc__ = NetProxy.__doc__\r
100 \r
101     def __init__(self, conn, oid):\r
102         NetProxy.__init__(self, conn, oid)\r
103         self.__dict__["____conn"].sync_request("handle_incref", self.__dict__["____oid"])\r
104 \r
105     def __del__(self):\r
106         try:\r
107             # decref'ing is done asynchronously, because we dont need to wait for the remote \r
108             # object to die. moreover, we dont care if it fails, because that would mean the \r
109             # connection is broken, so the remote object is already dead\r
110             self.__dict__["____conn"].async_request(_dummy_callback, "handle_decref", self.__dict__["____oid"])\r
111         except:\r
112             pass\r
113     \r
114     def __request__(self, handler, *args):\r
115         return self.__dict__["____conn"].sync_request(handler, self.__dict__["____oid"], *args)\r
116 \r
117 \r
118 \r
119 \r