6

In the case where there are command groups and every sub-command may raise exceptions, how can I handle them all together in one place?

Given the example below:

import click


@click.group()
def cli():
    pass

@cli.command()
def foo():
    pass

if __name__ == '__main__':
    cli()

Both cli and foo may raise. I know that one possible solution is to place try-except around cli() in the if clause. But that does not work when you distribute a package. In setup.py, you have to specify an entry point (in this case, cli). The if clause will not be executed.

1 Answer 1

12

You can create a custom click.Group by inheriting from same. The custom group can be used by passing it as the cls parameter to the click.group() decorator. If you override the __call__ method, you can insert an exception handler like:

Code:

class CatchAllExceptions(click.Group):

    def __call__(self, *args, **kwargs):
        try:
            return self.main(*args, **kwargs)
        except Exception as exc:
            click.echo('We found %s' % exc)

Test Code:

import click

@click.group(cls=CatchAllExceptions)
def cli():
    pass

@cli.command()
def foo():
    raise Exception('an exception!')

if __name__ == '__main__':
    cli('foo'.split())

Results:

We found an exception!
Sign up to request clarification or add additional context in comments.

1 Comment

This doesn't work when attempting to capture the exception in a unit test with the CliRunner. Invoking the custom group as follows: ``` runner = CliRunner() result = runner.invoke(cli, 'foo') print(result)` ``` prints: "an exception!"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.