From d6f2d6a30590ccb5769879cd07449dad5548f4b1 Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Sat, 17 Jun 2017 16:35:57 -0700 Subject: [PATCH 1/4] Add the UnixCommand, to parse unix-like command options --- evennia/commands/default/tests.py | 8 +- evennia/contrib/tests.py | 82 +++++++++--- evennia/contrib/unixcommand.py | 202 ++++++++++++++++++++++++++++++ 3 files changed, 271 insertions(+), 21 deletions(-) create mode 100644 evennia/contrib/unixcommand.py diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index e6a6f36590..55896db1b2 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -73,6 +73,9 @@ class CommandTest(EvenniaTest): cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() + except InterruptCommand: + pass + finally: # clean out prettytable sugar. We only operate on text-type stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True)) for name, args, kwargs in receiver.msg.mock_calls] @@ -88,11 +91,8 @@ class CommandTest(EvenniaTest): retval = sep1 + msg.strip() + sep2 + returned_msg + sep3 raise AssertionError(retval) else: - returned_msg = "\n".join(stored_msg) + returned_msg = "\n".join(str(msg) for msg in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() - except InterruptCommand: - pass - finally: receiver.msg = old_msg return returned_msg diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index 46016be3a1..8bae394100 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -452,13 +452,13 @@ class TestChargen(CommandTest): self.assertTrue(self.player.db._character_dbrefs) self.call(chargen.CmdOOCLook(), "", "You, TestPlayer, are an OOC ghost without form.",caller=self.player) self.call(chargen.CmdOOCLook(), "testchar", "testchar(", caller=self.player) - + # Testing clothing contrib from evennia.contrib import clothing from evennia.objects.objects import DefaultRoom class TestClothingCmd(CommandTest): - + def test_clothingcommands(self): wearer = create_object(clothing.ClothedCharacter, key="Wearer") friend = create_object(clothing.ClothedCharacter, key="Friend") @@ -501,7 +501,7 @@ class TestClothingCmd(CommandTest): self.call(clothing.CmdInventory(), "", "You are not carrying or wearing anything.", caller=wearer) class TestClothingFunc(EvenniaTest): - + def test_clothingfunctions(self): wearer = create_object(clothing.ClothedCharacter, key="Wearer") room = create_object(DefaultRoom, key="room") @@ -521,28 +521,28 @@ class TestClothingFunc(EvenniaTest): test_hat.wear(wearer, 'on the head') self.assertEqual(test_hat.db.worn, 'on the head') - + test_hat.remove(wearer) self.assertEqual(test_hat.db.worn, False) - + test_hat.worn = True test_hat.at_get(wearer) self.assertEqual(test_hat.db.worn, False) - + clothes_list = [test_shirt, test_hat, test_pants] self.assertEqual(clothing.order_clothes_list(clothes_list), [test_hat, test_shirt, test_pants]) - + test_hat.wear(wearer, True) test_pants.wear(wearer, True) self.assertEqual(clothing.get_worn_clothes(wearer), [test_hat, test_pants]) - - self.assertEqual(clothing.clothing_type_count(clothes_list), {'hat':1, 'top':1, 'bottom':1}) - - self.assertEqual(clothing.single_type_count(clothes_list, 'hat'), 1) - - - + self.assertEqual(clothing.clothing_type_count(clothes_list), {'hat':1, 'top':1, 'bottom':1}) + + self.assertEqual(clothing.single_type_count(clothes_list, 'hat'), 1) + + + + # Testing custom_gametime from evennia.contrib import custom_gametime @@ -850,7 +850,7 @@ from evennia.contrib import turnbattle from evennia.objects.objects import DefaultRoom class TestTurnBattleCmd(CommandTest): - + # Test combat commands def test_turnbattlecmd(self): self.call(turnbattle.CmdFight(), "", "You can't start a fight if you've been defeated!") @@ -858,9 +858,9 @@ class TestTurnBattleCmd(CommandTest): self.call(turnbattle.CmdPass(), "", "You can only do that in combat. (see: help fight)") self.call(turnbattle.CmdDisengage(), "", "You can only do that in combat. (see: help fight)") self.call(turnbattle.CmdRest(), "", "Char rests to recover HP.") - + class TestTurnBattleFunc(EvenniaTest): - + # Test combat functions def test_turnbattlefunc(self): attacker = create_object(turnbattle.BattleCharacter, key="Attacker") @@ -937,3 +937,51 @@ class TestTurnBattleFunc(EvenniaTest): self.assertTrue(turnhandler.db.fighters == [joiner, attacker, defender]) # Remove the script at the end turnhandler.stop() + + +# Test of the unixcommand module + +from evennia.contrib.unixcommand import UnixCommand + +class CmdDummy(UnixCommand): + + """A dummy UnixCommand.""" + + def init(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 + result = nb1 * nb2 + verbose = self.opts.verbose + if verbose: + self.msg("{} times {} is {}".format(nb1, nb2, result)) + else: + self.msg("{} * {} = {}".format(nb1, nb2, result)) + + +class TestUnixCommand(CommandTest): + + def test_success(self): + """See the command parsing succeed.""" + self.call(CmdDummy(), "5 10", "5 * 10 = 50") + self.call(CmdDummy(), "5 10 -v", "5 times 10 is 50") + + def test_failure(self): + """If not provided with the right info, should fail.""" + ret = self.call(CmdDummy(), "5") + lines = ret.splitlines() + self.assertTrue(any(l.startswith("usage:") for l in lines)) + self.assertTrue(any(l.startswith("dummy: error:") for l in lines)) + + # If we specify an incorrect number as parameter + ret = self.call(CmdDummy(), "five ten") + lines = ret.splitlines() + self.assertTrue(any(l.startswith("usage:") for l in lines)) + self.assertTrue(any(l.startswith("dummy: error:") for l in lines)) diff --git a/evennia/contrib/unixcommand.py b/evennia/contrib/unixcommand.py new file mode 100644 index 0000000000..0bc4ad9fbe --- /dev/null +++ b/evennia/contrib/unixcommand.py @@ -0,0 +1,202 @@ +""" +Module containing the UnixCommand class. + +This command allows to use unix-like options in game commands. It is +not the best parser for players, but can be really useful for builders +when they need to have a single command to do many things with many +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 `func` method, called to execute the command once parsed. + +Here's a short example: + +```python +class CmdPlant(UnixCommand): + + ''' + Plant a tree or plant. + + This command is used to plant a tree or plant in the room you are in. + + Examples: + plant orange -a 8 + plant strawberry --hidden + plant potato --hidden --age 5 + + ''' + + key = "plant" + + def init(self): + "Add the arguments to the parser." + # 'self.parser' inherits `argparse.ArgumentParser` + self.parser.add_argument("key", + help="the key of the plant to be planted here") + self.parser.add_argument("-a", "--age", type=int, + default=1, help="the age of the plant to be planted") + self.parser.add_argument("--hidden", action="store_true", + help="should the newly-planted plant be hidden to players?") + + def func(self): + "func is called only if the parser succeeded." + # 'self.opts' contains the parsed options + key = self.opts.key + age = self.opts.age + hidden = self.opts.hidden + self.msg("Going to plant '{}', age={}, hidden={}.".format( + key, age, hidden)) +``` + +To see the full power of argparse and the types of supported options, visit +[the documentation of argparse](https://docs.python.org/2/library/argparse.html). + +""" + +import argparse +import shlex +from textwrap import dedent + +from evennia import Command, InterruptCommand +from evennia.utils.ansi import raw + +class UnixCommand(Command): + """ + Unix-type commands, supporting short and long options. + + This command syntax uses the Unix-style commands with short options + (-X) and long options (--something). The `argparse` module is + 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. + It can be used to set options in the parser. `self.parser` + contains the `argparse.ArgumentParser`, so you can add arguments + here. + - `func`: this method is called to execute the command, but after + the parser has checked the arguments given to it are valid. + You can access the namespace of valid arguments in `self.opts` + at this point. + + The help of UnixCommands is derived from the docstring, in a + 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 + 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 + '--help' option on the command. Typing |whelp commandname|n will + display the same as |wcommandname -h|n, though this behavior can + be changed. + + """ + + def __init__(self, **kwargs): + super(UnixCommand, self).__init__() + + # Create the empty EvenniaParser, 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) + + # Fill the argument parser + self.init() + + def init(self): + """ + Configure the argument parser, adding in options. + + Note: + This method is to be overridden in order to add options + to the argument parser. Use `self.parser`, which contains + the `argparse.ArgumentParser`. You can, for instance, + use its `add_argument` method. + + """ + pass + + def func(self): + """Override to handle the command execution.""" + pass + + def get_help(self, caller, cmdset): + """ + Return the help message for this command and this caller. + + Args: + caller (Object or Player): the caller asking for help on the command. + cmdset (CmdSet): the command set (if you need additional commands). + + Returns: + docstring (str): the help text to provide the caller for this command. + + """ + return self.parser.format_help() + + def parse(self): + """ + Process arguments provided in `self.args`. + + Note: + You should not override this method. Consider overriding + `init` instead. + + """ + try: + self.opts = self.parser.parse_args(shlex.split(self.args)) + except ParseError as err: + self.msg(str(err)) + 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, + formatter_class=argparse.RawDescriptionHelpFormatter, + conflict_handler='resolve', **kwargs) + self.command = command + self.post_help = epilog + def n_exit(code=None, msg=None): + if msg: + raise ParseError(msg) + + self.exit = n_exit + + 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 autohelp + "\n\n" + self.post_help + + def print_usage(self, file=None): + """Print the usage to the caller.""" + if self.command: + self.command.msg(ParseError(self.format_usage())) + else: + raise ParseError(self.format_usage()) + + def print_help(self, file=None): + """Print the help to the caller.""" + if self.command: + self.command.msg(ParseError(self.format_help())) + else: + raise ParseError(self.format_help()) From 916d7933aa4df4e61c6b6bcbc90529f91a5f1caa Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Sun, 18 Jun 2017 20:29:46 -0700 Subject: [PATCH 2/4] Fix minor errors in displaying the UnixCommand --- evennia/contrib/unixcommand.py | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/evennia/contrib/unixcommand.py b/evennia/contrib/unixcommand.py index 0bc4ad9fbe..dde36207da 100644 --- a/evennia/contrib/unixcommand.py +++ b/evennia/contrib/unixcommand.py @@ -149,7 +149,9 @@ class UnixCommand(Command): try: self.opts = self.parser.parse_args(shlex.split(self.args)) except ParseError as err: - self.msg(str(err)) + msg = str(err) + if msg: + self.msg(msg) raise InterruptCommand @@ -168,16 +170,17 @@ class EvenniaParser(argparse.ArgumentParser): prog = prog or command.key super(EvenniaParser, self).__init__( prog=prog, description=description, - formatter_class=argparse.RawDescriptionHelpFormatter, - conflict_handler='resolve', **kwargs) + conflict_handler='resolve', add_help=False, **kwargs) self.command = command self.post_help = epilog def n_exit(code=None, msg=None): - if msg: - raise ParseError(msg) + 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()) @@ -185,18 +188,24 @@ class EvenniaParser(argparse.ArgumentParser): def format_help(self): """Return the parser help, including its epilog.""" autohelp = raw(super(EvenniaParser, self).format_help()) - return autohelp + "\n\n" + self.post_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(ParseError(self.format_usage())) - else: - raise ParseError(self.format_usage()) + 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(ParseError(self.format_help())) - else: - raise ParseError(self.format_help()) + 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, "") From 848b4c588cb5213151367a89e98caff6e9004066 Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Thu, 22 Jun 2017 16:08:10 -0700 Subject: [PATCH 3/4] Bring fixes suggested by the review on UnixCommand --- evennia/contrib/tests.py | 6 +- evennia/contrib/unixcommand.py | 182 +++++++++++++++++++++------------ 2 files changed, 119 insertions(+), 69 deletions(-) diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index 8bae394100..bbf6d29d43 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -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 diff --git a/evennia/contrib/unixcommand.py b/evennia/contrib/unixcommand.py index dde36207da..cb65011bbf 100644 --- a/evennia/contrib/unixcommand.py +++ b/evennia/contrib/unixcommand.py @@ -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, "") From 080cc8a7eb542715c55e7ec8d24981cd969f505d Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Tue, 27 Jun 2017 11:59:45 -0700 Subject: [PATCH 4/4] Clean up UnixCommand to take into account suggestions --- evennia/contrib/unixcommand.py | 42 +++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/evennia/contrib/unixcommand.py b/evennia/contrib/unixcommand.py index cb65011bbf..850ade42d3 100644 --- a/evennia/contrib/unixcommand.py +++ b/evennia/contrib/unixcommand.py @@ -82,13 +82,33 @@ class UnixCommandParser(argparse.ArgumentParser): """ - def __init__(self, prog, description="", epilogue="", command=None, **kwargs): + def __init__(self, prog, description="", epilog="", command=None, **kwargs): + """ + Build a UnixCommandParser with a link to the command using it. + + Args: + prog (str): the program name (usually the command key). + description (str): a very brief line to show in the usage text. + epilog (str): the epilog to show below options. + command (Command): the command calling the parser. + + Kwargs: + Additional keyword arguments are directly sent to + `argparse.ArgumentParser`. You will find them on the + [parser's documentation](https://docs.python.org/2/library/argparse.html). + + Note: + It's doubtful you would need to create this parser manually. + The `UnixCommand` does that automatically. If you create + sub-commands, this class will be used. + + """ 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 + self.post_help = epilog def n_exit(code=None, msg=None): raise ParseError(msg) @@ -109,12 +129,12 @@ class UnixCommandParser(argparse.ArgumentParser): return raw(super(UnixCommandParser, self).format_usage()) def format_help(self): - """Return the parser help, including its epilogue. + """Return the parser help, including its epilog. 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. + in the epilog (the command docstring) are supported. """ autohelp = raw(super(UnixCommandParser, self).format_help()) @@ -190,7 +210,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 "epilogue", displayed below the options. It + used as the program's "epilog", 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 @@ -201,13 +221,19 @@ class UnixCommand(Command): """ def __init__(self, **kwargs): - super(UnixCommand, self).__init__() + """ + The lockhandler works the same as for objects. + optional kwargs will be set as properties on the Command at runtime, + overloading evential same-named class properties. + + """ + super(UnixCommand, self).__init__(**kwargs) # Create the empty UnixCommandParser, inheriting argparse.ArgumentParser lines = dedent(self.__doc__.strip("\n")).splitlines() description = lines[0].strip() - epilogue = "\n".join(lines[1:]).strip() - self.parser = UnixCommandParser(None, description, epilogue, command=self) + epilog = "\n".join(lines[1:]).strip() + self.parser = UnixCommandParser(None, description, epilog, command=self) # Fill the argument parser self.init_parser()