Commit a4c95359 by David Hotham Committed by GitHub

check for circular self-dependency (#7757)

parent a770b3ac
......@@ -126,6 +126,7 @@ The add command adds required packages to your <comment>pyproject.toml</> and in
# dictionary.
content: dict[str, Any] = self.poetry.file.read()
poetry_content = content["tool"]["poetry"]
project_name = canonicalize_name(poetry_content["name"])
if group == MAIN_GROUP:
if "dependencies" not in poetry_content:
......@@ -223,6 +224,14 @@ The add command adds required packages to your <comment>pyproject.toml</> and in
canonical_constraint_name = canonicalize_name(constraint_name)
if canonical_constraint_name == project_name:
self.line_error(
f"<error>Cannot add dependency on <c1>{constraint_name}</c1> to"
" project with the same name."
)
self.line_error("\nNo changes were applied.")
return 1
for key in section:
if canonicalize_name(key) == canonical_constraint_name:
section[key] = constraint
......
......@@ -9,6 +9,7 @@ from typing import Any
from typing import cast
from cleo.io.null_io import NullIO
from packaging.utils import canonicalize_name
from poetry.core.factory import Factory as BaseFactory
from poetry.core.packages.dependency_group import MAIN_GROUP
from poetry.core.packages.project_package import ProjectPackage
......@@ -319,4 +320,18 @@ class Factory(BaseFactory):
results["errors"].extend(validate_object(config))
# A project should not depend on itself.
dependencies = set(config.get("dependencies", {}).keys())
dependencies.update(config.get("dev-dependencies", {}).keys())
groups = config.get("group", {}).values()
for group in groups:
dependencies.update(group.get("dependencies", {}).keys())
dependencies = {canonicalize_name(d) for d in dependencies}
if canonicalize_name(config["name"]) in dependencies:
results["errors"].append(
f"Project name ({config['name']}) is same as one of its dependencies"
)
return results
......@@ -1073,6 +1073,18 @@ If you prefer to upgrade it to the latest available version,\
assert expected in tester.io.fetch_output()
def test_add_should_fail_circular_dependency(
app: PoetryTestApplication, repo: TestRepository, tester: CommandTester
) -> None:
repo.add_package(get_package("simple-project", "1.1.2"))
result = tester.execute("simple-project")
assert result == 1
expected = "Cannot add dependency on simple-project to project with the same name."
assert expected in tester.io.fetch_error()
def test_add_latest_should_not_create_duplicate_keys(
project_factory: ProjectFactory,
repo: TestRepository,
......
......@@ -43,6 +43,7 @@ def test_check_invalid(
expected = """\
Error: 'description' is a required property
Error: Project name (invalid) is same as one of its dependencies
Error: Unrecognized classifiers: ['Intended Audience :: Clowns'].
Warning: A wildcard Python dependency is ambiguous.\
Consider specifying a more explicit one.
......
......@@ -15,3 +15,4 @@ classifiers = [
[tool.poetry.dependencies]
python = "*"
pendulum = {"version" = "^2.0.5", allows-prereleases = true}
invalid = "1.0"
[tool.poetry]
name = "my-package"
name = "sample-project"
version = "1.2.3"
description = "Some description."
authors = [
......@@ -51,7 +51,7 @@ pytest = "~3.4"
[tool.poetry.scripts]
my-script = "my_package:main"
my-script = "sample_project:main"
[tool.poetry.plugins."blogtool.parsers"]
......
[tool.poetry]
name = "my-package"
name = "with-default-source"
version = "1.2.3"
description = "Some description."
authors = [
......@@ -48,7 +48,7 @@ pytest = "~3.4"
[tool.poetry.scripts]
my-script = "my_package:main"
my-script = "with_default_source:main"
[tool.poetry.plugins."blogtool.parsers"]
......
[tool.poetry]
name = "my-package"
name = "default-source-legacy"
version = "1.2.3"
description = "Some description."
authors = [
......@@ -48,7 +48,7 @@ pytest = "~3.4"
[tool.poetry.scripts]
my-script = "my_package:main"
my-script = "default_source_legacy:main"
[tool.poetry.plugins."blogtool.parsers"]
......
[tool.poetry]
name = "my-package"
name = "with-explicit-source"
version = "1.2.3"
description = "Some description."
authors = [
......
[tool.poetry]
name = "my-package"
name = "local-config"
version = "1.2.3"
description = "Some description."
authors = [
......@@ -48,7 +48,7 @@ pytest = "~3.4"
[tool.poetry.scripts]
my-script = "my_package:main"
my-script = "local_config:main"
[tool.poetry.plugins."blogtool.parsers"]
......
[tool.poetry]
name = "my-package"
name = "two-default-sources"
version = "1.2.3"
description = "Some description."
authors = [
......@@ -48,7 +48,7 @@ pytest = "~3.4"
[tool.poetry.scripts]
my-script = "my_package:main"
my-script = "two_default_sources:main"
[tool.poetry.plugins."blogtool.parsers"]
......
[tool.poetry]
name = "my-package"
name = "two-default-sources-legacy"
version = "1.2.3"
description = "Some description."
authors = [
......@@ -48,7 +48,7 @@ pytest = "~3.4"
[tool.poetry.scripts]
my-script = "my_package:main"
my-script = "two_default_sources_legacy:main"
[tool.poetry.plugins."blogtool.parsers"]
......
......@@ -9,6 +9,7 @@ import pytest
from cleo.io.buffered_io import BufferedIO
from cleo.io.null_io import NullIO
from packaging.utils import canonicalize_name
from poetry.factory import Factory
from poetry.publishing.publisher import Publisher
......@@ -72,7 +73,8 @@ def test_publish_can_publish_to_given_repository(
("http://foo.bar",),
{"cert": True, "client_cert": None, "dry_run": False, "skip_existing": False},
] == uploader_upload.call_args
assert "Publishing my-package (1.2.3) to foo" in io.fetch_output()
project_name = canonicalize_name(fixture_name)
assert f"Publishing {project_name} (1.2.3) to foo" in io.fetch_output()
def test_publish_raises_error_for_undefined_repository(
......
......@@ -37,7 +37,7 @@ def test_create_poetry(fixture_dir: FixtureDirGetter) -> None:
package = poetry.package
assert package.name == "my-package"
assert package.name == "sample-project"
assert package.version.text == "1.2.3"
assert package.description == "Some description."
assert package.authors == ["Sébastien Eustace <sebastien@eustace.io>"]
......@@ -418,6 +418,7 @@ 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
"""
assert str(e.value) == expected
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment