Updated version of [ 558544 ] cmd.py: add instance-specific stdin/out
This patch adds stdin, stdout as optional arguments to the cmd.Cmd constructor (defaulting to sys.stdin, sys.stdout), and changes the Cmd methods throughout to use self.stdout.write() and self.stdin.foo for output and input. This allows much greater flexibility for using cmd - for instance, hooking it into a telnet server. Patch for library module and for documentation.
This commit is contained in:
parent
985eba53f5
commit
983b008824
|
@ -11,17 +11,23 @@ line-oriented command interpreters. These are often useful for
|
||||||
test harnesses, administrative tools, and prototypes that will
|
test harnesses, administrative tools, and prototypes that will
|
||||||
later be wrapped in a more sophisticated interface.
|
later be wrapped in a more sophisticated interface.
|
||||||
|
|
||||||
\begin{classdesc}{Cmd}{\optional{completekey}}
|
\begin{classdesc}{Cmd}{\optional{completekey},\optional{stdin},\optional{stdout}}
|
||||||
A \class{Cmd} instance or subclass instance is a line-oriented
|
A \class{Cmd} instance or subclass instance is a line-oriented
|
||||||
interpreter framework. There is no good reason to instantiate
|
interpreter framework. There is no good reason to instantiate
|
||||||
\class{Cmd} itself; rather, it's useful as a superclass of an
|
\class{Cmd} itself; rather, it's useful as a superclass of an
|
||||||
interpreter class you define yourself in order to inherit
|
interpreter class you define yourself in order to inherit
|
||||||
\class{Cmd}'s methods and encapsulate action methods.
|
\class{Cmd}'s methods and encapsulate action methods.
|
||||||
|
|
||||||
The optional argument is the \refmodule{readline} name of a completion
|
The optional argument \var{completekey} is the \refmodule{readline} name
|
||||||
key; it defaults to \kbd{Tab}. If \var{completekey} is not \code{None}
|
of a completion key; it defaults to \kbd{Tab}. If \var{completekey} is
|
||||||
and \module{readline} is available, command completion is done
|
not \code{None} and \module{readline} is available, command completion
|
||||||
automatically.
|
is done automatically.
|
||||||
|
|
||||||
|
The optional arguments \var{stdin} and \var{stdout} specify the
|
||||||
|
input and output file objects that the Cmd instance or subclass
|
||||||
|
instance will use for input and output. If not specified, they
|
||||||
|
will default to \var{sys.stdin} and \var{sys.stdout}.
|
||||||
|
|
||||||
\end{classdesc}
|
\end{classdesc}
|
||||||
|
|
||||||
\subsection{Cmd Objects}
|
\subsection{Cmd Objects}
|
||||||
|
|
51
Lib/cmd.py
51
Lib/cmd.py
|
@ -45,7 +45,7 @@ These interpreters use raw_input; thus, if the readline module is loaded,
|
||||||
they automatically support Emacs-like command history and editing features.
|
they automatically support Emacs-like command history and editing features.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import string, sys
|
import string
|
||||||
|
|
||||||
__all__ = ["Cmd"]
|
__all__ = ["Cmd"]
|
||||||
|
|
||||||
|
@ -76,15 +76,26 @@ class Cmd:
|
||||||
nohelp = "*** No help on %s"
|
nohelp = "*** No help on %s"
|
||||||
use_rawinput = 1
|
use_rawinput = 1
|
||||||
|
|
||||||
def __init__(self, completekey='tab'):
|
def __init__(self, completekey='tab', stdin=None, stdout=None):
|
||||||
"""Instantiate a line-oriented interpreter framework.
|
"""Instantiate a line-oriented interpreter framework.
|
||||||
|
|
||||||
The optional argument is the readline name of a completion key;
|
The optional argument 'completekey' is the readline name of a
|
||||||
it defaults to the Tab key. If completekey is not None and the
|
completion key; it defaults to the Tab key. If completekey is
|
||||||
readline module is available, command completion is done
|
not None and the readline module is available, command completion
|
||||||
automatically.
|
is done automatically. The optional arguments stdin and stdout
|
||||||
|
specify alternate input and output file objects; if not specified,
|
||||||
|
sys.stdin and sys.stdout are used.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
|
if stdin is not None:
|
||||||
|
self.stdin = stdin
|
||||||
|
else:
|
||||||
|
self.stdin = sys.stdin
|
||||||
|
if stdout is not None:
|
||||||
|
self.stdout = stdout
|
||||||
|
else:
|
||||||
|
self.stdout = sys.stdout
|
||||||
self.cmdqueue = []
|
self.cmdqueue = []
|
||||||
self.completekey = completekey
|
self.completekey = completekey
|
||||||
|
|
||||||
|
@ -99,7 +110,7 @@ class Cmd:
|
||||||
if intro is not None:
|
if intro is not None:
|
||||||
self.intro = intro
|
self.intro = intro
|
||||||
if self.intro:
|
if self.intro:
|
||||||
print self.intro
|
self.stdout.write(str(self.intro)+"\n")
|
||||||
stop = None
|
stop = None
|
||||||
while not stop:
|
while not stop:
|
||||||
if self.cmdqueue:
|
if self.cmdqueue:
|
||||||
|
@ -111,9 +122,9 @@ class Cmd:
|
||||||
except EOFError:
|
except EOFError:
|
||||||
line = 'EOF'
|
line = 'EOF'
|
||||||
else:
|
else:
|
||||||
sys.stdout.write(self.prompt)
|
self.stdout.write(self.prompt)
|
||||||
sys.stdout.flush()
|
self.stdout.flush()
|
||||||
line = sys.stdin.readline()
|
line = self.stdin.readline()
|
||||||
if not len(line):
|
if not len(line):
|
||||||
line = 'EOF'
|
line = 'EOF'
|
||||||
else:
|
else:
|
||||||
|
@ -215,7 +226,7 @@ class Cmd:
|
||||||
returns.
|
returns.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
print '*** Unknown syntax:', line
|
self.stdout.write('*** Unknown syntax: %s\n'%line)
|
||||||
|
|
||||||
def completedefault(self, *ignored):
|
def completedefault(self, *ignored):
|
||||||
"""Method called to complete an input line when no command-specific
|
"""Method called to complete an input line when no command-specific
|
||||||
|
@ -284,11 +295,11 @@ class Cmd:
|
||||||
try:
|
try:
|
||||||
doc=getattr(self, 'do_' + arg).__doc__
|
doc=getattr(self, 'do_' + arg).__doc__
|
||||||
if doc:
|
if doc:
|
||||||
print doc
|
self.stdout.write("%s\n"%str(doc))
|
||||||
return
|
return
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
print self.nohelp % (arg,)
|
self.stdout.write("%s\n"%str(self.nohelp % (arg,)))
|
||||||
return
|
return
|
||||||
func()
|
func()
|
||||||
else:
|
else:
|
||||||
|
@ -315,18 +326,18 @@ class Cmd:
|
||||||
cmds_doc.append(cmd)
|
cmds_doc.append(cmd)
|
||||||
else:
|
else:
|
||||||
cmds_undoc.append(cmd)
|
cmds_undoc.append(cmd)
|
||||||
print self.doc_leader
|
self.stdout.write("%s\n"%str(self.doc_leader))
|
||||||
self.print_topics(self.doc_header, cmds_doc, 15,80)
|
self.print_topics(self.doc_header, cmds_doc, 15,80)
|
||||||
self.print_topics(self.misc_header, help.keys(),15,80)
|
self.print_topics(self.misc_header, help.keys(),15,80)
|
||||||
self.print_topics(self.undoc_header, cmds_undoc, 15,80)
|
self.print_topics(self.undoc_header, cmds_undoc, 15,80)
|
||||||
|
|
||||||
def print_topics(self, header, cmds, cmdlen, maxcol):
|
def print_topics(self, header, cmds, cmdlen, maxcol):
|
||||||
if cmds:
|
if cmds:
|
||||||
print header
|
self.stdout.write("%s\n"%str(header))
|
||||||
if self.ruler:
|
if self.ruler:
|
||||||
print self.ruler * len(header)
|
self.stdout.write("%s\n"%str(self.ruler * len(header)))
|
||||||
self.columnize(cmds, maxcol-1)
|
self.columnize(cmds, maxcol-1)
|
||||||
print
|
self.stdout.write("\n")
|
||||||
|
|
||||||
def columnize(self, list, displaywidth=80):
|
def columnize(self, list, displaywidth=80):
|
||||||
"""Display a list of strings as a compact set of columns.
|
"""Display a list of strings as a compact set of columns.
|
||||||
|
@ -335,7 +346,7 @@ class Cmd:
|
||||||
Columns are separated by two spaces (one was not legible enough).
|
Columns are separated by two spaces (one was not legible enough).
|
||||||
"""
|
"""
|
||||||
if not list:
|
if not list:
|
||||||
print "<empty>"
|
self.stdout.write("<empty>\n")
|
||||||
return
|
return
|
||||||
nonstrings = [i for i in range(len(list))
|
nonstrings = [i for i in range(len(list))
|
||||||
if not isinstance(list[i], str)]
|
if not isinstance(list[i], str)]
|
||||||
|
@ -344,7 +355,7 @@ class Cmd:
|
||||||
", ".join(map(str, nonstrings)))
|
", ".join(map(str, nonstrings)))
|
||||||
size = len(list)
|
size = len(list)
|
||||||
if size == 1:
|
if size == 1:
|
||||||
print list[0]
|
self.stdout.write('%s\n'%str(list[0]))
|
||||||
return
|
return
|
||||||
# Try every row count from 1 upwards
|
# Try every row count from 1 upwards
|
||||||
for nrows in range(1, len(list)):
|
for nrows in range(1, len(list)):
|
||||||
|
@ -382,4 +393,4 @@ class Cmd:
|
||||||
del texts[-1]
|
del texts[-1]
|
||||||
for col in range(len(texts)):
|
for col in range(len(texts)):
|
||||||
texts[col] = texts[col].ljust(colwidths[col])
|
texts[col] = texts[col].ljust(colwidths[col])
|
||||||
print " ".join(texts)
|
self.stdout.write("%s\n"%str(" ".join(texts)))
|
||||||
|
|
Loading…
Reference in New Issue