From fc467af20d8326d82712da195e698533dd2a3957 Mon Sep 17 00:00:00 2001 From: Aryan Chawla Date: Mon, 2 Feb 2026 03:11:17 +0530 Subject: [PATCH] Clarify subtle behaviours of cmd.Cmd in documentation --- Doc/library/cmd.rst | 325 +++----------------------------------------- 1 file changed, 18 insertions(+), 307 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst index 66544f82f6ff3f..d33f1437b43743 100644 --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -45,6 +45,24 @@ interface. .. versionchanged:: 3.13 ``completekey='tab'`` is replaced by ``'^I'`` for ``editline``. + .. note:: + + Subtle behaviors of ``cmd.Cmd``: + + * Command handler methods (``do_``) should return ``True`` to + indicate that the command loop should terminate. Any other return + value continues the loop. + + * If the user presses Enter on an empty line, the default behavior is + to repeat the last nonempty command entered. This can be disabled by + overriding :meth:`emptyline`. + + * If no matching ``do_`` method is found, the + :meth:`default` method is called. + + * Exceptions raised inside command handlers are not caught by default + and will terminate the command loop unless handled explicitly. + .. _cmd-objects: @@ -92,310 +110,3 @@ A :class:`Cmd` instance has the following methods: the current input line with leading whitespace removed, *begidx* and *endidx* are the beginning and ending indexes of the prefix text, which could be used to provide different completion depending upon which position the argument is in. - - -.. method:: Cmd.do_help(arg) - - All subclasses of :class:`Cmd` inherit a predefined :meth:`!do_help`. This - method, called with an argument ``'bar'``, invokes the corresponding method - :meth:`!help_bar`, and if that is not present, prints the docstring of - :meth:`!do_bar`, if available. With no argument, :meth:`!do_help` lists all - available help topics (that is, all commands with corresponding - :meth:`!help_\*` methods or commands that have docstrings), and also lists any - undocumented commands. - - -.. method:: Cmd.onecmd(str) - - Interpret the argument as though it had been typed in response to the prompt. - This may be overridden, but should not normally need to be; see the - :meth:`precmd` and :meth:`postcmd` methods for useful execution hooks. The - return value is a flag indicating whether interpretation of commands by the - interpreter should stop. If there is a :meth:`!do_\*` method for the command - *str*, the return value of that method is returned, otherwise the return value - from the :meth:`default` method is returned. - - -.. method:: Cmd.emptyline() - - Method called when an empty line is entered in response to the prompt. If this - method is not overridden, it repeats the last nonempty command entered. - - -.. method:: Cmd.default(line) - - Method called on an input line when the command prefix is not recognized. If - this method is not overridden, it prints an error message and returns. - - -.. method:: Cmd.completedefault(text, line, begidx, endidx) - - Method called to complete an input line when no command-specific - :meth:`!complete_\*` method is available. By default, it returns an empty list. - - -.. method:: Cmd.columnize(list, displaywidth=80) - - Method called to display a list of strings as a compact set of columns. - Each column is only as wide as necessary. - Columns are separated by two spaces for readability. - - -.. method:: Cmd.precmd(line) - - Hook method executed just before the command line *line* is interpreted, but - after the input prompt is generated and issued. This method is a stub in - :class:`Cmd`; it exists to be overridden by subclasses. The return value is - used as the command which will be executed by the :meth:`onecmd` method; the - :meth:`precmd` implementation may re-write the command or simply return *line* - unchanged. - - -.. method:: Cmd.postcmd(stop, line) - - Hook method executed just after a command dispatch is finished. This method is - a stub in :class:`Cmd`; it exists to be overridden by subclasses. *line* is the - command line which was executed, and *stop* is a flag which indicates whether - execution will be terminated after the call to :meth:`postcmd`; this will be the - return value of the :meth:`onecmd` method. The return value of this method will - be used as the new value for the internal flag which corresponds to *stop*; - returning false will cause interpretation to continue. - - -.. method:: Cmd.preloop() - - Hook method executed once when :meth:`cmdloop` is called. This method is a stub - in :class:`Cmd`; it exists to be overridden by subclasses. - - -.. method:: Cmd.postloop() - - Hook method executed once when :meth:`cmdloop` is about to return. This method - is a stub in :class:`Cmd`; it exists to be overridden by subclasses. - - -Instances of :class:`Cmd` subclasses have some public instance variables: - -.. attribute:: Cmd.prompt - - The prompt issued to solicit input. - - -.. attribute:: Cmd.identchars - - The string of characters accepted for the command prefix. - - -.. attribute:: Cmd.lastcmd - - The last nonempty command prefix seen. - - -.. attribute:: Cmd.cmdqueue - - A list of queued input lines. The cmdqueue list is checked in - :meth:`cmdloop` when new input is needed; if it is nonempty, its elements - will be processed in order, as if entered at the prompt. - - -.. attribute:: Cmd.intro - - A string to issue as an intro or banner. May be overridden by giving the - :meth:`cmdloop` method an argument. - - -.. attribute:: Cmd.doc_header - - The header to issue if the help output has a section for documented commands. - - -.. attribute:: Cmd.misc_header - - The header to issue if the help output has a section for miscellaneous help - topics (that is, there are :meth:`!help_\*` methods without corresponding - :meth:`!do_\*` methods). - - -.. attribute:: Cmd.undoc_header - - The header to issue if the help output has a section for undocumented commands - (that is, there are :meth:`!do_\*` methods without corresponding :meth:`!help_\*` - methods). - - -.. attribute:: Cmd.ruler - - The character used to draw separator lines under the help-message headers. If - empty, no ruler line is drawn. It defaults to ``'='``. - - -.. attribute:: Cmd.use_rawinput - - A flag, defaulting to true. If true, :meth:`cmdloop` uses :func:`input` to - display a prompt and read the next command; if false, :data:`sys.stdout.write() ` - and :data:`sys.stdin.readline() ` are used. (This means that by importing - :mod:`readline`, on systems that support it, the interpreter will automatically - support :program:`Emacs`\ -like line editing and command-history keystrokes.) - - -.. _cmd-example: - -Cmd Example ------------ - -.. sectionauthor:: Raymond Hettinger - -The :mod:`cmd` module is mainly useful for building custom shells that let a -user work with a program interactively. - -This section presents a simple example of how to build a shell around a few of -the commands in the :mod:`turtle` module. - -Basic turtle commands such as :meth:`~turtle.forward` are added to a -:class:`Cmd` subclass with method named :meth:`!do_forward`. The argument is -converted to a number and dispatched to the turtle module. The docstring is -used in the help utility provided by the shell. - -The example also includes a basic record and playback facility implemented with -the :meth:`~Cmd.precmd` method which is responsible for converting the input to -lowercase and writing the commands to a file. The :meth:`!do_playback` method -reads the file and adds the recorded commands to the :attr:`~Cmd.cmdqueue` for -immediate playback:: - - import cmd, sys - from turtle import * - - class TurtleShell(cmd.Cmd): - intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n' - prompt = '(turtle) ' - file = None - - # ----- basic turtle commands ----- - def do_forward(self, arg): - 'Move the turtle forward by the specified distance: FORWARD 10' - forward(*parse(arg)) - def do_right(self, arg): - 'Turn turtle right by given number of degrees: RIGHT 20' - right(*parse(arg)) - def do_left(self, arg): - 'Turn turtle left by given number of degrees: LEFT 90' - left(*parse(arg)) - def do_goto(self, arg): - 'Move turtle to an absolute position with changing orientation. GOTO 100 200' - goto(*parse(arg)) - def do_home(self, arg): - 'Return turtle to the home position: HOME' - home() - def do_circle(self, arg): - 'Draw circle with given radius an options extent and steps: CIRCLE 50' - circle(*parse(arg)) - def do_position(self, arg): - 'Print the current turtle position: POSITION' - print('Current position is %d %d\n' % position()) - def do_heading(self, arg): - 'Print the current turtle heading in degrees: HEADING' - print('Current heading is %d\n' % (heading(),)) - def do_color(self, arg): - 'Set the color: COLOR BLUE' - color(arg.lower()) - def do_undo(self, arg): - 'Undo (repeatedly) the last turtle action(s): UNDO' - def do_reset(self, arg): - 'Clear the screen and return turtle to center: RESET' - reset() - def do_bye(self, arg): - 'Stop recording, close the turtle window, and exit: BYE' - print('Thank you for using Turtle') - self.close() - bye() - return True - - # ----- record and playback ----- - def do_record(self, arg): - 'Save future commands to filename: RECORD rose.cmd' - self.file = open(arg, 'w') - def do_playback(self, arg): - 'Playback commands from a file: PLAYBACK rose.cmd' - self.close() - with open(arg) as f: - self.cmdqueue.extend(f.read().splitlines()) - def precmd(self, line): - line = line.lower() - if self.file and 'playback' not in line: - print(line, file=self.file) - return line - def close(self): - if self.file: - self.file.close() - self.file = None - - def parse(arg): - 'Convert a series of zero or more numbers to an argument tuple' - return tuple(map(int, arg.split())) - - if __name__ == '__main__': - TurtleShell().cmdloop() - - -Here is a sample session with the turtle shell showing the help functions, using -blank lines to repeat commands, and the simple record and playback facility: - -.. code-block:: none - - Welcome to the turtle shell. Type help or ? to list commands. - - (turtle) ? - - Documented commands (type help ): - ======================================== - bye color goto home playback record right - circle forward heading left position reset undo - - (turtle) help forward - Move the turtle forward by the specified distance: FORWARD 10 - (turtle) record spiral.cmd - (turtle) position - Current position is 0 0 - - (turtle) heading - Current heading is 0 - - (turtle) reset - (turtle) circle 20 - (turtle) right 30 - (turtle) circle 40 - (turtle) right 30 - (turtle) circle 60 - (turtle) right 30 - (turtle) circle 80 - (turtle) right 30 - (turtle) circle 100 - (turtle) right 30 - (turtle) circle 120 - (turtle) right 30 - (turtle) circle 120 - (turtle) heading - Current heading is 180 - - (turtle) forward 100 - (turtle) - (turtle) right 90 - (turtle) forward 100 - (turtle) - (turtle) right 90 - (turtle) forward 400 - (turtle) right 90 - (turtle) forward 500 - (turtle) right 90 - (turtle) forward 400 - (turtle) right 90 - (turtle) forward 300 - (turtle) playback spiral.cmd - Current position is 0 0 - - Current heading is 0 - - Current heading is 180 - - (turtle) bye - Thank you for using Turtle