Skip to content

Commit

Permalink
locker/installer: drop support for reading very old lock files (prior…
Browse files Browse the repository at this point in the history
… lock file version 1.0 and Poetry 1.1) (python-poetry#9345)
  • Loading branch information
radoering committed May 12, 2024
1 parent 735225a commit 298443b
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 247 deletions.
35 changes: 0 additions & 35 deletions src/poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from poetry.repositories import RepositoryPool
from poetry.repositories.installed_repository import InstalledRepository
from poetry.repositories.lockfile_repository import LockfileRepository
from poetry.utils.extras import get_extra_package_names


if TYPE_CHECKING:
Expand Down Expand Up @@ -301,11 +300,6 @@ def _do_install(self) -> int:
extras=set(self._extras),
)

# We need to filter operations so that packages
# not compatible with the current system,
# or optional and not requested, are dropped
self._filter_operations(ops, lockfile_repo)

# Validate the dependencies
for op in ops:
dep = op.package.to_dependency()
Expand Down Expand Up @@ -344,34 +338,5 @@ def _populate_lockfile_repo(
if not repo.has_package(package):
repo.add_package(package)

def _filter_operations(self, ops: Iterable[Operation], repo: Repository) -> None:
extra_packages = self._get_extra_packages(repo)
for op in ops:
package = op.target_package if isinstance(op, Update) else op.package

if op.job_type == "uninstall":
continue

if not self._env.is_valid_for_marker(package.marker):
op.skip("Not needed for the current environment")
continue

# If a package is optional and not requested
# in any extra we skip it
if package.optional and package.name not in extra_packages:
op.skip("Not required")

def _get_extra_packages(self, repo: Repository) -> set[NormalizedName]:
"""
Returns all package names required by extras.
Maybe we just let the solver handle it?
"""
return get_extra_package_names(
repo.packages,
{k: [d.name for d in v] for k, v in self._package.extras.items()},
self._extras,
)

def _get_installed(self) -> InstalledRepository:
return InstalledRepository.load(self._env)
24 changes: 6 additions & 18 deletions src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from poetry.core.constraints.version import parse_constraint
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
from poetry.core.version.markers import parse_marker
from poetry.core.version.requirements import InvalidRequirement
from tomlkit import array
from tomlkit import comment
Expand Down Expand Up @@ -205,22 +204,6 @@ def locked_repository(self) -> LockfileRepository:

package.extras = package_extras

if "marker" in info:
package.marker = parse_marker(info["marker"])
else:
# Compatibility for old locks
if "requirements" in info:
dep = Dependency("foo", "0.0.0")
for name, value in info["requirements"].items():
if name == "python":
dep.python_versions = value
elif name == "platform":
dep.platform = value

split_dep = dep.to_pep_508(False).split(";")
if len(split_dep) > 1:
package.marker = parse_marker(split_dep[1].strip())

for dep_name, constraint in info.get("dependencies", {}).items():
root_dir = self.lock.parent
if package.source_type == "directory":
Expand Down Expand Up @@ -348,7 +331,12 @@ def _get_lock_data(self) -> dict[str, Any]:
)

metadata = lock_data["metadata"]
lock_version = Version.parse(metadata.get("lock-version", "1.0"))
if "lock-version" not in metadata:
raise RuntimeError(
"The lock file is not compatible with the current version of Poetry.\n"
"Regenerate the lock file with the `poetry lock` command."
)
lock_version = Version.parse(metadata["lock-version"])
current_version = Version.parse(self._VERSION)
accepted_versions = parse_constraint(self._READ_VERSION_RANGE)
lock_version_allowed = accepted_versions.allows(lock_version)
Expand Down
13 changes: 8 additions & 5 deletions src/poetry/puzzle/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ def calculate_operations(
uninstalls: set[NormalizedName] = set()
for result_package, priority in self._result_packages:
installed = False
is_unsolicited_extra = extras is not None and (
result_package.optional and result_package.name not in extra_packages
)

for installed_package in self._installed_packages:
if result_package.name == installed_package.name:
installed = True

# Extras that were not requested are always uninstalled.
if extras is not None and (
result_package.optional
and result_package.name not in extra_packages
):
if is_unsolicited_extra:
uninstalls.add(installed_package.name)
operations.append(Uninstall(installed_package))

Expand Down Expand Up @@ -100,7 +100,10 @@ def calculate_operations(
installed
or (skip_directory and result_package.source_type == "directory")
):
operations.append(Install(result_package, priority=priority))
op = Install(result_package, priority=priority)
if is_unsolicited_extra:
op.skip("Not required")
operations.append(op)

if with_uninstalls:
for current_package in self._current_packages:
Expand Down
5 changes: 2 additions & 3 deletions tests/console/commands/self/test_remove_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ def install_plugin(installed: Repository) -> None:
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
"files": [],
},
],
"metadata": {
"lock-version": "2.0",
"python-versions": "^3.6",
"platform": "*",
"content-hash": "123456789",
"files": {"poetry-plugin": []},
},
}
system_pyproject_file.parent.joinpath("poetry.lock").write_text(
Expand Down
112 changes: 0 additions & 112 deletions tests/installation/fixtures/old-lock.test

This file was deleted.

74 changes: 0 additions & 74 deletions tests/installation/test_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2234,80 +2234,6 @@ def test_installer_uses_prereleases_if_they_are_compatible(
assert installer.executor.installations_count == 2


def test_installer_can_handle_old_lock_files(
locker: Locker,
package: ProjectPackage,
repo: Repository,
installed: CustomInstalledRepository,
config: Config,
pypi_repository: PyPiRepository,
) -> None:
pool = RepositoryPool()
pool.add_repository(pypi_repository)

package.add_dependency(Factory.create_dependency("pytest", "^3.5", groups=["dev"]))

locker.locked()
locker.mock_lock_data(fixture("old-lock"))

installer = Installer(
NullIO(),
MockEnv(),
package,
locker,
pool,
config,
installed=installed,
executor=Executor(MockEnv(), pool, config, NullIO()),
)
result = installer.run()
assert result == 0

assert installer.executor.installations_count == 6

installer = Installer(
NullIO(),
MockEnv(version_info=(2, 7, 18)),
package,
locker,
pool,
config,
installed=installed,
executor=Executor(
MockEnv(version_info=(2, 7, 18)),
pool,
config,
NullIO(),
),
)
result = installer.run()
assert result == 0

# funcsigs will be added
assert installer.executor.installations_count == 7

installer = Installer(
NullIO(),
MockEnv(version_info=(2, 7, 18), platform="win32"),
package,
locker,
pool,
config,
installed=installed,
executor=Executor(
MockEnv(version_info=(2, 7, 18), platform="win32"),
pool,
config,
NullIO(),
),
)
result = installer.run()
assert result == 0

# colorama will be added
assert installer.executor.installations_count == 8


def test_installer_does_not_write_lock_file_when_installation_fails(
installer: Installer,
locker: Locker,
Expand Down
18 changes: 18 additions & 0 deletions tests/packages/test_locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,24 @@ def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed(
_ = locker.lock_data


def test_locker_should_raise_an_error_if_no_lock_version(
locker: Locker, caplog: LogCaptureFixture
) -> None:
"""Lock file prior Poetry 1.1 have no lock file version."""
content = """\
[metadata]
python-versions = "~2.7 || ^3.4"
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
"""
caplog.set_level(logging.WARNING, logger="poetry.packages.locker")

with open(locker.lock, "w", encoding="utf-8") as f:
f.write(content)

with pytest.raises(RuntimeError, match="^The lock file is not compatible"):
_ = locker.lock_data


def test_root_extras_dependencies_are_ordered(
locker: Locker, root: ProjectPackage, fixture_base: Path
) -> None:
Expand Down

0 comments on commit 298443b

Please sign in to comment.