Running TCL code (on an existing TCL shell) from Python - python

Introduction
I recently started working on a legacy product, under Linux, which incorporates a builtin TCL shell. Due to company limitations, I can't gain control to "behind the scenes" and all of the code I can write must be run under this TCL shell, handling the pre-defined clumsy TCL API of the product.
I found myself wondering a few times whether it will be possible to patch some Python into this setup, as some solutions seem more legitimate in Python than in TCL. By patching Python I mean: either calling the Python code from the TCL code itself (which can be done with Elmer, for example), or to use Python from outside of the product to wrap the TCL API (for which I found no "classic" solution).
The Problem
Given that the product already has an existing TCL shell in it, most solutions I browsed through (e.g. Tkinter) can't be used to run the TCL code from Python. I need to "inject" the code to the existing shell.
Solutions Considered
As a solution, I thought about bringing up a simple server on the TCL side which runs simple commands it receives from the Python side. I wrote a small demo and it worked. This enabled me to write a nice, class based, wrapper in Python for the clumsy TCL API, also manage a command queue, etc.
Another two solutions I thought of is forking the software from Python and playing with the read/write file descriptors or connecting through FIFO rather than a socket.
However, I wondered whether I'm actually doing it right or can you suggest a better solution?
Thanks in advance.

First:
If you just want a class based OO system to write your code in, you don't need python, Tcl can do OO just fine. (built in with 8.6, but there are quite a few options to get OO features, classes etc. in older versions too, e.g. Tcllibs SNIT or STOOOP
If you still feel Python is the superior tool for the task at hand (e.g. due to better library support for some tasks), you can 'remote control' the Tcl interpreter using the Tcllib comm package. This needs a working event loop in the Tcl shell you want to control, but otherwise it is pretty simple to do.
In your Tcl shell, install the Tcllib comm package.
(ask again if you need help with that)
Once you have that, start the comm server in your Tcl shell.
package require comm
set id [::comm::comm self]
# write ID to a file
set fd [open idfile.txt w]
puts $fd $id
close $fd
proc stop_server {} {set ::forever 1 }
# enter the event loop
vwait forever
On the python side, you do nearly the same, just in Tkinter code.
Basically like this:
import Tkinter
interp = Tkinter.Tcl()
interp.eval('package require comm')
# load the id
with open('idfile.txt') as fd:
comm_id = fd.read().strip()
result = interp.eval(
'comm::comm send {0!s} {1!s}'.format(comm_id, '{puts "Hello World"}')
Using that python code and your shell, you should see Hello World printed in your shell.
Read the comm manual for more details, how to secure things, get callbacks etc. comm
If you don't like the tkinter burden, you can implement the wire procotol for comm too, should not be too hard in Twisted or with the new async support in Python 3.x.
The on the wire protocol is documented in:
comm wire protocol

Related

Python script to interact with fdisk prompts automatically

This Python program enters fdisk. I see the output. fdisk is an interactive program. How do I get the Python program to pass an "m" to the first field and press enter?
import subprocess
a = "dev/sda"
x = subprocess.call(["fdisk", a])
print x
I'd rather not import a new module/library, but I could. I've tried different syntax with subprocess.call() and extra parameters in the above. Nothing seems to work. I get different errors. I've reviewed Python documentation. I want to feed input and press Enter in the subsequent, interactive menu options of fdisk.
Check out the pexpect library (I know you didn't want an extra module, but you want to use the best tool for the job). It's pure Python, with no compiled submodules, so installation is a snap. Basically, it does the same thing in Python as the classic Unix utility expect - spawns child applications, controls them, and responds to expected patterns in their output. It's great for automation, and especially application testing, where you can quickly feed the newest build of a command-line program a series of inputs and guide the interaction based on what output appears.
In case you just don't want another module at all, you can always fall back on the subprocess module's Popen() constructor. It spawns and creates a connection to a child process, allowing you to communicate with it as needed, and in fact pexpect relies a great deal on it. I personally think using pexpect is more intuitive than subprocess.Popen(), but that's just me. YMMV.

Insert keypresses into the Linux console from Python

I have recently been faced with a rather odd task, one result being the necessity for the ability to use DTMF (aka "Touch Tone") tones to control a non-X Linux computer's terminal. The computer has a modem which can be accessed through ALSA, and therefore the sox "rec" program, which is what I am reading the input through. The computer in question is otherwise completely isolated, having no Ethernet or other network interfaces whatsoever. The Goertzel algorithm implementation I am using works very well, as does the eSpeak speech synthesis engine which is the only source of output; this is supposed to work with any Touch Tone phone. It reads back both input (input being octal digits, one ASCII byte at a time)and whatever the dash shell feeds back -- the prompt, the output from commands, etc., using ASCII mnemonics for control characters.
The current method that I am using for interacting with dash and the programs launched through it is the pexpect module. However, I need it to be able to, on demand, read back the entire contents of the line on which the cursor is positioned, and I do not recall pexpect being able to do this (If it is, I cannot tell.). The only other solution that I can think of is to somehow use Python to either control, or act as, the keyboard and console drivers.
Is this, indeed, the only way to go about it (and if so, is it even possible with Python?), or is there another way of having direct access to the contents of the console?
Edit: Through dumb luck, I just recently found that the SVN version of PExpect has pexpect.screen. However, it does not have any way of actually running a program under it. I'll have to keep an eye on its development.
The simple solution is to use the Linux kernel uinput interface. It allows you to insert keypresses and mouse events into the kernel, exactly as if they came from a physical human interface device. This would basically turn your application into a keyboard/mouse.
Since you are working with Python, I recommend you take a look at the python-uinput module.
If you are comfortable with binary I/O in Python, then you can certainly do the same without any libraries; just check out the /usr/include/linux/uinput.h header file for the structures involved (the interface is completely stable), and perhaps some uinput tutorials in C, too.
Note that accessing the /dev/uinput or /dev/input/uinput device (depending on your distribution) normally requires root privileges. I would personally run the Python service as a user and group dedicated to the service, and modify/add a udev rule (check all files under rules.d) to allow read-write access to the uinput device to that group, something like
SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id"
KERNEL=="uinput", MODE="0660", GROUP="the-dedicated-group"
However, if your Python application simply executes programs, you should make it a terminal emulator -- for example, using this. You can do it too without any extra libraries, using the Python pty; the main work is to however simulate a terminal with ANSI escape sequences, so that applications don't get confused, and the existing terminal emulators have such code.
If you want to manipulate the contents of the console, you probably want to use curses. It's well documented here. Look at window.getch() and window.getyx().

Is there anyway to hook up Python/Tkinter to an already running Tcl/Tk app?

I work a lot on Pure Data, an app written in Tcl/Tk and C. I'd like to be able to make a python API for plugins for modifying the Tcl/Tk GUI. To do this, it seems that I would need to be able to pass the running Tk instance to python, then have Tkinter use that Tcl/Tk instance for its commands. So something like:
root = Tk(pid_of_running_app)
Take a look at the send command, you can do exactly that (to Tk applications, not plain Tcl applications). I do this all the time from my Emacs (connect to running Tk applications).
Tcl/Tk won't let you enslave another process, however using the send command, you can easily send over any commands you want to. Just find the "name" of the other interpreter by using [winfo interps] (note: the name of your Tk application can be gotten/set by [tk appname]. At which point, any command you want to have executed in the other interpreter would be sent over by evaluating
send $other_app tk_dialog . "Sample Dialog" "See, it's this easy." "" 0 Ok
The options are to use Tk's built-in send infrastructure (as Trey mentions) or to use the comm package from Tcllib. It should be possible to talk the comm protocol directly from Python, but I've never looked into the details so you might as well lead the way.
You could use sockets to communicate between the 2 apps.

Send emacs buffer to arbitrary Python process

I like the python-send-buffer command, however I very often use Python embedded in applications, or launch Python via a custom package management system (to launch Python with certain dependencies).. In other words, I can't just run "python" and get a useful Python instance (something that python-send-buffer relies on)
What I would like to achieve is:
in any Python interpreter (or application that allows you to evaluate Python code), import a magic_emacs_python_server.py module (appending to sys.path as necessary)
In emacs, run magic-emacs-python-send-buffer
This would evaluate the buffer in the remote Python instance.
Seems like it should be pretty simple - the Python module listens on a socket, in a thread. It evaluates in the main thread, and returns the repr() of the result (or maybe captures the stdout/stderr, or maybe both). The emacs module would just send text to the socket, waits for a string in response, and displays it in a buffer.
Sounds so simple something like this must exist already... IPython has ipy_vimserver, but this is the wrong way around. There is also swank, while it seems very Lisp-specific, there is a Javascript backend which looks very like what I want... but searching finds almost nothing, other than some vague (possibly true) claims that SLIME doesn't work nicely with non-Lisp languages
In short:
Does a project exist to send code from an emacs buffer to an existing Python process?
If not, how would you recommend I write such a thing (not being very familiar with elisp) - SWANK? IPython's server code? Simple TCP server from scratch?
comint provides most of the infrastructure for stuff like this. There's a bunch of good examples, like this or this
It allows you to run a command, provides things comint-send-string to easily implement send-region type commands.
dbr/remoterepl on Github is a crude proof-of-concept of what I described in the question.
It lacks any kind of polish, but it mostly works - you import the replify.py module in the target interpreter, then evaluate the emacs-remote-repl.el after fixing the stupid hardcoded path to client.py
Doesn't shell-command give you what you are looking for? You could write a wrapper script or adjust the #! and sys.path appropriately.

Accessing a Panatone Huey via Python

I have a Panatone Huey, a monitor calibration probe (device you attach to the monitor, and it gives you colour readings) - I want to get readings from the device in Python.
Having never written such a device driver before, I'm not sure where to start.
I've found are two open-source C/C++ projects that interface with the Heuy - ArgyllCMS and mcalib.
ArgyllCMS comes with a spotread command which returns readings from the device, although it only functions as an interactive command line tool, so running it via subprocess will not (easily) work.
The code ArgyllCMS uses to communicate with the device is in spectro/huey.c
Not tried it (only just found it while writing this question), but mcalib contains much less code, mainly just heuy.cpp - however it has a worrying number of FIXME comments and incomplete methods, and the code appears to have been automatically generated (unhelpful variable names)
There seems to be three options:
Modify spotread to work without any interactive prompts, call it via subprocess
Create a C-based Python module around huey.c or huey.cpp
Re-implement the interface using something like PyUSB
Being much more familiar with Python, I'm tempted to use PyUSB, but will this be substantially more work than wrapping existing code with the Python C API? Is there anything obvious in either of the C implementations that will not be easily doable in PyUSB?
Given the existence of spotread the easiest (though perhaps not the best) way to proceed would be to use pexpect. It allows you to interact with other command-line programs.

Categories

Resources