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
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
10 from Rpyc.Factories import SocketConnection
\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
16 from Rpyc.Utils import *
\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
23 # so let's connect to the server
\r
25 c = SocketConnection("localhost", 22222)
\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
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
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
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
53 print c.modules.sys.path
\r
54 c.modules.sys.path.append("lucy")
\r
55 print c.modules.sys.path[-1]
\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
61 rsys = c.modules.sys
\r
66 # and as you might expect, netproxies also look like the real objects
\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
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
79 # now for a demo of packages
\r
80 # (which looks very much like 'from xml.dom.minidom import parseString')
\r
82 parseString = c.modules.xml.dom.minidom.parseString
\r
83 x = parseString("<a>lala</a>")
\r
86 print x.firstChild.nodeName
\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
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
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
103 # but if you need to be explicit, you can, and it works like this:
\r
106 c.modules["xml.dom.minidom"].parseString("<a></a>")
\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
116 # and now for a little demo of working with files (a common task)
\r
118 f = c.modules.__builtin__.open("lala.txt", "w")
\r
121 c.modules.os.remove("lala.txt")
\r
124 # now to a bitter part of life: exceptions. as you could expect, they work just like
\r
125 # regular exceptions
\r
128 a = c.modules.sys.nonexistent_attribute
\r
129 except AttributeError:
\r
135 a = c.modules.__builtin__.open("**\\//##~~..::!@#$%^&*()_+\n <,>?")
\r