pty.spawn() and friends
Chris Gonnerman
chris.gonnerman at newcenturycomputers.net
Sat Dec 29 12:39:42 EST 2001
----- Original Message -----
From: "James T. Dennis" <jadestar at idiom.com>
> I've been trying to learn more Python and I've been sticking with
> the somewhat obscure kinds of things that I've routinely needed to
> do as a system administrator. I came across the pty module as a
> primitive alternative to using expect and it seems like I should
> be able to so simple work with it.
>
> So naturally I tried to implement the simplext expect script
> (autopasswd) as a Python script using the pty.spawn() function.
>
> This doesn't work as I'd expect.
I about pulled a cranial muscle understanding the pty.spawn() code;
evidently it runs a subprocess which communicates via callbacks.
If you give no callback arguments, it does indeed behave much
like os.system().
> ... well it certainly baffles the programmer that tries to use it.
No kidding. Ouch.
> My expectation was that this would spawn the program in question
> ("/usr/bin/passwd" for my tests) and allow me to print to its
> input and read from its output; under programmatic control. I
> would thus have to cross-wire the inputs and outputs of the child
> process with some sort of handle, object, or file descriptor on
> my (parent) process.
To do this, you need to roll a wrapper function using pty.fork().
> However it seem like pty.spawn() doesn't do any cross-wiring.
It does, if you use the callbacks.
> It seems to simply start a sub-process that interacts with my
> terminal, basically like the os.system() function. (The
> difference is that pty.spawn() takes a tuple of arguments while
Huh? Three arguments does not a tuple make (at least from the
caller's point-of-view.
> os.system() takes a string and passes it to a shell for parsing
> and execution).
>
> That seems pretty lame. It's like the author of the pty module
> didn't know what the author of the os module was doing and
> provided a gratuitously similar function with no actual relevance
> to psuedo-ttys and no additional functionality. In so doing,
> they've raised (my) expectations and failed to satisfy them.
Explained above.
> What pty.spawn() *should* do (to meet with reasonable expectations
> that it would have something to do with spawning subprocesses
> *UNDER THE CONTROL OF A psudo-tty*) is return a file-like object
> to which one can write (commands or "keystrokes") and from which
> one could read (responses, prompts, potentially screen updates).
Also explained above.
I'm not real sure why it was done this way; the callback method
is not my first choice. It might interact well with GUI code,
though.
> Ideally this would come with some convenience methods, and
> members/constants (possibly inherited from a common module with
> curses, and/or tty, to allow one to send keystrokes by their
> symbol names (rather than having to manually fuss with escape
> sequences) and receive data as structures of character/attribute
> data). (Imagine being able to run a child ncurses monitoring
> process and automatically programmatically respond to a specific
> bit of text "turning red" or "going on the blink").
Sounds good. When will you post the code? :-) :-) [humor,ar,ar]
> None of this would be nearly so irritating if USAGE EXAMPLES had
> been provide to explain what the programmer should expect of the
> program.
Ditto here!
> Naturally I had to fuss with it for some time before figure out
> that it really was a lame and redundant function rather than my
> own lack of skill. The fact that the reference docs give a couple
> of optional arguments: [,master_read[,stdin_read]] which are
> supposed to be:
>
> functions which read from a file-descriptor
>
> ... complicates it further. What kind of function could I write
> that "reads from a file-descriptor" but which takes no arguments
> telling it *which* file-descriptor!
CALLBACKS. You implement a function like so:
def my_read_callback(fd, nbytes):
# your code here.
and the pty.spawn() function calls it, assuming you do this:
pty.spawn(my_argv, my_read_callback, my_std_read_callback)
(for instance).
> At first I thought this was trying to say to call pty.spawn() with
> one argument to act sort of like os.system(), or two arguments
> (a tuple and a function invocation) to spawn a process under the
> control of that function. (Envisioning something where *that
> function's* stdin and stdout where wired up to the spawned
> process' stdout and stdin respectively). (If that was the case
> I'd expect that the optional third argument would be another
> controlling function for handling the child process' stderr;
> communications between the two would be "merely a matter of
> programming").
Hopefully my explanation makes this clearer. Handling stderr
*would* be nice... (or does handling stdout also handle stderr
with pty's? I haven't tried it.)
> Ugh! Between this and the equally frustrating Python curses docs
> I'm pretty grumpy.
curses is called that for a reason. ;-)
If you aren't a curses programmer at the C level it is certainly
hard to understand.
More information about the Python-list
mailing list