embedding python cli in python scripts

Just in case you ever wanted to debug your python service interactively, and pdb did not do the job you've been looking for, how about the standard python interpreter on stdin?

The one below basically wraps PyRun_InteractiveOne via ctypes, sets some tty modes, things not that interesting, they just have to work.

But, it even autocompletes on tab, and restores the tty settings via atexit.

Combined with objgraph1), this is was rather valueable to me. For objgraph, use python 3.3 and replace __name__ in objgraph with __qualname__2).

Given I was unable to find something, here is the code.

pyev3) can be replaced with your favourite event loop easily - it is just a single socket to poll for readability.

cli.py
#!/usr/bin/python3.2
 
import pyev
import sys
 
class cli:
	def __init__(self, loop):
		sys.ps1 = ">>>"
		sys.ps2 = "..."
 
		import ctypes
		libc = ctypes.cdll.LoadLibrary("libc.so.6")
		libc.fdopen.restype = ctypes.c_void_p
		libc.fdopen.argtype = [ctypes.c_int, ctypes.c_char_p]
		self.stdin = libc.fdopen(sys.stdin.fileno(),"r")
		self._io = pyev.Io(sys.stdin.fileno(), pyev.EV_READ, loop, self._io_cb)
		self._io.start()
 
		import termios
		# [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] 
		self.read_termios = termios.tcgetattr(sys.stdin.fileno());
		self.poll_termios = termios.tcgetattr(sys.stdin.fileno());
 
		self.read_termios[3] |=  (termios.ICANON|termios.ECHOCTL|termios.ECHO);
		self.poll_termios[3] &= ~(termios.ICANON|termios.ECHOCTL|termios.ECHO);
 
		try:
			import readline
		except ImportError:
			print("Module readline not available.")
		else:
			import rlcompleter
			readline.parse_and_bind("tab: complete")
 
		import atexit
		atexit.register(self._atexit)
 
	def _atexit(self):		
		self.mode(self.read_termios)
 
	def setblocking(self,blocking):
		import fcntl
		import os
		if blocking == True:
			fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
		else:
			fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL) & ~os.O_NONBLOCK)
 
	def mode(self, m):
		import termios
		termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, m)
 
	def _io_cb(self, watcher, revents):
		from ctypes import pythonapi
		self.mode(self.read_termios)
#		self.setblocking(False)
#		nonblocking stdin causes very interesting problems here!
 
		pythonapi.PyRun_InteractiveOne(self.stdin, b"<stdin>")
 
#		self.setblocking(True)
#		even if disabled during runtime operation
 
		self.mode(self.poll_termios)
 
if __name__ == '__main__':
	loop = pyev.default_loop()
	c = cli(loop)
 
	def signals(watcher, revents):
		watcher.loop.stop()
 
	import signal
	sigint = pyev.Signal(signal.SIGINT, loop, signals)
	sigint.start()
 
	loop.start()
	sys.exit(0)
1) objgraph is a module that lets you visually explore Python object graphs.
3) pyev Python libev interface

Comments



2012/05/15/embedding_python_cli_in_python_scripts.txt · Last modified: 2012/05/16 08:17 by common
chimeric.de = chi`s home Creative Commons License Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0