@@ 55,17 55,43 @@ def run(prog:str=None, usage:str=None, description:str=None, **kwargs):
execute(parser)
-def command(fnc:Callable):
+def _optional_arg_decorator(fn:Callable):
+ """ Decorate a function decorator to allow optional parameters to be passed to the decorated decorator...
+
+ (from https://stackoverflow.com/a/20966822. yeah! stackoverflow!)
+ """
+ def wrapped_decorator(*args, **kwargs):
+ if (len(args)==1 and callable(args[0])):
+ return fn(*args)
+ else:
+ def real_decorator(decoratee):
+ return fn(decoratee, *args, **kwargs)
+ return real_decorator
+ return wrapped_decorator
+
+@_optional_arg_decorator
+def command(fnc:Callable, command_name:str=None):
"""Build subcommand from function
Subcommand name will be the function name and arguments are parsed to build the command line.
+ Optionally, subcommand name can be passed as parameter:
+
+ @command('name')
+ def test():
+ ...
+
Each positional argument will be a positional paramenter.
+ Each positional argument of the decorated function will be a positional paramenter.
+
Each optional argument will be an optional flag.
+
Type hints are used to covert types from command line string.
+
An argument with `bool` type is converted to an optional flag parameter (with default sematic as "False")
+
To create an optional positional paramenter, use the `typing.Optional` type as hint with the parameter type,
- e.g. `Optional[str]`
+ e.g. `Optional[str]` and default value `None`
Function docstring is used to set command's help and description.
@@ 181,7 207,10 @@ def command(fnc:Callable):
name = name.replace("_", "-")
command['args'][name] = arg
- commands[fnc.__name__] = command
+ if command_name is None:
+ command_name = fnc.__name__
+
+ commands[command_name] = command
return fnc