Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: check for mutually exclusive markers #7970

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions src/poetry/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import re

from itertools import combinations
from typing import TYPE_CHECKING
from typing import Any
from typing import cast
Expand Down Expand Up @@ -358,7 +359,15 @@ def validate(

results["errors"].extend(validate_object(config))

# A project should not depend on itself.
cls._validate_project_should_not_depend_on_itself(config, results)
cls._validate_dependencies_have_mutually_exclusive_markers(config, results)

return results

@staticmethod
def _validate_project_should_not_depend_on_itself(
config: dict[str, Any], results: dict[str, list[str]]
) -> None:
dependencies = set(config.get("dependencies", {}).keys())
dependencies.update(config.get("dev-dependencies", {}).keys())
groups = config.get("group", {}).values()
Expand All @@ -369,7 +378,33 @@ def validate(

if canonicalize_name(config["name"]) in dependencies:
results["errors"].append(
f"Project name ({config['name']}) is same as one of its dependencies"
f"Project name ({config['name']}) is same as one of its dependencies."
)

return results
@classmethod
def _validate_dependencies_have_mutually_exclusive_markers(
cls, config: dict[str, Any], results: dict[str, list[str]]
) -> None:
dep_groups = [
config.get("dependencies", {}),
config.get("dev-dependencies", {}),
*(
group.get("dependencies", {})
for group in config.get("group", {}).values()
),
]
for group in dep_groups:
for name, constraints in group.items():
if isinstance(constraints, list) and len(constraints) > 1:
deps = [
cls.create_dependency(name, constraint)
for constraint in constraints
]
if not all(
d1.marker.intersect(d2.marker).is_empty()
for d1, d2 in combinations(deps, 2)
):
results["errors"].append(
f"Dependency {name} does not have mutually exclusive"
" markers."
)
3 changes: 2 additions & 1 deletion tests/console/commands/test_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def test_check_invalid(

expected = """\
Error: 'description' is a required property
Error: Project name (invalid) is same as one of its dependencies
Error: Project name (invalid) is same as one of its dependencies.
Error: Dependency pillow does not have mutually exclusive markers.
Error: Unrecognized classifiers: ['Intended Audience :: Clowns'].
Warning: A wildcard Python dependency is ambiguous.\
Consider specifying a more explicit one.
Expand Down
18 changes: 10 additions & 8 deletions tests/fixtures/invalid_pyproject/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
[tool.poetry]
name = "invalid"
version = "1.0.0"
authors = [
"Foo <[email protected]>"
]
license = "INVALID"
authors = ["Foo <[email protected]>"]
classifiers = [
"Environment :: Console",
"Intended Audience :: Clowns",
"Natural Language :: Ukranian",
"Topic :: Communications :: Chat :: AOL Instant Messenger",
]
license = "INVALID"
name = "invalid"
version = "1.0.0"

[tool.poetry.dependencies]
python = "*"
pendulum = {"version" = "^2.0.5", allows-prereleases = true}
invalid = "1.0"
pendulum = { "version" = "^2.0.5", allows-prereleases = true }
pillow = [
{ version = "^9", python = "^3.9" },
{ version = "^7", python = "^3.7" },
]
python = "*"
3 changes: 2 additions & 1 deletion tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,8 @@ def test_create_poetry_fails_on_invalid_configuration(
expected = """\
The Poetry configuration is invalid:
- 'description' is a required property
- Project name (invalid) is same as one of its dependencies
- Project name (invalid) is same as one of its dependencies.
- Dependency pillow does not have mutually exclusive markers.
"""
assert str(e.value) == expected

Expand Down