253
class ActionHelp(argparse.Action):
254
"""Custom "help" function for an action `ArgumentParser`.
256
We use the argument parser's "epilog" field for the action's detailed
259
This class is stateless.
262
keyword_args_help = dedent("""\
263
This method accepts keyword arguments. Pass each argument as a
264
key-value pair with an equals sign between the key and the value:
265
key1=value1 key2=value key3=value3. Keyword arguments must come after
266
any positional arguments.
270
def get_positional_args(cls, parser):
271
"""Return an API action's positional arguments.
273
Most typically, this holds a URL path fragment for the object that's
274
being addressed, e.g. a physical zone's name.
276
There will also be a "data" argument, representing the request's
277
embedded data, but that's of no interest to end-users. The CLI offers
278
a more fine-grained interface to pass parameters, so as a special case,
279
that one item is left out.
281
# Use private method on the parser. The list of actions does not
282
# seem to be publicly exposed.
283
positional_actions = parser._get_positional_actions()
284
names = [action.dest for action in positional_actions]
285
if len(names) > 0 and names[-1] == 'data':
290
def get_optional_args(cls, parser):
291
"""Return an API action's optional arguments."""
292
# Use private method on the parser. The list of actions does not
293
# seem to be publicly exposed.
294
optional_args = parser._get_optional_actions()
298
def compose_positional_args(cls, parser):
299
"""Describe positional arguments for `parser`, as a list of strings."""
300
positional_args = cls.get_positional_args(parser)
301
if len(positional_args) == 0:
307
"Positional arguments:",
308
] + ["\t%s" % arg for arg in positional_args]
311
def compose_epilog(cls, parser):
312
"""Describe action in detail, as a list of strings."""
313
epilog = parser.epilog
314
if parser.epilog is None:
316
epilog = epilog.rstrip()
324
if ':param ' in epilog:
325
# This API action documents keyword arguments. Explain to the
326
# user how those work first.
327
lines.append(cls.keyword_args_help)
328
# Finally, include the actual documentation body.
333
def compose_optional_args(cls, parser):
334
"""Describe optional arguments for `parser`, as a list of strings."""
335
optional_args = cls.get_optional_args(parser)
336
if len(optional_args) == 0:
342
"Common command-line options:",
344
for arg in optional_args:
345
# Minimal representation of options. Doesn't show
346
# arguments to the options, defaults, and so on. But it's
347
# all we need for now.
348
lines.append(' %s' % ', '.join(arg.option_strings))
349
lines.append('\t%s' % arg.help)
353
def compose(cls, parser):
354
"""Put together, and return, help output for `parser`."""
356
parser.format_usage().rstrip(),
360
lines += cls.compose_positional_args(parser)
361
lines += cls.compose_epilog(parser)
362
lines += cls.compose_optional_args(parser)
363
return '\n'.join(lines)
365
def __call__(self, parser, namespace, values, option_string):
366
"""Overridable as defined by the `argparse` API."""
367
print(self.compose(parser))
252
371
def register_actions(profile, handler, parser):
253
372
"""Register a handler's actions."""
254
373
for action in handler["actions"]:
263
382
action_class = type(action_name, action_bases, action_ns)
264
383
action_parser = parser.subparsers.add_parser(
265
384
action_name, help=help_title, description=help_title,
267
action_parser.set_defaults(
268
execute=action_class(action_parser))
385
epilog=help_body, add_help=False)
386
action_parser.add_argument(
387
'--help', '-h', action=ActionHelp, nargs=0,
388
help="Show this help message and exit.")
389
action_parser.set_defaults(execute=action_class(action_parser))
271
392
def register_handler(profile, handler, parser):