-
Notifications
You must be signed in to change notification settings - Fork 124
Description
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.