slm slm - 1 year ago 31
Python Question

How to add multiple blank lines to the end of the usage message produced by the Python click module?

I have a question that's somewhat similar to this SO Q&A, however I want to add additional blank lines to an epilog at the end of the output generated by click.

I have the following code:

EPILOG='\n' + '-' * 20

class SpecialEpilog(click.Group):
def format_epilog(self, ctx, formatter):
if self.epilog:
formatter.write_paragraph()
for line in self.epilog.split('\n'):
formatter.write_text(line)

#------------------
@click.group(cls=SpecialEpilog, epilog=EPILOG, invoke_without_command=True)
def cli():
"""Wraps cloud.tenable.com Nessus API calls in useful ways

\b
The CLI provides access to these subcommands:
- agent
- os
- vuln

Each subcommand can perform useful API queries within their respective domain.
"""
pass

#------------------
# main
cli.add_command(os)
cli.add_command(agent)
cli.add_command(vuln)


This produces the following usage output:

Usage: nessus_query [OPTIONS] COMMAND [ARGS]...



Wraps cloud.tenable.com Nessus API calls in useful ways

The CLI provides access to these subcommands:
- agent
- os
- vuln

Each subcommand can perform useful API queries within their respective
domain.

Options:
--help Show this message and exit.

Commands:
agent API calls focusing on assets' details - Works...
os API calls focusing on operating systems -...
vuln API calls focusing on vulnerabilities - Works...


--------------------
$ myprompt>


My question:

I cannot figure out a method which doesn't require printable characters. If I remove the dash sequence above, the newline characters (
\n
) no longer get displayed. In other words the above usage goes to this:

...
Commands:
agent API calls focusing on assets' details - Works...
os API calls focusing on operating systems -...
vuln API calls focusing on vulnerabilities - Works...
$ myprompt>

Answer Source

The issue is that click does an optimization to remove any blank lines at the end of the help. The behavior is in click.Command.get_help() and can be overridden like:

Code:

class SpecialEpilog(click.Group):

    def get_help(self, ctx):
        """ standard get help, but without rstrip """
        formatter = ctx.make_formatter()
        self.format_help(ctx, formatter)
        return formatter.getvalue()

Test Code:

import click

EPILOG = '\n\n'

class SpecialEpilog(click.Group):
    def format_epilog(self, ctx, formatter):
        if self.epilog:
            formatter.write_paragraph()
            for line in self.epilog.split('\n'):
                formatter.write_text(line)

    def get_help(self, ctx):
        """ standard get help, but without rstrip """
        formatter = ctx.make_formatter()
        self.format_help(ctx, formatter)
        return formatter.getvalue()

@click.group(cls=SpecialEpilog, epilog=EPILOG, invoke_without_command=True)
def cli():
    pass

@cli.command()
def os(*args, **kwargs):
    pass

@cli.command()
def agent(*args, **kwargs):
    pass

cli(['--help'])

But all I need is blanks, not an epilog:

If all you need is some blank lines, then we can ignore the epilog altogether and simply modify get_help() to add same like:

class AddSomeBlanksToHelp(click.Group):

    def get_help(self, ctx):
        return super(AddSomeBlanksToHelp, self).get_help(ctx) + '\n\n'

@click.group(cls=AddSomeBlanksToHelp, invoke_without_command=True)
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download