ea1c5a187b77e8532b49419c78f93b5a97309cad
[monitor.git] / Rpyc / Demo / demo-1.py
1 #\r
2 # welcome to RPyC. this demo serves as an introduction. i believe in learning through\r
3 # showcases, and that's why this package comes with a demo subpackage, instead of\r
4 # documentation\r
5\r
6 # so, the first thing we're gonna do is import the SocketConnection. this is a factory\r
7 # function that returns us a new Connection object over a socket stream. we dont need\r
8 # to get into details here.\r
9 #\r
10 from Rpyc.Factories import SocketConnection\r
11 \r
12 #\r
13 # next, we'll get all the helpful utilities. the utilities include wrappers for builtin\r
14 # functions, like dir(), so they'd work as expected with netproxies. \r
15 #\r
16 from Rpyc.Utils import *\r
17 \r
18 #\r
19 # by now you should have an rpyc server running. if you dont, go to the Servers directory\r
20 # and choose your favorite version of a socket server. for unixes i'd recommend the \r
21 # forking server; for windows -- the threaded server.\r
22 #\r
23 # so let's connect to the server\r
24 #\r
25 c = SocketConnection("localhost", 22222)\r
26 \r
27 #\r
28 # now it's time to explain a little about how rpyc works. it's quite simple really. the\r
29 # magic comes from a concept called NetProxy. a NetProxy object delivers all of the\r
30 # operations performed on it to the remote object. so if you get a list from your host,\r
31 # what you're are really getting is a NetProxy to that list. it looks and works just\r
32 # like a real list -- but everytime you do something on it, it actually performs a \r
33 # request on the list object stored on the host. this is called boxing. this means\r
34 # you can change the object you get locally, and the remote object changes, etc.\r
35 #\r
36 # however, for efficiency and other reason, not all objects you get are NetProxies.\r
37 # all immutable and pickle-able objects pass by value (through pickle). these types\r
38 # of objects include ints, longs, strings, and some other types. all other types are\r
39 # passed by boxing.\r
40 #\r
41 # this boxing mechanism works on everything -- objects, functions, classes, and modules,\r
42 # which is why rpyc is considered transparent. your code looks just as if it was meant \r
43 # to run locally.\r
44 #\r
45 \r
46 #\r
47 # let's start with something simple -- getting a remote module.  accessing the remote \r
48 # namespace always starts with the `modules` attribute, then the module (or package) \r
49 # name, and then the attribute you want to get.\r
50 #\r
51 \r
52 print c.modules.sys\r
53 print c.modules.sys.path \r
54 c.modules.sys.path.append("lucy")\r
55 print c.modules.sys.path[-1]\r
56 \r
57 #\r
58 # these remote objects are first class objects, like all others in python. this means\r
59 # you can store them in variables, pass them as parameters, etc.\r
60 #\r
61 rsys = c.modules.sys\r
62 rpath = rsys.path\r
63 rpath.pop(-1)\r
64 \r
65 #\r
66 # and as you might expect, netproxies also look like the real objects\r
67 #\r
68 print dir(rpath)\r
69 \r
70 #\r
71 # but there are a couple of issues with netproxies. the type(), isinstance(), and \r
72 # issubclass() classes dont work on them... as they query the underlying object, not\r
73 # the remote one. so:\r
74 #\r
75 print type(rsys.maxint) # <int> -- because it's a simple type which is passed by value)\r
76 print type(rsys.path)   # <SyncNetProxy> -- because, after all, it's a netproxy, not a list\r
77 \r
78 #\r
79 # now for a demo of packages\r
80 # (which looks very much like 'from xml.dom.minidom import parseString')\r
81 #\r
82 parseString = c.modules.xml.dom.minidom.parseString\r
83 x = parseString("<a>lala</a>")\r
84 print x\r
85 x.toxml()\r
86 print x.firstChild.nodeName\r
87 \r
88 #\r
89 # however, there's a catch when working with packages like that. the way it works is\r
90 # trying to find an attribute with that name, and if not found, trying to import a sub-\r
91 # module. \r
92 #\r
93 # now in english:\r
94 # c.module.xml is the xml module of the server. when you do c.module.xml.dom, rpyc looks\r
95 # for an attribute named 'dom' inside the xml module. since there's no such attribute,\r
96 # it tries to import a subpackage called xml.dom, which succeeds. then it does the same\r
97 # for xml.dom.minidom, and xml.dom.minidom.parseString.\r
98 #\r
99 # but there are times when that's ambiguous. this mean that the module has both a sub-\r
100 # module called 'X', and an attribute called 'X'. according to rpyc's algorithm, the\r
101 # attribute 'X' is returned, not the sub-module.\r
102 #\r
103 # but if you need to be explicit, you can, and it works like this:\r
104 #\r
105 \r
106 c.modules["xml.dom.minidom"].parseString("<a></a>")\r
107 \r
108 #\r
109 # this will make sure the module 'xml.dom.minidom' is returned, and not an attribute.\r
110 # in general, it's better to use this form, unless you know there are no such conflicts.\r
111 # remeber that "Explicit is better than implicit", although it requires four more key\r
112 # strokes. perhaps in a later version it will raise an exception if there's a conflict.\r
113 #\r
114 \r
115 #\r
116 # and now for a little demo of working with files (a common task)\r
117 #\r
118 f = c.modules.__builtin__.open("lala.txt", "w")\r
119 f.write("lucy")\r
120 f.close()\r
121 c.modules.os.remove("lala.txt")\r
122 \r
123 #\r
124 # now to a bitter part of life: exceptions. as you could expect, they work just like\r
125 # regular exceptions\r
126 #\r
127 try:\r
128     a = c.modules.sys.nonexistent_attribute\r
129 except AttributeError:\r
130     pass\r
131 else:\r
132     assert False\r
133 \r
134 try:\r
135     a = c.modules.__builtin__.open("**\\//##~~..::!@#$%^&*()_+\n <,>?")\r
136 except IOError:\r
137     pass\r
138 else:\r
139     assert False\r
140 \r
141 print "goodbye"\r
142 \r
143 \r
144 \r
145 \r
146 \r
147 \r
148 \r
149 \r
150 \r
151 \r
152 \r
153 \r
154 \r
155 \r
156 \r