Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Pyro4 fun: Controlling your PC from Pythonista
-
Hi,
one of my goals with Pythonista is to write programs on iPad that run more complex computations on a PC or Mac host. One of the ways to do this is via Remote Procedure Calls (RPCs). There are some fairly powerful packages available for Python, such as Pyro4 or RPyC. They allow to do RPCs in a fashion that makes the actual RPC almost invisible.
Using the recipe outlined below, using Pyro4, I have been able to run a Pyro server on my PC, and run Python code on that PC controlled from an Ipad running the client in Pythonista. The client code looks like this:
# connect to server flame = Pyro4.utils.flame.connect(hostname+":9999") # get remote module, and print name of remote host on iPad socketmodule = flame.module("socket") print("remote host name=", socketmodule.gethostname())
Run on the iPad this outputs "rosette", the name of my Windows host.
It also works the other way round, but frankly I ran into a couple of problems like being unable to stop the server process (it locks in sock.accept()), or a blocked socket that only goes away after a timeout. I guess an iPad is not the ideal server platform...
Below the recipe for installing the packages, some example code and example output.
Enjoy,
Georg- I used a Windows PC as a host. Mac, Linux, others should work as well.
- I used Pythonista 1.6 Beta on an old iPad. Pythonista 1.5 on other iOS devices should work as well.
- install Python 2.7 on your PC. I am using the Anaconda distribution, but any Python 2.7 should do.
- Install serpent and Pyro4 on your PC. Use the commands "pip install serpent" and "pip install Pyro4".
- install serpent into Pythonista. I have been using the "pip" that comes with stash. Use "pip install serpent"
- install Pyro4 into Pythonista. Due to this problem you cannot use pip for installing Pyro4. Instead, download the .tgz file from PyPi, and copy src/Pyro4 to site-packages.
- Run the server on your PC, and the client on the iPad. You need to adapt the hostname in the client code ("rosetta" in my case).
Server Code:
""" Abridged version of the flameserver.py file delivered with pyro4, see https://pythonhosted.org/Pyro4/flame.html """ from __future__ import division,absolute_import,print_function,unicode_literals import sys import platform import Pyro4.utils.flame import Pyro4.core def main(): host=platform.node() port=9999 print("Warning: Anyone can connect to this server!") Pyro4.config.FLAME_ENABLED=True Pyro4.config.SERIALIZERS_ACCEPTED = set(["pickle"]) # flame requires pickle serializer, doesn't work with the others. daemon = Pyro4.core.Daemon(host=host, port=port, unixsocket=False) uri = Pyro4.utils.flame.start(daemon) print("server uri is: %s" % uri) daemon.requestLoop() daemon.close() return 0 if __name__ == "__main__": sys.exit(main())
Client Code:
""" Modified from Pyro4 documentation https://pythonhosted.org/Pyro4/flame.html """ from __future__ import division,absolute_import,print_function,unicode_literals import traceback import sys import Pyro4.utils.flame # enter hostname of your server here hostname="rosetta" #hostname="georgs-ipad" Pyro4.config.SERIALIZER = "pickle" # flame requires pickle serializer flame = Pyro4.utils.flame.connect(hostname+":9999") # connect to server # get remote modules, and print values locally socketmodule = flame.module("socket") osmodule = flame.module("os") print("remote host name=", socketmodule.gethostname()) print("remote server directory contents=", osmodule.listdir(".")) # evaluate expresion on server flame.execute("import math") root = flame.evaluate("math.sqrt(500)") print("calculated square root=", root) # test exception handling. Exceptions triggered on remote system, forwarded to local system sys.stdout.flush() #to avoid mix of stdout/err on some systems try: print("remote exceptions also work", flame.evaluate("1//0")) except ZeroDivisionError as e: print("caught remote ZeroDivisionError:",e) traceback.print_exc() #time.sleep(1) # print something on the remote std output flame.builtin("print")("Hello there, remote server stdout!") print("evaluate interactive lines on remote server. End with ^D.") with flame.console() as console: console.interact()
Server Output on PC:
Warning: Anyone can connect to this server! server uri is: PYRO:Pyro.Flame@Rosetta:9999 Hello there, remote server stdout!
Client Output on iPad:
remote host name= Rosetta remote server directory contents= [u'.idea', u'myFlameClient.py', u'myFlameServer.py'] calculated square root= 22.360679775 caught remote ZeroDivisionError: integer division or modulo by zero Traceback (most recent call last): File "/var/mobile/Containers/Data/Application/8CDD2B5A-ED81-4ABF-A782-843F20FB5CF7/Documents/Net/Pyro4Test/myFlameClient.py", line 29, in <module> print("remote exceptions also work", flame.evaluate("1//0")) File "/var/mobile/Containers/Data/Application/8CDD2B5A-ED81-4ABF-A782-843F20FB5CF7/Documents/site-packages/Pyro4/core.py", line 171, in __call__ return self.__send(self.__name, args, kwargs) File "/var/mobile/Containers/Data/Application/8CDD2B5A-ED81-4ABF-A782-843F20FB5CF7/Documents/site-packages/Pyro4/core.py", line 426, in _pyroInvoke raise data ZeroDivisionError: integer division or modulo by zero evaluate interactive lines on remote server. End with ^D. Python 2.7.10 |Anaconda 2.3.0 (64-bit)| (default, May 28 2015, 16:44:52) [MSC v.1500 64 bit (AMD64)] on win32 (Remote console on Rosetta:9999) >>> import platform >>> platform.uname() ('Windows', 'Rosetta', '8', '6.2.9200', 'AMD64', 'Intel64 Family 6 Model 60 Stepping 3, GenuineIntel') >>> (Remote session ended)