Title: Cmd do_something only accepts one argument
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.8
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Oz.Tiram, eric.araujo, ned.deily
Priority: normal Keywords: patch

Created on 2018-04-05 06:26 by Oz.Tiram, last changed 2018-04-06 22:11 by ned.deily.

File name Uploaded Description Edit
cmd.patch Oz.Tiram, 2018-04-05 06:26 The patch adding the functionality described above review
Messages (6)
msg314968 - (view) Author: Oz Tiram (Oz.Tiram) * Date: 2018-04-05 06:26
Considering that I want to build an CLI interactive program using cmd.Cmd,
which has multiple functions that accept two or more arguments,
I always have to do parsing of arg inside my do_methods for example:

class Calc(cmd.Cmd):

    do_add(self, arg):
       a, b = parse_ints(arg)
       return a+b

    do_mult(self, arg):
       a, b = parse_ints(arg)
       return a*b

This is easy enough for a simple calculator. But for more logic I need to create more parse_type and explicitly call them at the top of each do_stuff.
Considering this I have created a patch for Cmd.cmd, that keeps the old functionality, but adds the ability to pass multiple arguments without having to parse them every time. 
The functionality is as follows:

class MyProg(cmd.Cmd):

    do_simple(self, arg):

    do_greet(self, name="World")
       print("Hello %s" %s)

    do_add(self, a, b):

Now in the cmd prompt:

(Cmd) simple foo
(Cmd) # keeps the old functionallity 
(Cmd) add 2 3
# add two properly add the values
(Cmd) add 2
# expects two arguments, so it will print the help for add
(Cmd) greet
Hello World
# does not complain because it has a default value
(Cmd) greet Guido
Hello Guido
(Cmd) greet name=Raymond
Hello Raymond
# works too

None of these example guess the type. It is simply handles as a string. but I am playing around with automatically detecting types of variables using function annotations in python 3.5 and later.

Also, although, not demonstrated here, one can also define:

    def do_some_method_with_kwargs(self, arg1, arg2, **kwargs):
        ... do fancy stuff ...

(Cmd) some_method_with_kwargs foo bar kwargs='{"name": "John", "age"=35}'

kwargs is parsed to a dict (using json.loads) when escaped properly.
This is a bit esoteric, hence not shown here (but the patch patch includes it).
I was wondering if this kind of enhancement would be considered for this module? 
I will happily create a PR with tests and documentation explaining this enhanced functionality.
msg315000 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2018-04-05 18:30
Thanks for your suggested enhancement to the cmd module.  cmd has been around a *long* time and, unfortunately, has received very little maintenance or enhancement attention for many years.  In the meantime, third-party replacements for cmd have arisen.  One of the most popular is cmd2, available from PyPI, which has also been around a long time and appears to be actively maintained.  In particular, it looks like cmd2 already offers robust parsing of arguments.  While enhancing the standard library cmd module sounds like it might be a good idea, in this particular case, you and other potential users of cmd might be better off using cmd2.  In any case, unless a core developer is interested in shepherding this change, your proposed change is likely to languish.
msg315023 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2018-04-06 16:40
I think using shlex unconditionally to parse lines sent to cmd.Cmd may not be ideal.

Cmd is very generic and there are many ways to parse lines into arguments:
- no parsing (think Python shells or remote command execution)
- shlex (makes sense for unix users, maybe not others)
- parse_ints as in your example (lexing + conversion)
- optparse (I read about a tool where the interactive command format was the same as the command-line arguments format, which makes is super easy to support all commands in a config file or “session replay” file!)
- many more.

Could the shlex parsing be in a subclass?  Or is it small enough to be in the docs?  If it’s not small, maybe the base Cmd class needs to be reworked to make it easier to hook into line parsing?
msg315032 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2018-04-06 21:09
The more I think about it, the more I feel it would be a disservice to our users to add piecemeal enhancements like this to the standard library cmd module at this point, when cmd is essentially unmaintained and there is already a superior alternative.  I have opened Issue33233 suggesting we at least add a See Also doc link to cmd2 and to consider potentially deprecating cmd in the standard library.  Again, thanks for the suggestion, Oz, but I would like to close this issue.
msg315034 - (view) Author: Oz Tiram (Oz.Tiram) * Date: 2018-04-06 21:29
I am disappointed you want to deprecate CMD. I knew about cmd2 and some other alternatives, but I think their execive use of decorators isn't so comfortable. That is why I wrote my own module.

I'm also willing to adopt the module and add even more features.
msg315036 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2018-04-06 22:11
Oz, I don't particularly like the idea of deprecating cmd but, realistically, Python development is almost entirely an unpaid, volunteer activity and we do not have enough resources to do everything we'd like to do.  So sometimes we need to make a tradeoff and this seems like it might be a good opportunity to make one that will benefit most people.  It's not my decision to make in isolation so I've sent a mail to the python-dev list asking other core developers and interested parties to comment on Issue33233.  So, let's keep this open until we resolve that issue and feel free to comment there.  Thanks again for your interest!
Date User Action Args
2018-04-06 22:11:02ned.deilysetmessages: + msg315036
2018-04-06 21:29:28Oz.Tiramsetstatus: pending -> open

messages: + msg315034
2018-04-06 21:09:12ned.deilysetstatus: open -> pending

messages: + msg315032
2018-04-06 16:40:59eric.araujosetnosy: + eric.araujo
messages: + msg315023
2018-04-05 18:30:40ned.deilysetnosy: + ned.deily

messages: + msg315000
versions: + Python 3.8
2018-04-05 07:03:12Oz.Tiramsettype: enhancement
components: + Library (Lib)
2018-04-05 06:26:53Oz.Tiramcreate