Проблема, с которой вы сталкиваетесь, заключается в том, что вы звоните click.Context.invoke
, который не использует click.Command.invoke
.С небольшим DRY мы можем выделить вашу оболочку вызова и использовать ее следующим образом:
Код:
def invoke_with_catch(self, ctx, original_invoke):
fmt = dict(command=getattr(ctx, 'command', ctx).name)
try:
click.echo("Running {command} command".format(**fmt))
result = original_invoke(self, ctx)
click.echo("Completed {command} command".format(**fmt))
return result
except Exception as exc:
click.echo(
'Command {command} failed with exception: {exc}'.format(
exc=exc, **fmt)
)
""" In case command invoked from another command """
raise click.ClickException(
"Failed to invoke {command} command".format(**fmt))
Вызов кода:
Обертка может быть вызвана напрямую, например:
invoke_with_catch(ctx, c1, click.Context.invoke)
или может использоваться в унаследованном классе, например:
class CLICommandInvoker(click.Command):
def invoke(self, ctx):
return invoke_with_catch(self, ctx, click.Command.invoke)
Код теста:
import click
class CLICommandInvoker(click.Command):
def invoke(self, ctx):
return invoke_with_catch(self, ctx, click.Command.invoke)
class CLIGroupInvoker(click.Group):
def invoke(self, ctx):
return invoke_with_catch(self, ctx, click.Group.invoke)
@click.group(cls=CLIGroupInvoker)
def g():
pass
@g.command(cls=CLICommandInvoker)
@click.option("--throw", is_flag=True)
def c1(throw):
click.echo("C1")
if throw:
raise Exception('Throwing in C1')
@g.command(cls=CLICommandInvoker)
@click.option("--throw", is_flag=True)
@click.pass_context
def c2(ctx, throw):
invoke_with_catch(ctx, c1, click.Context.invoke)
click.echo("C2")
if throw:
raise Exception('Throwing in C2')
if __name__ == "__main__":
commands = (
'c1',
'c1 --throw',
'c2',
'c2 --throw',
'--help',
'',
)
import sys, time
time.sleep(1)
print('Click Version: {}'.format(click.__version__))
print('Python Version: {}'.format(sys.version))
for cmd in commands:
try:
time.sleep(0.1)
print('-----------')
print('> ' + cmd)
time.sleep(0.1)
g(cmd.split())
except BaseException as exc:
if str(exc) != '0' and \
not isinstance(exc, (click.ClickException, SystemExit)):
raise
Результаты:
Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> c1
Running g command
Running c1 command
C1
Completed c1 command
Completed g command
-----------
> c1 --throw
Running g command
Running c1 command
C1
Command c1 failed with exception: Throwing in C1
Command g failed with exception: Failed to invoke c1 command
Error: Failed to invoke g command
-----------
> c2
Running g command
Running c2 command
Running c1 command
C1
Completed c1 command
C2
Completed c2 command
Completed g command
-----------
> c2 --throw
Running g command
Running c2 command
Running c1 command
C1
Completed c1 command
C2
Command c2 failed with exception: Throwing in C2
Command g failed with exception: Failed to invoke c2 command
Error: Failed to invoke g command
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
c1
c2
-----------
>
Usage: test.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
c1
c2