Skip to content

Commit

Permalink
Added more v2 tests and added support for PEP621 pyproject.toml files (
Browse files Browse the repository at this point in the history
…#54)

* Added more v2 tests and added support for PEP621 pyproject.toml files

* Fixed mypy issues

* Supress import error on 1.8.5
  • Loading branch information
ag14774 authored Jan 29, 2025
1 parent 4bad19a commit a5f23fa
Show file tree
Hide file tree
Showing 21 changed files with 398 additions and 73 deletions.
52 changes: 49 additions & 3 deletions poetry_monoranger_plugin/path_rewriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,30 @@

from __future__ import annotations

from contextlib import suppress
from typing import TYPE_CHECKING, cast

import poetry.__version__
from mypy.checkexpr import defaultdict
from poetry.console.commands.build import BuildCommand
from poetry.core.constraints.version import Version
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.dependency_group import MAIN_GROUP
from poetry.core.packages.directory_dependency import DirectoryDependency
from poetry.core.pyproject.toml import PyProjectTOML

with suppress(ImportError):
from poetry.core.pyproject.exceptions import PyProjectError # type: ignore[attr-defined] # exists only in >=2.0.0

if TYPE_CHECKING:
from cleo.events.console_command_event import ConsoleCommandEvent
from poetry.core.packages.dependency_group import DependencyGroup
from poetry.poetry import Poetry

from poetry_monoranger_plugin.config import MonorangerConfig

POETRY_V2 = poetry.__version__.__version__.startswith("2.")


class PathRewriter:
"""A class to handle the rewriting of directory dependencies in a Poetry project."""
Expand All @@ -43,7 +52,7 @@ def execute(self, event: ConsoleCommandEvent):
poetry = command.poetry

main_deps_group = poetry.package.dependency_group(MAIN_GROUP)
directory_deps = [dep for dep in main_deps_group.dependencies if isinstance(dep, DirectoryDependency)]
directory_deps = self._get_directory_deps(main_deps_group)

for dependency in directory_deps:
try:
Expand All @@ -55,6 +64,37 @@ def execute(self, event: ConsoleCommandEvent):
main_deps_group.remove_dependency(dependency.name)
main_deps_group.add_dependency(pinned)

@staticmethod
def _get_directory_deps(dep_grp: DependencyGroup) -> list[DirectoryDependency]:
if not POETRY_V2:
return [dep for dep in dep_grp.dependencies if isinstance(dep, DirectoryDependency)]

# Collect extras
features: defaultdict[str, set] = defaultdict(set)
for dep_set in [dep_grp._poetry_dependencies, dep_grp.dependencies, dep_grp.dependencies_for_locking]: # type: ignore[attr-defined]
# Collect all extras for each dependency from all three ways of accessing deps
# (._poetry_dependencies, .dependencies, .dependencies_for_locking)
if dep_set is not None:
for dep in dep_set:
if dep.features:
features[dep.name].update(dep.features)

# Required to have type: ignore[attr-defined] as the attribute is only defined in Poetry >=2.0.0
deps_for_locking = {dep.name: dep for dep in dep_grp.dependencies_for_locking} # type: ignore[attr-defined]

directory_deps = []
for dep in dep_grp.dependencies:
if isinstance(dep, DirectoryDependency):
dir_dep = dep
elif isinstance(deps_for_locking.get(dep.name, None), DirectoryDependency):
dir_dep = cast(DirectoryDependency, deps_for_locking[dep.name])
else:
continue

directory_deps.append(dir_dep.with_features(features[dir_dep.name]))

return directory_deps

def _get_dependency_pyproject(self, poetry: Poetry, dependency: DirectoryDependency) -> PyProjectTOML:
pyproject_file = poetry.pyproject_path.parent / dependency.path / "pyproject.toml"

Expand Down Expand Up @@ -84,8 +124,14 @@ def _pin_dependency(self, poetry: Poetry, dependency: DirectoryDependency):
"""
dep_pyproject: PyProjectTOML = self._get_dependency_pyproject(poetry, dependency)

name = cast(str, dep_pyproject.poetry_config["name"])
version = cast(str, dep_pyproject.poetry_config["version"])
try:
name = cast(str, dep_pyproject.poetry_config["name"])
version = cast(str, dep_pyproject.poetry_config["version"])
except PyProjectError:
# Fallback to the project section since Poetry V2 also supports PEP 621 pyproject.toml files
name = cast(str, dep_pyproject.data["project"]["name"])
version = cast(str, dep_pyproject.data["project"]["version"])

if self.plugin_conf.version_rewrite_rule in ["~", "^"]:
pinned_version = f"{self.plugin_conf.version_rewrite_rule}{version}"
elif self.plugin_conf.version_rewrite_rule == "==":
Expand Down
6 changes: 3 additions & 3 deletions tests/fixtures/v1/pkg_one/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ readme = "README.md"
[tool.poetry.dependencies]
python = "^3.9"

# A list of all of the optional dependencies, some of which are included in the
# A list of all the optional dependencies, some of which are included in the
# below `extras`. They can be opted into by apps.
pandas = { version = "^2.0.0", optional = true }
fsspec = { version = "^2024.12.0", optional = true }

[tool.poetry.extras]
withpandas = ["pandas"]
withfsspec = ["fsspec"]

[tool.poetry-monoranger-plugin]
enabled = true
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/v1/pkg_three/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ readme = "README.md"

[tool.poetry.dependencies]
python = "^3.9"
pkg-two = { path = '../pkg_two', develop = true, extras = ["withpandas"] }
pkg-one = { path = '../pkg_one', develop = true, extras = ["withfsspec"] }

[tool.poetry-monoranger-plugin]
enabled = true
Expand Down
46 changes: 44 additions & 2 deletions tests/fixtures/v1/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.
Empty file.
2 changes: 2 additions & 0 deletions tests/fixtures/v2/pkg_one/poetry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[virtualenvs]
create = false
23 changes: 23 additions & 0 deletions tests/fixtures/v2/pkg_one/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[project]
name = "pkg-one"
version = "0.1.0"
description = ""
authors = [
{name = "Example Example",email = "[email protected]"}
]
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
]

[project.optional-dependencies]
withfsspec = ["fsspec (>=2024.12.0,<2025.0.0)"]

[tool.poetry-monoranger-plugin]
enabled = true
monorepo-root = "../"
version-rewrite-rule = '=='

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
Empty file.
Empty file.
2 changes: 2 additions & 0 deletions tests/fixtures/v2/pkg_three/poetry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[virtualenvs]
create = false
24 changes: 24 additions & 0 deletions tests/fixtures/v2/pkg_three/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[project]
name = "pkg-three"
version = "0.1.0"
description = ""
authors = [
{name = "Example Example",email = "[email protected]"}
]
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"pkg-one"
]

[tool.poetry-monoranger-plugin]
enabled = true
monorepo-root = "../"
version-rewrite-rule = '=='

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.dependencies]
pkg-one = {path = "../pkg_one", develop = true, extras = ["withfsspec"]}
Empty file.
Empty file.
2 changes: 2 additions & 0 deletions tests/fixtures/v2/pkg_two/poetry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[virtualenvs]
create = false
21 changes: 21 additions & 0 deletions tests/fixtures/v2/pkg_two/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[project]
name = "pkg-two"
version = "0.1.0"
description = ""
authors = [
{name = "Example Example",email = "[email protected]"}
]
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"tqdm (>=4.67.1,<5.0.0)"
]

[tool.poetry-monoranger-plugin]
enabled = true
monorepo-root = "../"
version-rewrite-rule = '=='

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
120 changes: 120 additions & 0 deletions tests/fixtures/v2/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tests/fixtures/v2/poetry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[virtualenvs]
in-project = true
Loading

0 comments on commit a5f23fa

Please sign in to comment.