Bring fixes suggested by the review on UnixCommand

This commit is contained in:
Vincent Le Goff 2017-06-22 16:08:10 -07:00
parent 916d7933aa
commit 848b4c588c
2 changed files with 119 additions and 69 deletions

View file

@ -947,14 +947,14 @@ class CmdDummy(UnixCommand):
"""A dummy UnixCommand."""
def init(self):
key = "dummy"
def init_parser(self):
"""Fill out options."""
self.parser.add_argument("nb1", type=int, help="the first number")
self.parser.add_argument("nb2", type=int, help="the second number")
self.parser.add_argument("-v", "--verbose", action="store_true")
key = "dummy"
def func(self):
nb1 = self.opts.nb1
nb2 = self.opts.nb2

View file

@ -8,7 +8,7 @@ options.
The UnixCommand can be ovverridden to have your commands parsed.
You will need to override two methods:
- The `init` method, which adds options to the parser.
- The `init_parser` method, which adds options to the parser.
- The `func` method, called to execute the command once parsed.
Here's a short example:
@ -30,7 +30,7 @@ class CmdPlant(UnixCommand):
key = "plant"
def init(self):
def init_parser(self):
"Add the arguments to the parser."
# 'self.parser' inherits `argparse.ArgumentParser`
self.parser.add_argument("key",
@ -62,6 +62,112 @@ from textwrap import dedent
from evennia import Command, InterruptCommand
from evennia.utils.ansi import raw
class ParseError(Exception):
"""An error occurred during parsing."""
pass
class UnixCommandParser(argparse.ArgumentParser):
"""A modifier command parser for unix commands.
This parser is used to replace `argparse.ArgumentParser`. It
is aware of the command calling it, and can more easily report to
the caller. Some features (like the "brutal exit" of the original
parser) are disabled or replaced. This parser is used by UnixCommand
and creating one directly isn't recommended nor necessary. Even
adding a sub-command will use this replaced parser automatically.
"""
def __init__(self, prog, description="", epilogue="", command=None, **kwargs):
prog = prog or command.key
super(UnixCommandParser, self).__init__(
prog=prog, description=description,
conflict_handler='resolve', add_help=False, **kwargs)
self.command = command
self.post_help = epilogue
def n_exit(code=None, msg=None):
raise ParseError(msg)
self.exit = n_exit
# Replace the -h/--help
self.add_argument("-h", "--hel", nargs=0, action=HelpAction,
help="display the command help")
def format_usage(self):
"""Return the usage line.
Note:
This method is present to return the raw-escaped usage line,
in order to avoid unintentional color codes.
"""
return raw(super(UnixCommandParser, self).format_usage())
def format_help(self):
"""Return the parser help, including its epilogue.
Note:
This method is present to return the raw-escaped help,
in order to avoid unintentional color codes. Color codes
in the epilogue (the command docstring) are supported.
"""
autohelp = raw(super(UnixCommandParser, self).format_help())
return "\n" + autohelp + "\n" + self.post_help
def print_usage(self, file=None):
"""Print the usage to the caller.
Args:
file (file-object): not used here, the caller is used.
Note:
This method will override `argparse.ArgumentParser`'s in order
to not display the help on stdout or stderr, but to the
command's caller.
"""
if self.command:
self.command.msg(self.format_usage().strip())
def print_help(self, file=None):
"""Print the help to the caller.
Args:
file (file-object): not used here, the caller is used.
Note:
This method will override `argparse.ArgumentParser`'s in order
to not display the help on stdout or stderr, but to the
command's caller.
"""
if self.command:
self.command.msg(self.format_help().strip())
class HelpAction(argparse.Action):
"""Override the -h/--help action in the default parser.
Using the default -h/--help will call the exit function in different
ways, preventing the entire help message to be provided. Hence
this override.
"""
def __call__(self, parser, namespace, values, option_string=None):
"""If asked for help, display to the caller."""
if parser.command:
parser.command.msg(parser.format_help().strip())
parser.exit(0, "")
class UnixCommand(Command):
"""
Unix-type commands, supporting short and long options.
@ -71,7 +177,7 @@ class UnixCommand(Command):
used to parse the command.
In order to use it, you should override two methods:
- `init`: the init method is called when the command is created.
- `init_parser`: this method is called when the command is created.
It can be used to set options in the parser. `self.parser`
contains the `argparse.ArgumentParser`, so you can add arguments
here.
@ -84,7 +190,7 @@ class UnixCommand(Command):
slightly different way than usual: the first line of the docstring
is used to represent the program description (the very short
line at the top of the help message). The other lines below are
used as the program's "epilog", displayed below the options. It
used as the program's "epilogue", displayed below the options. It
means in your docstring, you don't have to write the options.
They will be automatically provided by the parser and displayed
accordingly. The `argparse` module provides a default '-h' or
@ -97,16 +203,16 @@ class UnixCommand(Command):
def __init__(self, **kwargs):
super(UnixCommand, self).__init__()
# Create the empty EvenniaParser, inheriting argparse.ArgumentParser
# Create the empty UnixCommandParser, inheriting argparse.ArgumentParser
lines = dedent(self.__doc__.strip("\n")).splitlines()
description = lines[0].strip()
epilog = "\n".join(lines[1:]).strip()
self.parser = EvenniaParser(None, description, epilog, command=self)
epilogue = "\n".join(lines[1:]).strip()
self.parser = UnixCommandParser(None, description, epilogue, command=self)
# Fill the argument parser
self.init()
self.init_parser()
def init(self):
def init_parser(self):
"""
Configure the argument parser, adding in options.
@ -143,7 +249,7 @@ class UnixCommand(Command):
Note:
You should not override this method. Consider overriding
`init` instead.
`init_parser` instead.
"""
try:
@ -153,59 +259,3 @@ class UnixCommand(Command):
if msg:
self.msg(msg)
raise InterruptCommand
class ParseError(Exception):
"""An error occurred during parsing."""
pass
class EvenniaParser(argparse.ArgumentParser):
"""A parser just for Evennia."""
def __init__(self, prog, description="", epilog="", command=None, **kwargs):
prog = prog or command.key
super(EvenniaParser, self).__init__(
prog=prog, description=description,
conflict_handler='resolve', add_help=False, **kwargs)
self.command = command
self.post_help = epilog
def n_exit(code=None, msg=None):
raise ParseError(msg)
self.exit = n_exit
# Replace the -h/--help
self.add_argument("-h", "--hel", nargs=0, action=HelpAction, help="display heeeelp")
def format_usage(self):
"""Return the usage line."""
return raw(super(EvenniaParser, self).format_usage())
def format_help(self):
"""Return the parser help, including its epilog."""
autohelp = raw(super(EvenniaParser, self).format_help())
return "\n" + autohelp + "\n" + self.post_help
def print_usage(self, file=None):
"""Print the usage to the caller."""
if self.command:
self.command.msg(self.format_usage().strip())
def print_help(self, file=None):
"""Print the help to the caller."""
if self.command:
self.command.msg(self.format_help().strip())
class HelpAction(argparse.Action):
"""Override the -h/--he.p."""
def __call__(self, parser, namespace, values, option_string=None):
if parser.command:
parser.command.msg(parser.format_help().strip())
parser.exit(0, "")