Skip to content

Commit

Permalink
Fail with comprehensible error message if path dependencies do not ex…
Browse files Browse the repository at this point in the history
…ist (#6844)

Co-authored-by: Randy Döring <[email protected]>
  • Loading branch information
adriangb and radoering authored Feb 1, 2023
1 parent 0b1d869 commit 651d82d
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from poetry.core.packages.directory_dependency import DirectoryDependency
from poetry.core.packages.file_dependency import FileDependency
from poetry.core.packages.package import Package
from poetry.core.packages.path_dependency import PathDependency
from poetry.core.packages.url_dependency import URLDependency
from poetry.core.packages.vcs_dependency import VCSDependency
from poetry.core.version.markers import BaseMarker
Expand Down Expand Up @@ -390,6 +391,7 @@ def get_package_from_vcs(
)

def _search_for_file(self, dependency: FileDependency) -> Package:
dependency.validate(raise_error=True)
package = self.get_package_from_file(dependency.full_path)

self.validate_package_for_dependency(dependency=dependency, package=package)
Expand Down Expand Up @@ -420,6 +422,7 @@ def get_package_from_file(cls, file_path: Path) -> Package:
return package

def _search_for_directory(self, dependency: DirectoryDependency) -> Package:
dependency.validate(raise_error=True)
package = self.get_package_from_directory(dependency.full_path)

self.validate_package_for_dependency(dependency=dependency, package=package)
Expand Down Expand Up @@ -652,6 +655,11 @@ def complete_package(
if locked is not None and locked.package.is_same_package_as(dep):
continue
self.search_for_direct_origin_dependency(dep)
else:
for dep in _dependencies:
if dep.is_file() or dep.is_directory():
dep = cast("PathDependency", dep)
dep.validate(raise_error=True)

dependencies = self._get_dependencies_with_overrides(
_dependencies, dependency_package
Expand Down
38 changes: 38 additions & 0 deletions tests/console/commands/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from poetry.poetry import Poetry
from tests.types import CommandTesterFactory
from tests.types import FixtureDirGetter
from tests.types import ProjectFactory


Expand Down Expand Up @@ -69,6 +70,22 @@ def tester(
return command_tester_factory("install")


def _project_factory(
fixture_name: str,
project_factory: ProjectFactory,
fixture_dir: FixtureDirGetter,
) -> Poetry:
source = fixture_dir(fixture_name)
pyproject_content = (source / "pyproject.toml").read_text(encoding="utf-8")
poetry_lock_content = (source / "poetry.lock").read_text(encoding="utf-8")
return project_factory(
name="foobar",
pyproject_content=pyproject_content,
poetry_lock_content=poetry_lock_content,
source=source,
)


@pytest.mark.parametrize(
("options", "groups"),
[
Expand Down Expand Up @@ -291,3 +308,24 @@ def test_install_logs_output_decorated(tester: CommandTester, mocker: MockerFixt
)
assert tester.status_code == 0
assert tester.io.fetch_output() == expected


@pytest.mark.parametrize("options", ["", "--without dev"])
@pytest.mark.parametrize(
"project", ["missing_directory_dependency", "missing_file_dependency"]
)
def test_install_path_dependency_does_not_exist(
command_tester_factory: CommandTesterFactory,
project_factory: ProjectFactory,
fixture_dir: FixtureDirGetter,
project: str,
options: str,
):
poetry = _project_factory(project, project_factory, fixture_dir)
poetry.locker.locked(True)
tester = command_tester_factory("install", poetry=poetry)
if options:
tester.execute(options)
else:
with pytest.raises(ValueError, match="does not exist"):
tester.execute(options)
57 changes: 57 additions & 0 deletions tests/console/commands/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,63 @@ def test_lock_no_update_path_dependencies(
assert {p.name for p in packages} == {"quix", "sampleproject"}


@pytest.mark.parametrize("update", [True, False])
@pytest.mark.parametrize(
"project", ["missing_directory_dependency", "missing_file_dependency"]
)
def test_lock_path_dependency_does_not_exist(
command_tester_factory: CommandTesterFactory,
project_factory: ProjectFactory,
fixture_dir: FixtureDirGetter,
project: str,
update: bool,
):
poetry = _project_factory(project, project_factory, fixture_dir)
locker = Locker(
lock=poetry.pyproject.file.path.parent / "poetry.lock",
local_config=poetry.locker._local_config,
)
poetry.set_locker(locker)
options = "" if update else "--no-update"

tester = command_tester_factory("lock", poetry=poetry)
if update or "directory" in project:
# directory dependencies are always updated
with pytest.raises(ValueError, match="does not exist"):
tester.execute(options)
else:
tester.execute(options)


@pytest.mark.parametrize("update", [True, False])
@pytest.mark.parametrize(
"project", ["deleted_directory_dependency", "deleted_file_dependency"]
)
def test_lock_path_dependency_deleted_from_pyproject(
command_tester_factory: CommandTesterFactory,
project_factory: ProjectFactory,
fixture_dir: FixtureDirGetter,
project: str,
update: bool,
):
poetry = _project_factory(project, project_factory, fixture_dir)
locker = Locker(
lock=poetry.pyproject.file.path.parent / "poetry.lock",
local_config=poetry.locker._local_config,
)
poetry.set_locker(locker)

tester = command_tester_factory("lock", poetry=poetry)
if update:
tester.execute("")
else:
tester.execute("--no-update")

packages = locker.locked_repository().packages

assert {p.name for p in packages} == set()


@pytest.mark.parametrize("is_no_update", [False, True])
def test_lock_with_incompatible_lockfile(
command_tester_factory: CommandTesterFactory,
Expand Down
31 changes: 31 additions & 0 deletions tests/console/commands/test_show.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from poetry.core.packages.dependency_group import DependencyGroup

from poetry.factory import Factory
from poetry.utils._compat import tomllib
from tests.helpers import MOCK_DEFAULT_GIT_REVISION
from tests.helpers import get_package

Expand Down Expand Up @@ -2140,3 +2141,33 @@ def test_url_dependency_is_not_outdated_by_repository_package(
# version in the repository.
tester.execute("--outdated")
assert tester.io.fetch_output() == ""


@pytest.mark.parametrize(
("project_directory", "required_fixtures"),
[
(
"deleted_directory_dependency",
[],
),
],
)
def test_show_outdated_missing_directory_dependency(
tester: CommandTester,
poetry: Poetry,
installed: Repository,
repo: TestRepository,
):
with (poetry.pyproject.file.path.parent / "poetry.lock").open(mode="rb") as f:
data = tomllib.load(f)
poetry.locker.mock_lock_data(data)

poetry.package.add_dependency(
Factory.create_dependency(
"missing",
{"path": data["package"][0]["source"]["url"]},
)
)

with pytest.raises(ValueError, match="does not exist"):
tester.execute("")
20 changes: 20 additions & 0 deletions tests/fixtures/deleted_directory_dependency/poetry.lock

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

10 changes: 10 additions & 0 deletions tests/fixtures/deleted_directory_dependency/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[tool.poetry]
name = "project-with-missing-directory-dependency"
version = "1.2.3"
description = "This is a description"
authors = ["Your Name <[email protected]>"]
license = "MIT"
packages = []

[tool.poetry.dependencies]
python = "*"
20 changes: 20 additions & 0 deletions tests/fixtures/deleted_file_dependency/poetry.lock

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

10 changes: 10 additions & 0 deletions tests/fixtures/deleted_file_dependency/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[tool.poetry]
name = "project-with-missing-directory-dependency"
version = "1.2.3"
description = "This is a description"
authors = ["Your Name <[email protected]>"]
license = "MIT"
packages = []

[tool.poetry.dependencies]
python = "*"
20 changes: 20 additions & 0 deletions tests/fixtures/missing_directory_dependency/poetry.lock

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

13 changes: 13 additions & 0 deletions tests/fixtures/missing_directory_dependency/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[tool.poetry]
name = "project-with-missing-directory-dependency"
version = "1.2.3"
description = "This is a description"
authors = ["Your Name <[email protected]>"]
license = "MIT"
packages = []

[tool.poetry.dependencies]
python = "*"

[tool.poetry.dev-dependencies]
missing = { path = "./missing" }
20 changes: 20 additions & 0 deletions tests/fixtures/missing_file_dependency/poetry.lock

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

13 changes: 13 additions & 0 deletions tests/fixtures/missing_file_dependency/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[tool.poetry]
name = "project-with-missing-directory-dependency"
version = "1.2.3"
description = "This is a description"
authors = ["Your Name <[email protected]>"]
license = "MIT"
packages = []

[tool.poetry.dependencies]
python = "*"

[tool.poetry.dev-dependencies]
missing = { file = "missing-0.1.0-py2.py3-none-any.whl" }

0 comments on commit 651d82d

Please sign in to comment.