question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow customization of the default argument parser used by cmd2

See original GitHub issue

We have the ability to modify the argument parser used by do_XX commands with @with_parser decorator.

The parsers used by the inbuilt cmd2 commands such as macro, alias etc are hardcoded to use Cmd2ArgumentParser https://github.com/python-cmd2/cmd2/blob/master/cmd2/cmd2.py#L2384

Since I have my custom argument parser for all my do_XX commands (which inherits from Cmd2ArgumentParser), the output of my custom commands while parsing commands (color/format) doesn’t match with the output of the default commands like alias, macro.

Currently, I have a class similar to,


class CustomCmd2(cmd2.Cmd):
    def __init__(self, connection, *args, **kwargs):
        # Dynamically add all do_XX functions from the package 'modules' since it is cumbersome
        # to write every method in the class.
        for module_name in modules.__all__:
            module = importlib.import_module(modules.__name__ + "." + module_name)
            predicate = lambda obj: inspect.isfunction(obj) and obj.__name__.startswith("do_")
            functions = inspect.getmembers(module, predicate)
            for function_name, function in functions:
                setattr(self, function_name, types.MethodType(function, self))

        cmd2.Cmd.__init__(self, *args, **kwargs)

        # Modify the parsers after initialization.
        # Cast the parser to my custom parser for added functionality.
        def cast(obj, req_type, obj_type = None):
            if obj_type:
                assert isinstance(self.alias_parser, obj_type), "The object type is different. Dangerous to  cast."
            obj.__class__ = req_type

        cast(self.alias_parser, ColoredArgParser, cmd2.Cmd2ArgumentParser)
        .........

    def get_names(self):
        """
        The default implementation from cmd (cpython implementation) looks like,
            def get_names(self):
                return dir(self.__class__)
        Since we are modifying the class instance so that functions are added at runtime, we have to return dir(self)
        This fixes the issue of the commands not registering in do_help().
        """
        return dir(self) 

To change the default parser to my custom ColoredArgParser, I am hacking the class with,

def obj_cast(obj, req_type, obj_type = None):
    if obj_type:
        assert isinstance(self.alias_parser, obj_type), "The object type is different. Dangerous to  cast."
    obj.__class__ = req_type

obj_cast(self.alias_parser, ColoredArgParser, cmd2.Cmd2ArgumentParser)

This seems very hackish, and casting is not pythonic. I believe there should be a way to specify the default argument parser used.

This would also match the API used in the rest of the project. We have the ability to modify the HelpFormatter in cmd2 https://github.com/python-cmd2/cmd2/blob/master/cmd2/argparse_custom.py#L694 There must also be a way to modify the default argument parser. Maybe in a similar fashion while constructing the object?

If there is a simpler way to achieve this, it would be helpful to know the method. I am willing to contribute if necessary.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
tleonhardtcommented, Sep 19, 2019

@teto There isn’t any problem in inheriting from the cmd2 parser.

This discussion is about possibly giving a way to retrofit the built-in cmd2 commands to use a custom parser for the sake of consistency in help output formatting.

1reaction
tleonhardtcommented, Sep 15, 2019

I think this is an excellent suggestion for an enhancement.

I suspect a significant number of larger projects using cmd2 might implement a custom Cmd2ArgumentParser. The whole reason we ported all of the built-in commands within cmd2 to use @with_argparser (even when they don’t need any arguments/options) was for consistency in the help formatting and style.

As to implementation, I’m not sure what the best approach would be. But I suspect we could keep it relatively simple.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Argument Processing — cmd2 2.4 documentation
By default, cmd2 uses the docstring of the command method when a user asks for help on the command. When you use the...
Read more >
cmd2/argparse_custom.py at master - GitHub
Registers a custom argparse argument parameter. The registered name will then be a recognized keyword parameter to the parser's `add_argument()` function.
Read more >
argparse — Parser for command-line options, arguments and ...
By default, ArgumentParser objects use sys.argv[0] to determine how to display the ... ArgumentParser objects allow the help formatting to be customized by ......
Read more >
cmd2 Documentation - Read the Docs
The basic use of cmd2 is identical to that of cmd. ... All of these decorators accept an optional preserve_quotes argument which defaults...
Read more >
picocli - a mighty tiny command line interface
Enabling this annotation processor in your project is optional, but strongly recommended. Use this if you're interested in: Compile time error checking. The ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found