Skip to content
This repository was archived by the owner on Jul 12, 2025. It is now read-only.

Commit ae5d346

Browse files
authored
Merge pull request #18 from souliane/refactor-get-poetry-deps
2 parents 7e56f1e + 979bc38 commit ae5d346

File tree

3 files changed

+53
-32
lines changed

3 files changed

+53
-32
lines changed

poetry_to_pre_commit/common.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,18 @@ def pre_commit_config_roundtrip(
2323
yaml.dump(config, path)
2424

2525

26-
@dataclasses.dataclass
26+
@dataclasses.dataclass(frozen=True, order=True)
2727
class PoetryPackage:
2828
name: str
29-
version: str
29+
version: str = "*"
30+
extras: frozenset[str] = dataclasses.field(default_factory=frozenset)
31+
32+
def __str__(self) -> str:
33+
if self.extras:
34+
extras = ",".join(sorted(self.extras))
35+
return f"{self.name}[{extras}]=={self.version}"
36+
else:
37+
return f"{self.name}=={self.version}"
3038

3139

3240
def get_poetry_packages(cwd: pathlib.Path | None = None) -> Iterable[PoetryPackage]:
@@ -35,6 +43,5 @@ def get_poetry_packages(cwd: pathlib.Path | None = None) -> Iterable[PoetryPacka
3543

3644
for package in repository.packages:
3745
yield PoetryPackage(
38-
name=package.name,
39-
version=package.version.text,
46+
name=package.name, version=package.version.text, extras=package.features
4047
)

poetry_to_pre_commit/sync_hooks_additional_dependencies.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ def get_sync_hooks_additional_dependencies_parser() -> argparse.ArgumentParser:
5555
return parser
5656

5757

58-
def get_poetry_deps(*, cwd: pathlib.Path | None = None, group: str) -> Iterable[str]:
58+
def get_poetry_deps(
59+
*, cwd: pathlib.Path | None = None, group: str
60+
) -> Iterable[common.PoetryPackage]:
5961
package_by_name = {p.name: p for p in common.get_poetry_packages(cwd=cwd)}
6062
main_package = factory.Factory().create_poetry(cwd=cwd).package
6163
try:
@@ -71,28 +73,25 @@ def get_poetry_deps(*, cwd: pathlib.Path | None = None, group: str) -> Iterable[
7173
f"Package not found in poetry.lock: {dep.name}. "
7274
"Is your poetry.lock up-to-date?"
7375
) from e
74-
yield f"{dep.complete_name}=={package.version}"
76+
yield common.PoetryPackage(
77+
name=dep.name, version=package.version, extras=dep.extras
78+
)
7579

7680

7781
def update_or_remove_additional_deps(
78-
poetry_deps: set[str], hook_additional_deps: list[str]
79-
) -> set[str]:
82+
poetry_deps: set[common.PoetryPackage], hook_additional_deps: list[str]
83+
) -> set[common.PoetryPackage]:
8084
# Additional packages that are already in pre-commit configuration could be listed with
8185
# any format that is accepted by pip - use `Requirement` to parse them properly.
8286
current_deps = [Requirement(dep).name for dep in hook_additional_deps]
8387

84-
return {
85-
package
86-
for package in poetry_deps
87-
# package is yielded by `get_poetry_deps` above, and we are pretty sure that this won't raise `IndexError`
88-
if package.split("==")[0].split("[")[0] in current_deps
89-
}
88+
return {package for package in poetry_deps if package.name in current_deps}
9089

9190

9291
def _sync_hooks_additional_dependencies(
9392
*,
9493
config: dict[str, Any],
95-
deps_by_group: dict[str, set[str]],
94+
deps_by_group: dict[str, set[common.PoetryPackage]],
9695
bind: dict[str, set[str]],
9796
no_new_deps: bool = False,
9897
) -> None:
@@ -112,19 +111,22 @@ def _sync_hooks_additional_dependencies(
112111
groups = bind[hook_id]
113112
except KeyError:
114113
continue
115-
deps: set[str] = set()
114+
deps: set[common.PoetryPackage] = set()
116115

117116
for group in groups:
118117
deps.update(deps_by_group.get(group, set()))
119118

120-
hook["additional_dependencies"] = sorted(
119+
packages = (
121120
update_or_remove_additional_deps(
122121
poetry_deps=deps,
123122
hook_additional_deps=hook["additional_dependencies"],
124123
)
125124
if no_new_deps
126125
else deps
127126
)
127+
hook["additional_dependencies"] = sorted(
128+
str(package) for package in packages
129+
)
128130

129131

130132
def sync_hooks_additional_dependencies(
@@ -137,7 +139,7 @@ def sync_hooks_additional_dependencies(
137139
args = parser.parse_args(argv)
138140

139141
bind = combine_bind_values(args.bind)
140-
deps_by_group: dict[str, set[str]] = {}
142+
deps_by_group: dict[str, set[common.PoetryPackage]] = {}
141143

142144
for groups in bind.values():
143145
for group in groups:

tests/test_sync_hooks_additional_dependencies.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import ruamel.yaml
77

88
from poetry_to_pre_commit import sync_hooks_additional_dependencies
9+
from poetry_to_pre_commit.common import PoetryPackage
910

1011

1112
@pytest.mark.parametrize(
@@ -33,9 +34,7 @@ def test_combine_bind_values() -> None:
3334

3435

3536
def test_get_sync_hooks_additional_dependencies_parser() -> None:
36-
parser = (
37-
sync_hooks_additional_dependencies.get_sync_hooks_additional_dependencies_parser()
38-
)
37+
parser = sync_hooks_additional_dependencies.get_sync_hooks_additional_dependencies_parser()
3938
assert parser.parse_args(["--bind", "foo=bar,baz", "--bind", "foo=qux"]).bind == [
4039
("foo", {"bar", "baz"}),
4140
("foo", {"qux"}),
@@ -51,9 +50,9 @@ def test_get_poetry_deps(poetry_cwd: Path) -> None:
5150
)
5251

5352
assert sorted(results) == [
54-
"flake8==7.0.0",
55-
"pylint==3.1.0",
56-
"pyright==1.1.355",
53+
PoetryPackage("flake8", "7.0.0"),
54+
PoetryPackage("pylint", "3.1.0"),
55+
PoetryPackage("pyright", "1.1.355"),
5756
]
5857

5958

@@ -130,16 +129,29 @@ def test_sync_hooks_additional_dependencies(tmp_path: Path, poetry_cwd: Path) ->
130129
@pytest.mark.parametrize(
131130
("poetry_deps", "additional_deps", "expected_additional_deps"),
132131
[
133-
(["a==1", "b"], ["a"], ["a==1"]),
134-
(["a==1", "b"], ["a[x]==2"], ["a==1"]),
135-
(["a[x]==1", "b"], ["a"], ["a[x]==1"]),
136-
(["a[x]==1", "b"], ["a[x]"], ["a[x]==1"]),
137-
(["a==1", "b"], ["a == 2"], ["a==1"]),
138-
(["a==1", "b"], ["a<=2"], ["a==1"]),
139-
(["a==1", "b"], ["a>=1"], ["a==1"]),
132+
({PoetryPackage("a", "1"), PoetryPackage("b")}, ["a"], ["a==1"]),
133+
({PoetryPackage("a", "1"), PoetryPackage("b")}, ["a[x]==2"], ["a==1"]),
134+
(
135+
{PoetryPackage("a", "1", frozenset({"x"})), PoetryPackage("b")},
136+
["a"],
137+
["a[x]==1"],
138+
),
139+
(
140+
{PoetryPackage("a", "1", frozenset({"x"})), PoetryPackage("b")},
141+
["a[x]"],
142+
["a[x]==1"],
143+
),
144+
(
145+
{PoetryPackage("a", "1", frozenset({"x", "y"})), PoetryPackage("b")},
146+
["a[x]"],
147+
["a[x,y]==1"],
148+
),
149+
({PoetryPackage("a", "1"), PoetryPackage("b")}, ["a == 2"], ["a==1"]),
150+
({PoetryPackage("a", "1"), PoetryPackage("b")}, ["a<=2"], ["a==1"]),
151+
({PoetryPackage("a", "1"), PoetryPackage("b")}, ["a>=1"], ["a==1"]),
140152
],
141153
)
142-
def test__sync_hooks_additional_deps__no_new_deps(
154+
def test__sync_hooks_additional_dependencies__no_new_deps(
143155
poetry_deps, additional_deps, expected_additional_deps
144156
) -> None:
145157
"""Check that `_sync_hooks_additional_dependencies` handles the different ways to write a package entry."""

0 commit comments

Comments
 (0)