-
Notifications
You must be signed in to change notification settings - Fork 190
Description
the copier project is using a decorator to wrap error handling around some plumbum methods, like so-
from decorator import decorator
@decorator
def handle_exceptions(method, *args, **kwargs):
"""Handle keyboard interruption while running a method."""
try:
try:
return method(*args, **kwargs)
except KeyboardInterrupt:
raise UserMessageError("Execution stopped by user")
except UserMessageError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
return 1
except UnsafeTemplateError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
# DOCS https://github.com/copier-org/copier/issues/1328#issuecomment-1723214165
return 0b100this decorator is then applied to plumbum.cli subcommand methods.
This works fine- the @decorator decorator ensures the wrapped method's signature doesn't change, so plumbum.cli's introspection still works. There are two downsides
@decoratoris untyped@decoratorbreaks if you addfrom __future__ import annotationsto the file
I tried a different approach using a native decorator:
def _handle_exceptions(method: Callable[P, int]) -> Callable[P, int]:
@functools.wraps(method)
def inner(*args: P.args, **kwargs: P.kwargs) -> int:
try:
try:
return method(*args, **kwargs)
except KeyboardInterrupt:
raise UserMessageError("Execution stopped by user")
except UserMessageError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
return 1
except UnsafeTemplateError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
# DOCS https://github.com/copier-org/copier/issues/1328#issuecomment-1723214165
return 0b100
return innerbut this fails, presumably because plumbum.cli is relying on some element of the method signature that functools.wraps fails to forward.
I tried instead-
# ...
inner.__signature = inspect.signature(method)
return innerthat works, unless you add from __future__ import annotations, because that import changes the behaviour of inspect.signature (see https://bugs.python.org/issue43355)
i'm guessing that's the exact issue that was causing me problems at the beginning of this journey...
How should I proceed?