Skip to content

Commit fc467af

Browse files
committed
Clarify subtle behaviours of cmd.Cmd in documentation
1 parent 1834741 commit fc467af

File tree

1 file changed

+18
-307
lines changed

1 file changed

+18
-307
lines changed

Doc/library/cmd.rst

Lines changed: 18 additions & 307 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ interface.
4545
.. versionchanged:: 3.13
4646
``completekey='tab'`` is replaced by ``'^I'`` for ``editline``.
4747

48+
.. note::
49+
50+
Subtle behaviors of ``cmd.Cmd``:
51+
52+
* Command handler methods (``do_<command>``) should return ``True`` to
53+
indicate that the command loop should terminate. Any other return
54+
value continues the loop.
55+
56+
* If the user presses Enter on an empty line, the default behavior is
57+
to repeat the last nonempty command entered. This can be disabled by
58+
overriding :meth:`emptyline`.
59+
60+
* If no matching ``do_<command>`` method is found, the
61+
:meth:`default` method is called.
62+
63+
* Exceptions raised inside command handlers are not caught by default
64+
and will terminate the command loop unless handled explicitly.
65+
4866

4967
.. _cmd-objects:
5068

@@ -92,310 +110,3 @@ A :class:`Cmd` instance has the following methods:
92110
the current input line with leading whitespace removed, *begidx* and *endidx*
93111
are the beginning and ending indexes of the prefix text, which could be used to
94112
provide different completion depending upon which position the argument is in.
95-
96-
97-
.. method:: Cmd.do_help(arg)
98-
99-
All subclasses of :class:`Cmd` inherit a predefined :meth:`!do_help`. This
100-
method, called with an argument ``'bar'``, invokes the corresponding method
101-
:meth:`!help_bar`, and if that is not present, prints the docstring of
102-
:meth:`!do_bar`, if available. With no argument, :meth:`!do_help` lists all
103-
available help topics (that is, all commands with corresponding
104-
:meth:`!help_\*` methods or commands that have docstrings), and also lists any
105-
undocumented commands.
106-
107-
108-
.. method:: Cmd.onecmd(str)
109-
110-
Interpret the argument as though it had been typed in response to the prompt.
111-
This may be overridden, but should not normally need to be; see the
112-
:meth:`precmd` and :meth:`postcmd` methods for useful execution hooks. The
113-
return value is a flag indicating whether interpretation of commands by the
114-
interpreter should stop. If there is a :meth:`!do_\*` method for the command
115-
*str*, the return value of that method is returned, otherwise the return value
116-
from the :meth:`default` method is returned.
117-
118-
119-
.. method:: Cmd.emptyline()
120-
121-
Method called when an empty line is entered in response to the prompt. If this
122-
method is not overridden, it repeats the last nonempty command entered.
123-
124-
125-
.. method:: Cmd.default(line)
126-
127-
Method called on an input line when the command prefix is not recognized. If
128-
this method is not overridden, it prints an error message and returns.
129-
130-
131-
.. method:: Cmd.completedefault(text, line, begidx, endidx)
132-
133-
Method called to complete an input line when no command-specific
134-
:meth:`!complete_\*` method is available. By default, it returns an empty list.
135-
136-
137-
.. method:: Cmd.columnize(list, displaywidth=80)
138-
139-
Method called to display a list of strings as a compact set of columns.
140-
Each column is only as wide as necessary.
141-
Columns are separated by two spaces for readability.
142-
143-
144-
.. method:: Cmd.precmd(line)
145-
146-
Hook method executed just before the command line *line* is interpreted, but
147-
after the input prompt is generated and issued. This method is a stub in
148-
:class:`Cmd`; it exists to be overridden by subclasses. The return value is
149-
used as the command which will be executed by the :meth:`onecmd` method; the
150-
:meth:`precmd` implementation may re-write the command or simply return *line*
151-
unchanged.
152-
153-
154-
.. method:: Cmd.postcmd(stop, line)
155-
156-
Hook method executed just after a command dispatch is finished. This method is
157-
a stub in :class:`Cmd`; it exists to be overridden by subclasses. *line* is the
158-
command line which was executed, and *stop* is a flag which indicates whether
159-
execution will be terminated after the call to :meth:`postcmd`; this will be the
160-
return value of the :meth:`onecmd` method. The return value of this method will
161-
be used as the new value for the internal flag which corresponds to *stop*;
162-
returning false will cause interpretation to continue.
163-
164-
165-
.. method:: Cmd.preloop()
166-
167-
Hook method executed once when :meth:`cmdloop` is called. This method is a stub
168-
in :class:`Cmd`; it exists to be overridden by subclasses.
169-
170-
171-
.. method:: Cmd.postloop()
172-
173-
Hook method executed once when :meth:`cmdloop` is about to return. This method
174-
is a stub in :class:`Cmd`; it exists to be overridden by subclasses.
175-
176-
177-
Instances of :class:`Cmd` subclasses have some public instance variables:
178-
179-
.. attribute:: Cmd.prompt
180-
181-
The prompt issued to solicit input.
182-
183-
184-
.. attribute:: Cmd.identchars
185-
186-
The string of characters accepted for the command prefix.
187-
188-
189-
.. attribute:: Cmd.lastcmd
190-
191-
The last nonempty command prefix seen.
192-
193-
194-
.. attribute:: Cmd.cmdqueue
195-
196-
A list of queued input lines. The cmdqueue list is checked in
197-
:meth:`cmdloop` when new input is needed; if it is nonempty, its elements
198-
will be processed in order, as if entered at the prompt.
199-
200-
201-
.. attribute:: Cmd.intro
202-
203-
A string to issue as an intro or banner. May be overridden by giving the
204-
:meth:`cmdloop` method an argument.
205-
206-
207-
.. attribute:: Cmd.doc_header
208-
209-
The header to issue if the help output has a section for documented commands.
210-
211-
212-
.. attribute:: Cmd.misc_header
213-
214-
The header to issue if the help output has a section for miscellaneous help
215-
topics (that is, there are :meth:`!help_\*` methods without corresponding
216-
:meth:`!do_\*` methods).
217-
218-
219-
.. attribute:: Cmd.undoc_header
220-
221-
The header to issue if the help output has a section for undocumented commands
222-
(that is, there are :meth:`!do_\*` methods without corresponding :meth:`!help_\*`
223-
methods).
224-
225-
226-
.. attribute:: Cmd.ruler
227-
228-
The character used to draw separator lines under the help-message headers. If
229-
empty, no ruler line is drawn. It defaults to ``'='``.
230-
231-
232-
.. attribute:: Cmd.use_rawinput
233-
234-
A flag, defaulting to true. If true, :meth:`cmdloop` uses :func:`input` to
235-
display a prompt and read the next command; if false, :data:`sys.stdout.write() <sys.stdout>`
236-
and :data:`sys.stdin.readline() <sys.stdin>` are used. (This means that by importing
237-
:mod:`readline`, on systems that support it, the interpreter will automatically
238-
support :program:`Emacs`\ -like line editing and command-history keystrokes.)
239-
240-
241-
.. _cmd-example:
242-
243-
Cmd Example
244-
-----------
245-
246-
.. sectionauthor:: Raymond Hettinger <python at rcn dot com>
247-
248-
The :mod:`cmd` module is mainly useful for building custom shells that let a
249-
user work with a program interactively.
250-
251-
This section presents a simple example of how to build a shell around a few of
252-
the commands in the :mod:`turtle` module.
253-
254-
Basic turtle commands such as :meth:`~turtle.forward` are added to a
255-
:class:`Cmd` subclass with method named :meth:`!do_forward`. The argument is
256-
converted to a number and dispatched to the turtle module. The docstring is
257-
used in the help utility provided by the shell.
258-
259-
The example also includes a basic record and playback facility implemented with
260-
the :meth:`~Cmd.precmd` method which is responsible for converting the input to
261-
lowercase and writing the commands to a file. The :meth:`!do_playback` method
262-
reads the file and adds the recorded commands to the :attr:`~Cmd.cmdqueue` for
263-
immediate playback::
264-
265-
import cmd, sys
266-
from turtle import *
267-
268-
class TurtleShell(cmd.Cmd):
269-
intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n'
270-
prompt = '(turtle) '
271-
file = None
272-
273-
# ----- basic turtle commands -----
274-
def do_forward(self, arg):
275-
'Move the turtle forward by the specified distance: FORWARD 10'
276-
forward(*parse(arg))
277-
def do_right(self, arg):
278-
'Turn turtle right by given number of degrees: RIGHT 20'
279-
right(*parse(arg))
280-
def do_left(self, arg):
281-
'Turn turtle left by given number of degrees: LEFT 90'
282-
left(*parse(arg))
283-
def do_goto(self, arg):
284-
'Move turtle to an absolute position with changing orientation. GOTO 100 200'
285-
goto(*parse(arg))
286-
def do_home(self, arg):
287-
'Return turtle to the home position: HOME'
288-
home()
289-
def do_circle(self, arg):
290-
'Draw circle with given radius an options extent and steps: CIRCLE 50'
291-
circle(*parse(arg))
292-
def do_position(self, arg):
293-
'Print the current turtle position: POSITION'
294-
print('Current position is %d %d\n' % position())
295-
def do_heading(self, arg):
296-
'Print the current turtle heading in degrees: HEADING'
297-
print('Current heading is %d\n' % (heading(),))
298-
def do_color(self, arg):
299-
'Set the color: COLOR BLUE'
300-
color(arg.lower())
301-
def do_undo(self, arg):
302-
'Undo (repeatedly) the last turtle action(s): UNDO'
303-
def do_reset(self, arg):
304-
'Clear the screen and return turtle to center: RESET'
305-
reset()
306-
def do_bye(self, arg):
307-
'Stop recording, close the turtle window, and exit: BYE'
308-
print('Thank you for using Turtle')
309-
self.close()
310-
bye()
311-
return True
312-
313-
# ----- record and playback -----
314-
def do_record(self, arg):
315-
'Save future commands to filename: RECORD rose.cmd'
316-
self.file = open(arg, 'w')
317-
def do_playback(self, arg):
318-
'Playback commands from a file: PLAYBACK rose.cmd'
319-
self.close()
320-
with open(arg) as f:
321-
self.cmdqueue.extend(f.read().splitlines())
322-
def precmd(self, line):
323-
line = line.lower()
324-
if self.file and 'playback' not in line:
325-
print(line, file=self.file)
326-
return line
327-
def close(self):
328-
if self.file:
329-
self.file.close()
330-
self.file = None
331-
332-
def parse(arg):
333-
'Convert a series of zero or more numbers to an argument tuple'
334-
return tuple(map(int, arg.split()))
335-
336-
if __name__ == '__main__':
337-
TurtleShell().cmdloop()
338-
339-
340-
Here is a sample session with the turtle shell showing the help functions, using
341-
blank lines to repeat commands, and the simple record and playback facility:
342-
343-
.. code-block:: none
344-
345-
Welcome to the turtle shell. Type help or ? to list commands.
346-
347-
(turtle) ?
348-
349-
Documented commands (type help <topic>):
350-
========================================
351-
bye color goto home playback record right
352-
circle forward heading left position reset undo
353-
354-
(turtle) help forward
355-
Move the turtle forward by the specified distance: FORWARD 10
356-
(turtle) record spiral.cmd
357-
(turtle) position
358-
Current position is 0 0
359-
360-
(turtle) heading
361-
Current heading is 0
362-
363-
(turtle) reset
364-
(turtle) circle 20
365-
(turtle) right 30
366-
(turtle) circle 40
367-
(turtle) right 30
368-
(turtle) circle 60
369-
(turtle) right 30
370-
(turtle) circle 80
371-
(turtle) right 30
372-
(turtle) circle 100
373-
(turtle) right 30
374-
(turtle) circle 120
375-
(turtle) right 30
376-
(turtle) circle 120
377-
(turtle) heading
378-
Current heading is 180
379-
380-
(turtle) forward 100
381-
(turtle)
382-
(turtle) right 90
383-
(turtle) forward 100
384-
(turtle)
385-
(turtle) right 90
386-
(turtle) forward 400
387-
(turtle) right 90
388-
(turtle) forward 500
389-
(turtle) right 90
390-
(turtle) forward 400
391-
(turtle) right 90
392-
(turtle) forward 300
393-
(turtle) playback spiral.cmd
394-
Current position is 0 0
395-
396-
Current heading is 0
397-
398-
Current heading is 180
399-
400-
(turtle) bye
401-
Thank you for using Turtle

0 commit comments

Comments
 (0)