This page contains a collection of useful concepts and examples for developing with RPyC
Redirecting Standard Input/Output
You can "rewire" stdin, stdout and stderr between hosts. For example, if you want remote code that writes to stdout (on a remote tty) to print on your client's tty, you can do it like so:
>>> import rpyc >>> c = rpyc.classic.connect("localhost") >>> c.execute("print 'hi there'") # this will print on the host >>> import sys >>> c.modules.sys.stdout = sys.stdout >>> c.execute("print 'hi here'") # now this will be redirected here hi here
Also note that if you are using classic mode RPyC, you can use the context manager rpyc.classic.redirected_stdio:
>>> from __future__ import with_statement >>> c.execute("print 'hi there'") >>> >>> with rpyc.classic.redirected_stdio(c): ... c.execute("print 'hi here'") ... hi here >>> c.execute("print 'hi there again'") >>>

Debugging
If you are using the classic mode, you will be glad to know that you can debug remote exceptions with pdb:
>>> c = rpyc.classic.connect("localhost") >>> c.modules["xml.dom.minidom"].parseString("<<invalid xml>/>") ======= Remote traceback ======= Traceback (most recent call last): ... File "/usr/lib/python2.5/xml/dom/minidom.py", line 1925, in parseString return expatbuilder.parseString(string) File "/usr/lib/python2.5/xml/dom/expatbuilder.py", line 940, in parseString return builder.parseString(string) File "/usr/lib/python2.5/xml/dom/expatbuilder.py", line 223, in parseString parser.Parse(string, True) ExpatError: not well-formed (invalid token): line 1, column 1 ... File "/home/tomer/workspace/rpyc/core/protocol.py", line 298, in sync_request raise obj xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 1 >>> >>> rpyc.classic.pm(c) # start post-portem pdb > /usr/lib/python2.5/xml/dom/expatbuilder.py(226)parseString() -> pass (Pdb) l 221 parser = self.getParser() 222 try: 223 parser.Parse(string, True) 224 self._setup_subset(string) 225 except ParseEscape: 226 -> pass 227 doc = self.document 228 self.reset() 229 self._parser = None 230 return doc 231 (Pdb) w ... /home/tomer/workspace/rpyc/core/protocol.py(381)_handle_call() -> return self._local_objects[oid](*args, **dict(kwargs)) /usr/lib/python2.5/xml/dom/minidom.py(1925)parseString() -> return expatbuilder.parseString(string) /usr/lib/python2.5/xml/dom/expatbuilder.py(940)parseString() -> return builder.parseString(string) > /usr/lib/python2.5/xml/dom/expatbuilder.py(226)parseString() -> pass (Pdb)
Tunneling
Many times, especially in testing environments, you have subnets, VLANs, VPNs, and other separate networks, which may prevent you from establishing an IP connection between two machines in two different networks. This may be done for security reasons or to simulate the environment where your product will be running, but it also hinders your ability to conduct tests. However, with RPyC you can overcome this limitation very easily: simply use the remote machine's socket module!
Consider the following diagram:

Machine A is on network A, and it wants to connect to machine B on network B. Assuming there's a third machine (C) that has access to both networks (e.g., it has multiple NICs or belongs to multiple VLANs), all you have to do is run an RPyC server on it and you're ready to go.
# machine A: connect to machine C, which sees both networks >>> import rpyc >>> c = rpyc.classic.connect("machine-c") # from machine C: connect to machine B >>> s = c.modules.socket.socket() >>> s.connect(("machine-b", 12345))
If you have python utilities (i.e., tftp server, etc.) that make use of the socket module, and you want them to be able to serve on the remote network, you can use monkey-patching to solve the problem:
myserver.py
import socket import os # ... server code ...
run_my_server.py
import myserver import rpyc c = rpyc.classic.connect("machine-c") myserver.socket = c.modules.socket # <<< monkey-patch # ... run myserver, which will now open sockets on machine-c instead of the local machine
Monkey-Patching
As shown under Tunneling above, you can override (monkey-patch) modules, functions, and classes, transparently:
import mymodule import rpyc # ... mymodule.os = c.modules.os mymodule.open = c.modules.__builtin__.open mymodule.Telnet = c.modules.telnetlib.Telnet
So that when mymodule runs and makes use of the environment, the environment is that of the remote machine.







