diff --git a/copier/cli.py b/copier/cli.py index 51d2616bb..09e596163 100644 --- a/copier/cli.py +++ b/copier/cli.py @@ -52,9 +52,9 @@ from os import PathLike from pathlib import Path from textwrap import dedent +from typing import Callable import yaml -from decorator import decorator from plumbum import cli, colors from .errors import UnsafeTemplateError, UserMessageError @@ -63,12 +63,11 @@ from .types import AnyByStrDict, OptStr, StrSeq -@decorator -def handle_exceptions(method, *args, **kwargs): +def _handle_exceptions(method: Callable[[], None]) -> int: """Handle keyboard interruption while running a method.""" try: try: - return method(*args, **kwargs) + method() except KeyboardInterrupt: raise UserMessageError("Execution stopped by user") except UserMessageError as error: @@ -78,6 +77,7 @@ def handle_exceptions(method, *args, **kwargs): print(colors.red | "\n".join(error.args), file=sys.stderr) # DOCS https://github.com/copier-org/copier/issues/1328#issuecomment-1723214165 return 0b100 + return 0 class CopierApp(cli.Application): @@ -247,7 +247,6 @@ class CopierCopySubApp(_Subcommand): help="Overwrite files that already exist, without asking.", ) - @handle_exceptions def main(self, template_src: str, destination_path: str) -> int: """Call [run_copy][copier.main.Worker.run_copy]. @@ -260,15 +259,18 @@ def main(self, template_src: str, destination_path: str) -> int: destination_path: Where to generate the new subproject. It must not exist or be empty. """ - with self._worker( - template_src, - destination_path, - cleanup_on_error=self.cleanup_on_error, - defaults=self.force or self.defaults, - overwrite=self.force or self.overwrite, - ) as worker: - worker.run_copy() - return 0 + + def inner() -> None: + with self._worker( + template_src, + destination_path, + cleanup_on_error=self.cleanup_on_error, + defaults=self.force or self.defaults, + overwrite=self.force or self.overwrite, + ) as worker: + worker.run_copy() + + return _handle_exceptions(inner) @CopierApp.subcommand("recopy") @@ -315,7 +317,6 @@ class CopierRecopySubApp(_Subcommand): help="Skip questions that have already been answered", ) - @handle_exceptions def main(self, destination_path: cli.ExistingDirectory = ".") -> int: """Call [run_recopy][copier.main.Worker.run_recopy]. @@ -327,14 +328,17 @@ def main(self, destination_path: cli.ExistingDirectory = ".") -> int: The subproject must exist. If not specified, the currently working directory is used. """ - with self._worker( - dst_path=destination_path, - defaults=self.force or self.defaults, - overwrite=self.force or self.overwrite, - skip_answered=self.skip_answered, - ) as worker: - worker.run_recopy() - return 0 + + def inner() -> None: + with self._worker( + dst_path=destination_path, + defaults=self.force or self.defaults, + overwrite=self.force or self.overwrite, + skip_answered=self.skip_answered, + ) as worker: + worker.run_recopy() + + return _handle_exceptions(inner) @CopierApp.subcommand("update") @@ -387,7 +391,6 @@ class CopierUpdateSubApp(_Subcommand): help="Skip questions that have already been answered", ) - @handle_exceptions def main(self, destination_path: cli.ExistingDirectory = ".") -> int: """Call [run_update][copier.main.Worker.run_update]. @@ -399,13 +402,16 @@ def main(self, destination_path: cli.ExistingDirectory = ".") -> int: The subproject must exist. If not specified, the currently working directory is used. """ - with self._worker( - dst_path=destination_path, - conflict=self.conflict, - context_lines=self.context_lines, - defaults=self.defaults, - skip_answered=self.skip_answered, - overwrite=True, - ) as worker: - worker.run_update() - return 0 + + def inner() -> None: + with self._worker( + dst_path=destination_path, + conflict=self.conflict, + context_lines=self.context_lines, + defaults=self.defaults, + skip_answered=self.skip_answered, + overwrite=True, + ) as worker: + worker.run_update() + + return _handle_exceptions(inner) diff --git a/poetry.lock b/poetry.lock index dfae6c694..77ff58a29 100644 --- a/poetry.lock +++ b/poetry.lock @@ -238,17 +238,6 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] -[[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -optional = false -python-versions = ">=3.5" -files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] - [[package]] name = "distlib" version = "0.3.7" @@ -1503,17 +1492,6 @@ files = [ {file = "types_backports-0.1.3-py2.py3-none-any.whl", hash = "sha256:dafcd61848081503e738a7768872d1dd6c018401b4d2a1cfb608ea87ec9864b9"}, ] -[[package]] -name = "types-decorator" -version = "5.1.8.20240106" -description = "Typing stubs for decorator" -optional = false -python-versions = ">=3.8" -files = [ - {file = "types-decorator-5.1.8.20240106.tar.gz", hash = "sha256:32ff92b33615060d23b9d3760124bdb3506c4aa8d9eb50963cf1a3c20b9ecbbf"}, - {file = "types_decorator-5.1.8.20240106-py3-none-any.whl", hash = "sha256:14d21e6a0755dbb8f301f2f532b3eab5148f433c69dad2d98bf5bd2b3a2ef4e7"}, -] - [[package]] name = "types-psutil" version = "5.9.5.20240205" @@ -1652,4 +1630,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "2.0" python-versions = ">=3.8" -content-hash = "68ae53c03a93971c92d62fdd18a7635f2b9a7d2a42317b781777412020227e01" +content-hash = "e77e027798e8d257d07fee377fb2581be217bbcd761326d043f3b5006e6e870f" diff --git a/pyproject.toml b/pyproject.toml index b662b473e..b353a8231 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ copier = "copier.__main__:copier_app_run" [tool.poetry.dependencies] python = ">=3.8" colorama = ">=0.4.6" -decorator = ">=5.1.1" # HACK Remove markers when https://github.com/mtkennerly/dunamai/issues/74 is fixed dunamai = { version = ">=1.7.0", markers = "python_version < '4'" } funcy = ">=1.17" @@ -58,7 +57,6 @@ pytest-cov = ">=3.0.0" pytest-gitconfig = ">=0.6.0" pytest-xdist = ">=2.5.0" types-backports = ">=0.1.3" -types-decorator = ">=5.1.1" types-pyyaml = ">=6.0.4" types-psutil = "*"