poetry-plugin-hook 0.0.0__py3-none-any.whl → 1.4.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +1,33 @@
1
- from poetry.plugins.application_plugin import ApplicationPlugin
2
-
3
- from .latest import LatestCommand
4
- from .sync import SyncCommand
5
-
6
-
7
- class HookPlugin(ApplicationPlugin):
8
- def activate(self, application):
9
-
10
- application.command_loader.register_factory(
11
- LatestCommand.name,
12
- lambda: LatestCommand(),
13
- )
14
- application.command_loader.register_factory(
15
- SyncCommand.name,
16
- lambda: SyncCommand(),
17
- )
1
+ """
2
+ .. include:: ../README.md
3
+ """
4
+
5
+ from poetry.plugins.application_plugin import ApplicationPlugin
6
+
7
+ from poetry_plugin_hook.bump import BumpCommand
8
+ from poetry_plugin_hook.latest import LatestCommand
9
+ from poetry_plugin_hook.sync import SyncCommand
10
+
11
+
12
+ class HookPlugin(ApplicationPlugin):
13
+ def activate(self, application):
14
+
15
+ application.command_loader.register_factory(
16
+ BumpCommand.name,
17
+ lambda: BumpCommand(),
18
+ )
19
+ application.command_loader.register_factory(
20
+ LatestCommand.name,
21
+ lambda: LatestCommand(),
22
+ )
23
+ application.command_loader.register_factory(
24
+ SyncCommand.name,
25
+ lambda: SyncCommand(),
26
+ )
27
+
28
+
29
+ __all__ = [
30
+ "BumpCommand",
31
+ "LatestCommand",
32
+ "SyncCommand",
33
+ ]
@@ -0,0 +1,157 @@
1
+ import os
2
+ import re
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from cleo.helpers import option
7
+ from poetry.console.commands.version import VersionCommand
8
+
9
+
10
+ class PathNotFoundError(FileNotFoundError):
11
+ def __init__(self, path: os.PathLike):
12
+ errno = 2
13
+ super().__init__(
14
+ errno,
15
+ os.strerror(errno),
16
+ str(path),
17
+ )
18
+
19
+
20
+ class BumpCommand(VersionCommand):
21
+ name = "hook bump"
22
+ description = "Update the version in pyproject.toml and synchronize it into files."
23
+ help = """\
24
+ Update the version from package and also bumps __version__ strings in any given file.
25
+
26
+ <info>poetry hook bump --next-phase patch --file __init__.py</>
27
+
28
+ The new version should ideally be a valid semver string or a valid bump rule:
29
+ patch, minor, major, prepatch, preminor, premajor, prerelease.
30
+
31
+ If no next-phase or version is provied the version from the pyproject.toml file will be
32
+ synced into the files.
33
+ """
34
+
35
+ _regex = re.compile(
36
+ r"(?P<prefix>__version__\s*=\s*)(?P<quote>['\"])(?P<version>[^'\"]+)(?P=quote)",
37
+ re.IGNORECASE,
38
+ )
39
+
40
+ _del_options = ["short"]
41
+
42
+ @property
43
+ def root_dir(self) -> Path:
44
+ """
45
+ Parent of the pyproject.toml file.
46
+ """
47
+ return self.poetry.pyproject_path.parent
48
+
49
+ @property
50
+ def package(self) -> Path:
51
+ """
52
+ Path to the package directory.
53
+ """
54
+ return self.root_dir / self.poetry.package.name.replace("-", "_")
55
+
56
+ @property
57
+ def version(self) -> str:
58
+ """
59
+ Package version from the pyproject.toml file.
60
+ """
61
+
62
+ content: dict[str, Any] = self.poetry.file.read()
63
+ poetry_content = content["tool"]["poetry"]
64
+ return poetry_content["version"]
65
+
66
+ def substitute(self, file: Path, version: str) -> int:
67
+ """
68
+ Substitute the version in the file.
69
+ """
70
+
71
+ replacement = rf"\g<prefix>\g<quote>{version}\g<quote>"
72
+
73
+ content = file.read_text()
74
+
75
+ match = self._regex.search(content)
76
+
77
+ if not match:
78
+ self.line_error(
79
+ f"- Skipped: <warning>{file.relative_to(self.root_dir)}</warning>"
80
+ )
81
+ return 1
82
+
83
+ if not self.option("dry-run"):
84
+ file.write_text(
85
+ self._regex.sub(
86
+ replacement,
87
+ content,
88
+ count=1,
89
+ ),
90
+ )
91
+
92
+ self.line(f"- Bumped : <info>{file.relative_to(self.root_dir)}</info>")
93
+
94
+ return 0
95
+
96
+ def resolve(self, filename: str) -> Path:
97
+ """
98
+ Resolve the file path to the package directory.
99
+ """
100
+
101
+ file = Path(filename)
102
+
103
+ try:
104
+ file = file.resolve(True)
105
+ except FileNotFoundError:
106
+
107
+ try:
108
+ root = self.root_dir
109
+
110
+ file = root.joinpath(filename).resolve(True)
111
+ except FileNotFoundError:
112
+ package = self.package
113
+
114
+ file = package.joinpath(filename).resolve(True)
115
+
116
+ finally:
117
+ if not file.is_file():
118
+ raise PathNotFoundError(file)
119
+
120
+ return file
121
+
122
+ def configure(self) -> None:
123
+ """
124
+ Modifiy all options from `poetry version` to fit the `poetry hook bump`
125
+ command.
126
+ """
127
+ self.options = [
128
+ option(
129
+ "file",
130
+ "f",
131
+ description="Specify the files to update the __version__ string.",
132
+ flag=False,
133
+ multiple=True,
134
+ default=["__init__.py"],
135
+ )
136
+ ] + [option for option in self.options if option.name not in self._del_options]
137
+
138
+ super().configure()
139
+
140
+ def handle(self) -> int:
141
+
142
+ result = super().handle()
143
+
144
+ if result:
145
+ return result
146
+
147
+ for file in self.option("file"):
148
+ try:
149
+ file = self.resolve(file)
150
+ except PathNotFoundError as e:
151
+ if self.io.is_verbose():
152
+ self.line_error(f"- Error : <error>{e.filename}</error>")
153
+ continue
154
+
155
+ result += self.substitute(file, self.version)
156
+
157
+ return 0
@@ -1,72 +1,133 @@
1
- import re
2
-
3
- from poetry.console.commands.show import ShowCommand
4
-
5
- from .redirect import buffered_io, strip_ansi
6
-
7
-
8
- class LatestCommand(ShowCommand):
9
- name = "hook latest"
10
- description = "Check if all top-level dependencies are up-to-date."
11
- help = ""
12
-
13
- _dependencies = re.compile(
14
- r"^(?P<package>\w\S+)\s+"
15
- r"(?P<current>\d\S+)\s+"
16
- r"(?P<latest>\d\S+)\s+"
17
- r"(?P<description>\w.*?)$",
18
- re.MULTILINE,
19
- )
20
-
21
- _true_options = ["latest", "outdated", "top-level"]
22
- _del_options = ["no-dev", "tree", "all", "why"]
23
-
24
- def configure(self) -> None:
25
- """
26
- Modifiy all options from `poetry show` to fit the `poetry latest` command.
27
-
28
- Returns:
29
- None
30
- """
31
-
32
- self.options = [
33
- option for option in self.options if option.name not in self._del_options
34
- ]
35
-
36
- for opt in filter(lambda o: o.name in self._true_options, self.options):
37
- opt._description += " <warning>(option is always True)</warning>"
38
-
39
- super().configure()
40
-
41
- def handle(self) -> int:
42
- """
43
- Executes `poetry show -o -T` to check for outdated dependencies.
44
-
45
- Catches stdout to check for dependencies and returns non-zero.
46
-
47
- Returns:
48
- int: Non-zero if there are outdated dependencies, zero otherwise.
49
- """
50
-
51
- # force options to True, `poetry show -o -T`
52
- for option in self._true_options:
53
- self.io.input.set_option(option, True)
54
-
55
- # redirect output to check for outdated dependencies
56
- with buffered_io(self) as io:
57
- super().handle()
58
- text = io.fetch_output()
59
-
60
- # count outdated dependencies
61
- outdated = len(
62
- self._dependencies.findall(
63
- strip_ansi(text),
64
- )
65
- )
66
-
67
- if outdated == 0:
68
- self.line("All top-level dependencies are up-to-date.")
69
- else:
70
- self.line(text)
71
-
72
- return outdated
1
+ import re
2
+
3
+ from poetry.console.commands.show import ShowCommand
4
+
5
+ from poetry_plugin_hook.redirect import buffered_io, strip_ansi
6
+
7
+
8
+ class LatestCommand(ShowCommand):
9
+ name = "hook latest"
10
+ description = "Check if all top-level dependencies are up-to-date."
11
+ help = """\
12
+ To check if all top-level dependencies of your package are up-to-date
13
+ <info>poetry hook latest --only=main</>
14
+
15
+ If a specific package is outdated
16
+ <info>poetry hook latest <package></>
17
+ """
18
+
19
+ _version = (
20
+ r"([1-9][0-9]*!)?"
21
+ r"(0|[1-9][0-9]*)"
22
+ r"(\.(0|[1-9][0-9]*))*"
23
+ r"((a|b|rc)(0|[1-9][0-9]*))?"
24
+ r"(\.post(0|[1-9][0-9]*))?"
25
+ r"(\.dev(0|[1-9][0-9]*))?"
26
+ )
27
+ """PEP 440 version regex."""
28
+
29
+ _dependencies = re.compile(
30
+ r"^(?P<package>.*?)\s+"
31
+ rf"(?P<current>{_version})\s+"
32
+ rf"(?P<latest>{_version})\s+"
33
+ r"(?P<description>.*?)$",
34
+ re.MULTILINE,
35
+ )
36
+
37
+ _true_options = ["latest", "outdated", "top-level"]
38
+ _del_options = ["no-dev", "tree", "all", "why"]
39
+
40
+ def configure(self) -> None:
41
+ """
42
+ Modifiy all options from `poetry show -o -T` to fit the `poetry hook latest`
43
+ command.
44
+ """
45
+
46
+ self.options = [
47
+ option for option in self.options if option.name not in self._del_options
48
+ ]
49
+
50
+ for opt in filter(lambda o: o.name in self._true_options, self.options):
51
+ opt._description += " <warning>(option is always True)</warning>"
52
+
53
+ super().configure()
54
+
55
+ def handle(self) -> int:
56
+ """
57
+ Executes `poetry show -o -T` to check for outdated dependencies.
58
+
59
+ Returns:
60
+ int: Non-zero if there are outdated dependencies, zero otherwise.
61
+ """
62
+
63
+ # force options to True, `poetry show -o -T`
64
+ for option in self._true_options:
65
+ self.io.input.set_option(option, True)
66
+
67
+ # check for certain package if specified
68
+ package = self.io.input.argument("package")
69
+ if package:
70
+ self.io.input.set_argument("package", None)
71
+
72
+ # redirect output to check for outdated dependencies
73
+ with buffered_io(self) as io:
74
+ super().handle()
75
+ stdout = io.fetch_output()
76
+ stderr = io.fetch_error()
77
+
78
+ if stdout.strip() or stderr.strip():
79
+ self.line(stdout)
80
+ self.line_error(stderr)
81
+
82
+ stdout = strip_ansi(stdout)
83
+
84
+ if package is not None:
85
+ return self._handle_package(package, stdout)
86
+
87
+ return self._handle_outdated(stdout)
88
+
89
+ def _handle_outdated(self, stdout: str) -> int:
90
+ """
91
+ Handles the output of the `poetry show -o -T` command to check for outdated
92
+ dependencies.
93
+
94
+ Prints a message if all top-level dependencies are up-to-date.
95
+
96
+ Args:
97
+ stdout (str): The standard output from the `poetry show -o -T` command.
98
+
99
+ Returns:
100
+ int: The number of outdated dependencies.
101
+ """
102
+ outdated = len(self._dependencies.findall(stdout))
103
+
104
+ if outdated == 0:
105
+ self.line("All top-level dependencies are up-to-date.", style="info")
106
+
107
+ return outdated
108
+
109
+ def _handle_package(self, package: str, stdout: str) -> int:
110
+ """
111
+ Handles the output of the `poetry show -o -T` command to check for the given
112
+ package.
113
+
114
+ Prints a message if the top-level package is not found in the output.
115
+
116
+ Args:
117
+ package (str): The name of the package to check.
118
+ stdout (str): The standard output from the `poetry show -o -T` command.
119
+ Returns:
120
+ int: Returns 1 if the package is outdated otherwise returns 0.
121
+ """
122
+
123
+ _dependency = re.compile(
124
+ re.escape(package),
125
+ )
126
+
127
+ for match in self._dependencies.finditer(stdout):
128
+ _package = match.group("package").split()[0]
129
+ if _dependency.fullmatch(_package):
130
+ return 1
131
+
132
+ self.line(f"Top-level {package=} is up-to-date.", style="info")
133
+ return 0
@@ -1,82 +1,82 @@
1
- import contextlib
2
- import re
3
- from abc import ABC, abstractmethod
4
- from typing import Generator, List
5
-
6
- from cleo.io.buffered_io import BufferedIO
7
- from cleo.io.io import IO
8
-
9
-
10
- class CommandCleo(ABC):
11
- @property
12
- @abstractmethod
13
- def _io(self) -> IO:
14
- pass
15
-
16
-
17
- def strip_ansi(text: str) -> str:
18
- """
19
- Remove ANSI escape sequences from a string.
20
-
21
- Args:
22
- text (str): The string to remove ANSI escape sequences from.
23
-
24
- Returns:
25
- str: The string without ANSI escape sequences.
26
- """
27
- return re.sub(r"\x1B[@-_][0-?]*[ -/]*[@-~]", "", text)
28
-
29
-
30
- @contextlib.contextmanager
31
- def buffered_io(
32
- *args: CommandCleo,
33
- **kwargs,
34
- ) -> Generator[BufferedIO, None, None]:
35
- """
36
- Context manager that temporarily replaces the I/O of multiple Poetry commands with
37
- the same buffered I/O to capture their output.
38
-
39
- Args:
40
- *cmds (List[CommandCleo]): The Poetry commands whose I/O will be captured.
41
- **kwargs: Additional keyword arguments to pass to the BufferedIO constructor.
42
-
43
- Yields:
44
- BufferedIO: The buffered I/O object.
45
-
46
- Raises:
47
- ValueError: If any of the commands does not have an I/O attribute.
48
-
49
- Example:
50
- ```python
51
- with buffered_ios(cmd1, cmd2, decorated=False) as io:
52
- # Perform operations with the buffered I/O
53
- output = io.fetch_output()
54
- ```
55
- """
56
-
57
- # perform check if all commands have a `_io` attribute
58
- original: List[IO] = []
59
-
60
- for cmd in args:
61
- if not hasattr(cmd, "_io"):
62
- raise ValueError(f"Command {cmd} does not have an I/O attribute.")
63
-
64
- original.append(cmd._io)
65
-
66
- # create a new buffered I/O object
67
- io = BufferedIO(
68
- input=kwargs.pop("input", original[0].input),
69
- decorated=kwargs.pop("decorated", original[0].output.is_decorated()),
70
- **kwargs,
71
- )
72
-
73
- try:
74
- # assign the buffered I/O object to all commands
75
- for cmd in args:
76
- cmd._io = io
77
-
78
- yield io
79
- finally:
80
- # restore the original I/O objects
81
- for cmd, original_io in zip(args, original):
82
- cmd._io = original_io
1
+ import contextlib
2
+ import re
3
+ from abc import ABC, abstractmethod
4
+ from typing import Generator, List
5
+
6
+ from cleo.io.buffered_io import BufferedIO
7
+ from cleo.io.io import IO
8
+
9
+
10
+ class CommandCleo(ABC): # pragma: no cover
11
+ @property
12
+ @abstractmethod
13
+ def _io(self) -> IO:
14
+ pass
15
+
16
+
17
+ def strip_ansi(text: str) -> str:
18
+ """
19
+ Remove ANSI escape sequences from a string.
20
+
21
+ Args:
22
+ text (str): The string to remove ANSI escape sequences from.
23
+
24
+ Returns:
25
+ str: The string without ANSI escape sequences.
26
+ """
27
+ return re.sub(r"\x1B[@-_][0-?]*[ -/]*[@-~]", "", text)
28
+
29
+
30
+ @contextlib.contextmanager
31
+ def buffered_io(
32
+ *args: CommandCleo,
33
+ **kwargs,
34
+ ) -> Generator[BufferedIO, None, None]:
35
+ """
36
+ Context manager that temporarily replaces the I/O of multiple Poetry commands with
37
+ the same buffered I/O to capture their output.
38
+
39
+ Args:
40
+ *cmds (List[CommandCleo]): The Poetry commands whose I/O will be captured.
41
+ **kwargs: Additional keyword arguments to pass to the BufferedIO constructor.
42
+
43
+ Yields:
44
+ BufferedIO: The buffered I/O object.
45
+
46
+ Raises:
47
+ ValueError: If any of the commands does not have an I/O attribute.
48
+
49
+ Example:
50
+ ```python
51
+ with buffered_ios(cmd1, cmd2, decorated=False) as io:
52
+ # Perform operations with the buffered I/O
53
+ output = io.fetch_output()
54
+ ```
55
+ """
56
+
57
+ # perform check if all commands have a `_io` attribute
58
+ original: List[IO] = []
59
+
60
+ for cmd in args:
61
+ if not hasattr(cmd, "_io"):
62
+ raise ValueError(f"Command {cmd} does not have an I/O attribute.")
63
+
64
+ original.append(cmd._io)
65
+
66
+ # create a new buffered I/O object
67
+ io = BufferedIO(
68
+ input=kwargs.pop("input", original[0].input),
69
+ decorated=kwargs.pop("decorated", original[0].output.is_decorated()),
70
+ **kwargs,
71
+ )
72
+
73
+ try:
74
+ # assign the buffered I/O object to all commands
75
+ for cmd in args:
76
+ cmd._io = io
77
+
78
+ yield io
79
+ finally:
80
+ # restore the original I/O objects
81
+ for cmd, original_io in zip(args, original):
82
+ cmd._io = original_io
@@ -1,90 +1,106 @@
1
- import re
2
-
3
- from cleo.exceptions import CleoError
4
- from cleo.helpers import option
5
- from poetry.console.commands.install import InstallCommand
6
-
7
- from .redirect import buffered_io, strip_ansi
8
-
9
-
10
- class SyncCommand(InstallCommand):
11
- name = "hook sync"
12
- description = "Install the current project and synchronize the environment."
13
- help = ""
14
-
15
- _true_options = ["sync"]
16
- _del_options = ["no-dev", "remove-untracked", "compile"]
17
- _exit_codes = ["any", "installs", "updates", "removals"]
18
-
19
- _operations = re.compile(
20
- r"^Package operations: "
21
- r"(?P<installs>\d+)\D+"
22
- r"(?P<updates>\d+)\D+"
23
- r"(?P<removals>\d+)\D+"
24
- r"(?P<skipped>\d+)\D+$",
25
- re.MULTILINE,
26
- )
27
-
28
- def configure(self) -> None:
29
-
30
- self.options = [
31
- option(
32
- "exit",
33
- description=(
34
- "Specify the value to return as exitcode. "
35
- f"<info>choices={str(self._exit_codes)}</info>"
36
- ),
37
- flag=False,
38
- default="any",
39
- )
40
- ] + [option for option in self.options if option.name not in self._del_options]
41
-
42
- for opt in filter(lambda o: o.name in self._true_options, self.options):
43
- opt._description += " <warning>(option is always True)</warning>"
44
-
45
- super().configure()
46
-
47
- def handle(self) -> int:
48
-
49
- # check if the exit option is valid
50
- exit = self.io.input.option("exit")
51
- if exit not in self._exit_codes:
52
- raise CleoError(f"Invalid option: {exit=}")
53
-
54
- # force options to `poetry install --sync`
55
- for opt in self._true_options:
56
- self.io.input.set_option(opt, True)
57
-
58
- with buffered_io(
59
- self.installer.executor,
60
- self.installer,
61
- self,
62
- ) as io:
63
- super().handle()
64
- stdout = io.fetch_output()
65
-
66
- # parse the output for matching lines and take the last one
67
- match: re.Match = list(
68
- self._operations.finditer(
69
- strip_ansi(stdout),
70
- )
71
- )[-1]
72
-
73
- # retrive the exit code
74
- try:
75
- result = int(match.group(exit))
76
- except IndexError:
77
- result = 0
78
-
79
- for code in self._exit_codes:
80
- try:
81
- result += int(match.group(code))
82
- except IndexError:
83
- pass
84
-
85
- if result == 0:
86
- self.line(match.group(0))
87
- else:
88
- self.line(stdout)
89
-
90
- return result
1
+ import re
2
+
3
+ from cleo.exceptions import CleoLogicError
4
+ from cleo.helpers import option
5
+ from poetry.console.commands.install import InstallCommand
6
+
7
+ from poetry_plugin_hook.redirect import buffered_io, strip_ansi
8
+
9
+
10
+ class SyncCommand(InstallCommand):
11
+ name = "hook sync"
12
+ description = (
13
+ "Synchronize the environment with the locked packages and the specified groups."
14
+ )
15
+ help = """\
16
+ To check if your environment is synchronized without making any changes
17
+ <info>poetry hook sync --dry-run</>
18
+ """
19
+
20
+ _true_options = ["sync"]
21
+ _del_options = ["no-dev", "remove-untracked", "compile"]
22
+ _exit_codes = ["any", "installs", "updates", "removals"]
23
+
24
+ _operations = re.compile(
25
+ r"^Package operations: "
26
+ r"(?P<installs>\d+)\D+"
27
+ r"(?P<updates>\d+)\D+"
28
+ r"(?P<removals>\d+)\D+"
29
+ r"(?:(?P<skipped>\d+)\D+)?$",
30
+ re.MULTILINE,
31
+ )
32
+
33
+ def configure(self) -> None:
34
+ """
35
+ Modifiy all options from `poetry install --sync` to fit the `poetry hook sync`
36
+ command.
37
+
38
+ The `--exit` option is added to specify the return value of the command.
39
+ """
40
+
41
+ self.options = [
42
+ option(
43
+ "exit",
44
+ description=(
45
+ "Specify the value to return as exitcode. "
46
+ f"<info>choices={str(self._exit_codes)}</info>"
47
+ ),
48
+ flag=False,
49
+ default="any",
50
+ )
51
+ ] + [option for option in self.options if option.name not in self._del_options]
52
+
53
+ for opt in filter(lambda o: o.name in self._true_options, self.options):
54
+ opt._description += " <warning>(option is always True)</warning>"
55
+
56
+ super().configure()
57
+
58
+ def handle(self) -> int:
59
+ """
60
+ Executes `poetry install --sync` to synchronize the environment with the locked
61
+ packages and the specified groups.
62
+
63
+ Returns:
64
+ int: Non-zero exit code specified by the `--exit` option.
65
+ """
66
+
67
+ # check if the exit option is valid
68
+ exit = self.io.input.option("exit")
69
+ if exit not in self._exit_codes:
70
+ raise CleoLogicError(f"Invalid option: {exit=}")
71
+
72
+ # force options to `poetry install --sync`
73
+ for opt in self._true_options:
74
+ self.io.input.set_option(opt, True)
75
+
76
+ with buffered_io(
77
+ self.installer.executor,
78
+ self.installer,
79
+ self,
80
+ ) as io:
81
+ super().handle()
82
+ stdout = io.fetch_output()
83
+ stderr = io.fetch_error()
84
+
85
+ match = self._operations.search(strip_ansi(stdout))
86
+
87
+ # retrieve the exit code
88
+ try:
89
+ result = int(match.group(exit))
90
+ except AttributeError:
91
+ self.line("No dependencies to syncronize.", style="info")
92
+ return 0
93
+ except IndexError:
94
+ result = 0
95
+
96
+ for code in self._exit_codes:
97
+ try:
98
+ result += int(match.group(code))
99
+ except IndexError:
100
+ pass
101
+
102
+ if stdout.strip() or stderr.strip():
103
+ self.line(stdout)
104
+ self.line_error(stderr)
105
+
106
+ return result
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Christoph Dörrer
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Christoph Dörrer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,287 @@
1
+ Metadata-Version: 2.3
2
+ Name: poetry-plugin-hook
3
+ Version: 1.4.0
4
+ Summary: poetry plugin to register wrapped commands to use as pre-commit-hooks
5
+ License: MIT
6
+ Keywords: poetry,pre-commit,plugin,hook
7
+ Author: Christoph Dörrer
8
+ Author-email: d-chris@web.de
9
+ Requires-Python: >=3.9,<4.0
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Build Tools
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Dist: cleo (>=2.1.0,<3.0.0)
21
+ Requires-Dist: poetry (>=1.7.0)
22
+ Project-URL: documentation, https://d-chris.github.io/poetry-plugin-hook
23
+ Project-URL: repository, https://github.com/d-chris/poetry-plugin-hook
24
+ Description-Content-Type: text/markdown
25
+
26
+ # poetry-plugin-hook
27
+
28
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/poetry-plugin-hook)](https://pypi.org/project/poetry-plugin-hook/)
29
+ [![PyPI - Version](https://img.shields.io/pypi/v/poetry-plugin-hook)](https://pypi.org/project/poetry-plugin-hook/)
30
+ [![PyPI - Downloads](https://img.shields.io/pypi/dm/poetry-plugin-hook)](https://pypi.org/project/poetry-plugin-hook/)
31
+ [![PyPI - License](https://img.shields.io/pypi/l/poetry-plugin-hook)](https://raw.githubusercontent.com/d-chris/poetry-plugin-hook/main/LICENSE)
32
+ [![GitHub - Pytest](https://img.shields.io/github/actions/workflow/status/d-chris/poetry-plugin-hook/pytest.yml?logo=github&label=pytest)](https://github.com/d-chris/poetry-plugin-hook/actions/workflows/pytest.yml)
33
+ [![GitHub - Page](https://img.shields.io/website?url=https%3A%2F%2Fd-chris.github.io%2Fpoetry-plugin-hook&up_message=pdoc&logo=github&label=documentation)](https://d-chris.github.io/poetry-plugin-hook)
34
+ [![GitHub - Release](https://img.shields.io/github/v/tag/d-chris/poetry-plugin-hook?logo=github&label=github)](https://github.com/d-chris/poetry-plugin-hook)
35
+ [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://raw.githubusercontent.com/d-chris/poetry-plugin-hook/main/.pre-commit-config.yaml)
36
+ [![codecov](https://codecov.io/gh/d-chris/poetry-plugin-hook/graph/badge.svg?token=RNNV7TN8WZ)](https://codecov.io/gh/d-chris/poetry-plugin-hook)
37
+
38
+ ---
39
+
40
+ [`poetry`](https://python-poetry.org/) plugin to register wrapped commands to use as [`pre-commit-hooks`](https://pre-commit.com/). all hook commands return zero on success and non-zero on failure.
41
+
42
+ ## install
43
+
44
+ ```cmd
45
+ $ pip install poetry-plugin-hook
46
+ ```
47
+
48
+ or with `poetry`
49
+
50
+ > Especially on [Windows](https://python-poetry.org/docs/cli/#self), self commands that update or remove packages may be problematic.
51
+
52
+ ```cmd
53
+ $ poetry self add poetry-plugin-hook
54
+ ```
55
+
56
+ ## hook bump
57
+
58
+ Extends `poetry version` command, to also bump `__version__` strings in python files.
59
+
60
+ ```cmd
61
+ $ poetry hook bump --help
62
+
63
+ Description:
64
+ Update the version in pyproject.toml and synchronize it into files.
65
+
66
+ Usage:
67
+ hook bump [options] [--] [<version>]
68
+
69
+ Arguments:
70
+ version The version number or the rule to update the version.
71
+
72
+ Options:
73
+ -f, --file=FILE Specify the files to update the __version__ string. [default: ["__init__.py"]] (multiple values allowed)
74
+ --dry-run Do not update pyproject.toml file
75
+ --next-phase Increment the phase of the current version
76
+ -h, --help Display help for the given command. When no command is given display help for the list command.
77
+ -q, --quiet Do not output any message.
78
+ -V, --version Display this application version.
79
+ --ansi Force ANSI output.
80
+ --no-ansi Disable ANSI output.
81
+ -n, --no-interaction Do not ask any interactive question.
82
+ --no-plugins Disables plugins.
83
+ --no-cache Disables Poetry source caches.
84
+ -P, --project=PROJECT Specify another path as the project root. All command-line arguments will be resolved relative to the current working directory.
85
+ -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory). All command-line arguments will be resolved relative to the given directory.
86
+ -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
87
+
88
+ Help:
89
+ Update the version from package and also bumps __version__ strings in any given file.
90
+
91
+ poetry hook bump --next-phase patch --file __init__.py
92
+
93
+ The new version should ideally be a valid semver string or a valid bump rule:
94
+ patch, minor, major, prepatch, preminor, premajor, prerelease.
95
+
96
+ If no next-phase or version is provied the version from the pyproject.toml file will be
97
+ synced into the files.
98
+ ```
99
+
100
+ ## hook latest
101
+
102
+ Wrapper for `poetry show -o -T` command.
103
+
104
+ Exit code represents the number of outdated packages.
105
+
106
+ ```cmd
107
+ $ poetry hook latest --help
108
+
109
+ Description:
110
+ Check if all top-level dependencies are up-to-date.
111
+
112
+ Usage:
113
+ hook latest [options] [--] [<package>]
114
+
115
+ Arguments:
116
+ package The package to inspect
117
+
118
+ Options:
119
+ --without=WITHOUT The dependency groups to ignore. (multiple values allowed)
120
+ --with=WITH The optional dependency groups to include. (multiple values allowed)
121
+ --only=ONLY The only dependency groups to include. (multiple values allowed)
122
+ -l, --latest Show the latest version. (option is always True)
123
+ -o, --outdated Show the latest version but only for packages that are outdated. (option is always True)
124
+ -T, --top-level Show only top-level dependencies. (option is always True)
125
+ -h, --help Display help for the given command. When no command is given display help for the list command.
126
+ -q, --quiet Do not output any message.
127
+ -V, --version Display this application version.
128
+ --ansi Force ANSI output.
129
+ --no-ansi Disable ANSI output.
130
+ -n, --no-interaction Do not ask any interactive question.
131
+ --no-plugins Disables plugins.
132
+ --no-cache Disables Poetry source caches.
133
+ -P, --project=PROJECT Specify another path as the project root. All command-line arguments will be resolved relative to the current working directory.
134
+ -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory). All command-line arguments will be resolved relative to the given directory.
135
+ -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
136
+
137
+ Help:
138
+ To check if all top-level dependencies of your package are up-to-date
139
+ poetry hook latest --only=main
140
+
141
+ If a specific package is outdated
142
+ poetry hook latest <package>
143
+ ```
144
+
145
+ ## hook sync
146
+
147
+ Wrapper for `poetry install --sync` command.
148
+
149
+ With `--exit` option, the command returns the corresponding value as exit code. With it's default `--exit=any` the sum of *installs*, *updates* and *removals* is returned.
150
+
151
+ ```cmd
152
+ $ poetry hook sync --help
153
+
154
+ Description:
155
+ Synchronize the environment with the locked packages and the specified groups.
156
+
157
+ Usage:
158
+ hook sync [options]
159
+
160
+ Options:
161
+ --exit=EXIT Specify the value to return as exitcode. choices=['any', 'installs', 'updates', 'removals'] [default: "any"]
162
+ --without=WITHOUT The dependency groups to ignore. (multiple values allowed)
163
+ --with=WITH The optional dependency groups to include. (multiple values allowed)
164
+ --only=ONLY The only dependency groups to include. (multiple values allowed)
165
+ --sync Synchronize the environment with the locked packages and the specified groups. (Deprecated) (option is always True)
166
+ --no-root Do not install the root package (the current project).
167
+ --no-directory Do not install any directory path dependencies; useful to install dependencies without source code, e.g. for caching of Docker layers)
168
+ --dry-run Output the operations but do not execute anything (implicitly enables --verbose).
169
+ -E, --extras=EXTRAS Extra sets of dependencies to install. (multiple values allowed)
170
+ --all-extras Install all extra dependencies.
171
+ --all-groups Install dependencies from all groups.
172
+ --only-root Exclude all dependencies.
173
+ -h, --help Display help for the given command. When no command is given display help for the list command.
174
+ -q, --quiet Do not output any message.
175
+ -V, --version Display this application version.
176
+ --ansi Force ANSI output.
177
+ --no-ansi Disable ANSI output.
178
+ -n, --no-interaction Do not ask any interactive question.
179
+ --no-plugins Disables plugins.
180
+ --no-cache Disables Poetry source caches.
181
+ -P, --project=PROJECT Specify another path as the project root. All command-line arguments will be resolved relative to the current working directory.
182
+ -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory). All command-line arguments will be resolved relative to the given directory.
183
+ -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
184
+
185
+ Help:
186
+ To check if your environment is synchronized without making any changes
187
+ poetry hook sync --dry-run
188
+ ```
189
+
190
+ ## pre-commit-config
191
+
192
+ Add the following to your `.pre-commit-config.yaml` file.
193
+
194
+ ```yaml
195
+ default_install_hook_types:
196
+ - pre-commit
197
+ - pre-push
198
+ default_stages:
199
+ - pre-commit
200
+ repos:
201
+ - repo: https://github.com/d-chris/poetry-plugin-hook
202
+ rev: v1.2.1
203
+ hooks:
204
+ - id: poetry-hook-bump
205
+ - id: poetry-hook-latest
206
+ args: ["--only=main"]
207
+ - id: poetry-hook-sync
208
+ args: ["--dry-run"]
209
+ ```
210
+
211
+ ### usage
212
+
213
+ 1. Make sure pre-commit is installed, see [official documentation](https://pre-commit.com/#installation).
214
+ ```cmd
215
+ $ pre-commit --version
216
+
217
+ pre-commit 3.7.1
218
+ ```
219
+ 2. `cd` into your project and register hooks and install them. this may take a while.
220
+ ```cmd
221
+ $ pre-commit install --install-hooks
222
+
223
+ pre-commit installed at .git\hooks\pre-commit
224
+ pre-commit installed at .git\hooks\pre-push
225
+ ```
226
+ 3. Test the pre-push hook.
227
+ ```cmd
228
+ $ pre-commit run poetry-hook-latest --all-files --hook-stage pre-push
229
+
230
+ poetry-hook-latest.......................................................Failed
231
+ - hook id: poetry-hook-latest
232
+ - exit code: 1
233
+
234
+ pytest-cov 5.0.0 6.0.0 Pytest plugin for measuring coverage.
235
+ ```
236
+ 4. Test the pre-commit hooks.
237
+ ```cmd
238
+ $ pre-commit run poetry-hook-sync --all-files
239
+
240
+ poetry-hook-sync.........................................................Failed
241
+ - hook id: poetry-hook-sync
242
+ - exit code: 1
243
+
244
+ Installing dependencies from lock file
245
+
246
+ Package operations: 0 installs, 1 update, 0 removals
247
+
248
+ - Downgrading pytest-cov (6.0.0 -> 5.0.0)
249
+
250
+ Installing the current project: poetry-plugin-hook (0.0.0)
251
+ ```
252
+
253
+ ## pre-commit-hooks
254
+
255
+ ```yaml
256
+ - id: poetry-hook-bump
257
+ name: poetry-hook-bump
258
+ description: Bump the version of the package and also in files.
259
+ entry: poetry hook bump
260
+ language: system
261
+ pass_filenames: false
262
+ always_run: true
263
+ stages: [pre-push]
264
+ - id: poetry-hook-latest
265
+ name: poetry-hook-latest
266
+ description: Check if all top-level dependencies are up-to-date.
267
+ entry: poetry hook latest
268
+ language: system
269
+ pass_filenames: false
270
+ always_run: true
271
+ stages: [pre-push]
272
+ - id: poetry-hook-sync
273
+ name: poetry-hook-sync
274
+ description: Synchronize the environment with the locked packages and the specified groups.
275
+ entry: poetry hook sync
276
+ language: system
277
+ pass_filenames: false
278
+ files: ^(.*/)?(poetry\.lock|pyproject\.toml)$
279
+ ```
280
+
281
+ ## Dependencies
282
+
283
+ [![PyPI - cleo](https://img.shields.io/pypi/v/cleo?logo=pypi&logoColor=white&label=cleo)](https://pypi.org/project/cleo/)
284
+ [![PyPI - poetry](https://img.shields.io/pypi/v/poetry?logo=poetry&logoColor=white&label=poetry)](https://pypi.org/project/poetry/)
285
+
286
+ ---
287
+
@@ -0,0 +1,10 @@
1
+ poetry_plugin_hook/__init__.py,sha256=6QewfFFP69aVHMK3v1FyCNJLA3YMkMkz9RfJ1RYsDXI,788
2
+ poetry_plugin_hook/bump.py,sha256=AH2aNa2eJHXtzjt3r8jGZfEDJ_csUw5-Kgcm1LAAnuc,4176
3
+ poetry_plugin_hook/latest.py,sha256=gybKBpqVRzA5z9Xjn4u4okML-Ddn0MrZ76EKBd78t-k,4046
4
+ poetry_plugin_hook/redirect.py,sha256=uDe-xlXKmyJqBGw9HEFy_HhAPr37HDAAIMMQyjd2Ibg,2153
5
+ poetry_plugin_hook/sync.py,sha256=kY7Ac_-UbI2_iFHZQUJDSNW3vPfM8kEPM5F7yh9IhKs,3211
6
+ poetry_plugin_hook-1.4.0.dist-info/LICENSE,sha256=Ht_pJ-L8m2lTUYYUJK3BKAef0sGTcaITzbPtGy4qZxk,1074
7
+ poetry_plugin_hook-1.4.0.dist-info/METADATA,sha256=xehytre7EvfpW6KjETpby7X5E8h5-VPThCbrT3P2ah4,12634
8
+ poetry_plugin_hook-1.4.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
9
+ poetry_plugin_hook-1.4.0.dist-info/entry_points.txt,sha256=kl0zCMvjQc4wRSKYgkhJYdTacDKVxgBuc27bBMwlqdc,64
10
+ poetry_plugin_hook-1.4.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.8.1
2
+ Generator: poetry-core 2.0.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,55 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: poetry-plugin-hook
3
- Version: 0.0.0
4
- Summary: poetry plugin to register new command to check if all dependencies are up-to-date
5
- Author: Christoph Dörrer
6
- Author-email: d-chris@web.de
7
- Requires-Python: >=3.9,<4.0
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.9
10
- Classifier: Programming Language :: Python :: 3.10
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Requires-Dist: cleo (>=2.1.0,<3.0.0)
14
- Requires-Dist: poetry (>=1.8.0,<2.0.0)
15
- Description-Content-Type: text/markdown
16
-
17
- # poetry-plugin-latest
18
-
19
- poetry plugin to add a command to check if all dependencies are up-to-date
20
-
21
- ```cmd
22
- $ poetry latest --help
23
-
24
- Description:
25
- Check if all top-level dependencies are up-to-date
26
-
27
- Usage:
28
- latest [options] [--] [<package>]
29
-
30
- Arguments:
31
- package The package to inspect
32
-
33
- Options:
34
- --without=WITHOUT The dependency groups to ignore. (multiple values allowed)
35
- --with=WITH The optional dependency groups to include. (multiple values allowed)
36
- --only=ONLY The only dependency groups to include. (multiple values allowed)
37
- -l, --latest Show the latest version. (option is always True)
38
- -o, --outdated Show the latest version but only for packages that are outdated. (option is always True)
39
- -T, --top-level Show only top-level dependencies. (option is always True)
40
- -h, --help Display help for the given command. When no command is given display help for the list command.
41
- -q, --quiet Do not output any message.
42
- -V, --version Display this application version.
43
- --ansi Force ANSI output.
44
- --no-ansi Disable ANSI output.
45
- -n, --no-interaction Do not ask any interactive question.
46
- --no-plugins Disables plugins.
47
- --no-cache Disables Poetry source caches.
48
- -C, --directory=DIRECTORY The working directory for the Poetry command (defaults to the current working directory).
49
- -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
50
-
51
- Help:
52
- The show command displays detailed information about a package, or
53
- lists all packages available.
54
- ```
55
-
@@ -1,9 +0,0 @@
1
- poetry_plugin_hook/__init__.py,sha256=voDfXAXN5fseTNp3WoYqmws0RuXlbpwaWCI4BlFTtIg,483
2
- poetry_plugin_hook/latest.py,sha256=3Bq_Lp_VN7N47lcAd4eNRnT3yxuKokZpLQHAhvcD7Pg,2053
3
- poetry_plugin_hook/redirect.py,sha256=gauxL6c7Zy33hwvOqYCBng83ajdELJcRTWDpU2J4J5k,2215
4
- poetry_plugin_hook/sync.py,sha256=g22_JTJfWL9RM21h_jWncGnRa_KlDIIHyl_9PSV3ZW0,2640
5
- poetry_plugin_hook-0.0.0.dist-info/entry_points.txt,sha256=kl0zCMvjQc4wRSKYgkhJYdTacDKVxgBuc27bBMwlqdc,64
6
- poetry_plugin_hook-0.0.0.dist-info/LICENSE,sha256=r4et7kLDvZTYdQubvsPzH-Mq2FVYd6u4VsVBkiAuuf8,1095
7
- poetry_plugin_hook-0.0.0.dist-info/METADATA,sha256=ufgjCPaR32BqPae_8QwxWAssq5FgTxyzWrWIKna_ieg,2358
8
- poetry_plugin_hook-0.0.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
9
- poetry_plugin_hook-0.0.0.dist-info/RECORD,,