Title: Cmd: list available completions from the cmd.Cmd subclass and filter out EOF handler(s)
Type: enhancement Stage: patch review
Components: Library (Lib) Versions: Python 3.6
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Catherine.Devlin, Kimball Leavitt, aldwinaldwin, boompig, ngie, rhettinger
Priority: normal Keywords: patch

Created on 2011-10-18 19:16 by ngie, last changed 2019-11-07 00:41 by python-dev.

File name Uploaded Description Edit
python-cmd-better-filtering.patch ngie, 2011-10-18 19:16 review
python-cmd-better-filtering.patch ngie, 2011-10-21 05:43 review
python-cmd-better-filtering-py3.patch Catherine.Devlin, 2012-07-30 07:07 review
test_cmd.patch Catherine.Devlin, 2012-07-30 07:15 expand review
Pull Requests
URL Status Linked Edit
PR 17074 closed python-dev, 2019-11-07 00:41
Messages (8)
msg145856 - (view) Author: Enji Cooper (ngie) * Date: 2011-10-18 19:16
1. The current code in cmd.get_names does a dir on the derived class for
   cmd.Cmd object instead, which means that if I do something similar to
   the following:

class CLI(cmd.Cmd):
   def register_subcommand(self, cmd, cli_class):
       def call_cli(self):
           cli = cli_class()
       setattr(self, 'do_%s' % (cmd, ), call_cli)

   it won't register the command in the completion list or help list.

2. Registering a do_EOF handler is a bit of a hack to work around
   the fact that entering in ^D on the command line prints out:

   (Cmd) *** Unknown syntax: EOF

   I can't speak to the fact that my desired behavior should be 
   enforced (basically trickle up the EOFError like so):

   def do_EOF(self, arg):
       raise EOFError

   so what I'm proposing instead is that it be filtered out by default.

Given that there's some value in allowing developers to build custom filter rules for the completions (example: certain commands can be undocumented, hidden to lower privilege users, etc), I figured it would be wise to create a custom mechanism for filtering out commands.

This could be cleaned up to use better python idioms like a generator, cache the data and have a refresh method, etc, but this is a good first start.
msg145868 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2011-10-18 21:15
This looks to be a reasonable request.

I think the patch would be better if the filtering were done directly in get_names().  A subclass can override or extend that method if it wants to customize the filter.
msg146060 - (view) Author: Enji Cooper (ngie) * Date: 2011-10-21 05:43
Here's a version incorporating your suggestion and better documenting the choices and the method for overriding purposes. I have a few reservations with the current implementation:

1. As noted, the information for the class really could be and should be cached as the attributes of a given cmd.Cmd derived class don't change all that frequently.
2. One has to override the entire function in order to get what I consider standard functionality (filtering).. so I don't know if that's a good idea.
3. I've thought about the do_EOF handler stuff, and it would be nice if that was shoved into the completer method(s) as a keyword argument, defaulting to False -- that way one could avoid having to explicitly install an EOF handler when dealing with ^D, etc, but this can be hashed out better in a different issue, over IRC, email, etc.

This module could be better cleaned up (isn't PEP8 compliant, overrides built-ins, is pythonic but not super pythonic, etc), but I'll see what other modules exist out there that could be used in its place, because they could have resolved some of these issues. There is some value that can be obtained from pexpect, some of the other cmd module variants, etc .. I just like this module because it's nice, simple, and standard -- it just needs a little love and it will be awesome.

Anyhow -- thanks again for the work :).
msg166859 - (view) Author: Catherine Devlin (Catherine.Devlin) * Date: 2012-07-30 07:07
Needed to update the patch slightly for Python 3; now that filter() returns an iterator, ``do_help``'s call to 
names = self.get_names()
followed by
was throwing an error, so I changed get_names to return a list.
msg166861 - (view) Author: Catherine Devlin (Catherine.Devlin) * Date: 2012-07-30 07:15
Change to to test for help displaying the name of the registered subcommand (as well as a simple test for the basic operation of the registered sub-CLI).
msg309788 - (view) Author: Daniel (boompig) Date: 2018-01-11 01:59
If you write a handler for EOF like so:

from cmd import Cmd

class FooShell(Cmd):
	def do_EOF(self, args):
		# exit on EOF
		raise SystemExit()

shell = FooShell()

Then when running the shell, you can see "EOF" as an undocumented command in the help screen. You can see this when typing "?".

$ python
(Cmd) ?

Documented commands (type help <topic>):

Undocumented commands:

I believe the correct behaviour should be (1) don't show it in the undocumented commands, since it's not really a command; and (2) maybe create a built-in command for this, since the literal string "EOF" is also caught by this handler.
msg343874 - (view) Author: Aldwin Pollefeyt (aldwinaldwin) * Date: 2019-05-29 08:49
The EOF mentioned in msg309788 is the first reason why I searched in the library code for a solution. Then saw it as an opportunity to create hidden functions in the shell. So I created issue37030 [0] and PR13536 [1]. Later got notified about this thread.

msg353374 - (view) Author: Kimball Leavitt (Kimball Leavitt) Date: 2019-09-27 15:48
I know that many people do something like:

def do_EOF(self, arg):
    return True

to exit the program when you press Ctrl+d. Others might prefer something like ngie

def do_EOF(self, arg):
    raise EOFError

The issue that I have is if the command you enter is 'EOF' (or 'EOF --some --arg'), you end up calling your do_EOF function. I think this unintended side effect could be avoided if the check for EOFError was removed and the exception was just raised. (see
Date User Action Args
2019-11-07 00:41:34python-devsetstage: patch review
pull_requests: + pull_request16584
2019-09-27 15:48:43Kimball Leavittsetnosy: + Kimball Leavitt
messages: + msg353374
2019-05-29 08:49:26aldwinaldwinsetnosy: + aldwinaldwin
messages: + msg343874
2018-01-11 08:55:31rhettingersetassignee: rhettinger ->
2018-01-11 01:59:27boompigsetnosy: + boompig

messages: + msg309788
versions: + Python 3.6, - Python 3.3
2012-07-30 07:15:55Catherine.Devlinsetfiles: + test_cmd.patch

messages: + msg166861
2012-07-30 07:07:03Catherine.Devlinsetfiles: + python-cmd-better-filtering-py3.patch
nosy: + Catherine.Devlin
messages: + msg166859

2011-10-21 05:43:17ngiesetfiles: + python-cmd-better-filtering.patch

messages: + msg146060
2011-10-18 21:15:20rhettingersetversions: + Python 3.3, - Python 2.7, Python 3.4
nosy: + rhettinger

messages: + msg145868

assignee: rhettinger
2011-10-18 19:16:06ngiecreate