|
14 | 14 | import logging |
15 | 15 | import os |
16 | 16 | import re |
17 | | -from collections.abc import Collection |
| 17 | +from collections.abc import Collection, Mapping |
18 | 18 | from dataclasses import dataclass |
19 | 19 |
|
| 20 | +from pip._vendor.packaging import pylock |
20 | 21 | from pip._vendor.packaging.markers import Marker |
21 | 22 | from pip._vendor.packaging.requirements import InvalidRequirement, Requirement |
| 23 | +from pip._vendor.packaging.utils import parse_sdist_filename, parse_wheel_filename |
22 | 24 |
|
23 | 25 | from pip._internal.exceptions import InstallationError |
| 26 | +from pip._internal.models.format_control import FormatControl |
24 | 27 | from pip._internal.models.index import PyPI, TestPyPI |
25 | 28 | from pip._internal.models.link import Link |
26 | 29 | from pip._internal.models.wheel import Wheel |
|
29 | 32 | from pip._internal.utils.filetypes import is_archive_file |
30 | 33 | from pip._internal.utils.misc import is_installable_dir |
31 | 34 | from pip._internal.utils.packaging import get_requirement |
| 35 | +from pip._internal.utils.pylock import ( |
| 36 | + package_archive_requirement_url, |
| 37 | + package_directory_requirement_url, |
| 38 | + package_sdist_requirement_url, |
| 39 | + package_vcs_requirement_url, |
| 40 | + package_wheel_requirement_url, |
| 41 | +) |
32 | 42 | from pip._internal.utils.urls import path_to_url |
33 | 43 | from pip._internal.vcs import is_url, vcs |
34 | 44 |
|
@@ -568,3 +578,83 @@ def install_req_extend_extras( |
568 | 578 | else None |
569 | 579 | ) |
570 | 580 | return result |
| 581 | + |
| 582 | + |
| 583 | +def _pylock_hashes_to_hash_options(hashes: Mapping[str, str]) -> dict[str, list[str]]: |
| 584 | + return {k: [v] for k, v in hashes.items()} |
| 585 | + |
| 586 | + |
| 587 | +def install_req_from_pylock_package( |
| 588 | + package: pylock.Package, |
| 589 | + package_dist: ( |
| 590 | + pylock.PackageVcs |
| 591 | + | pylock.PackageArchive |
| 592 | + | pylock.PackageDirectory |
| 593 | + | pylock.PackageSdist |
| 594 | + | pylock.PackageWheel |
| 595 | + ), |
| 596 | + pylock_path_or_url: str, |
| 597 | + format_control: FormatControl, |
| 598 | +) -> InstallRequirement: |
| 599 | + pass |
| 600 | + # TODO: user_supplied |
| 601 | + # TODO: validate file size |
| 602 | + if isinstance(package_dist, pylock.PackageVcs): |
| 603 | + return InstallRequirement( |
| 604 | + req=Requirement( |
| 605 | + f"{package.name} @ " |
| 606 | + f"{package_vcs_requirement_url(pylock_path_or_url, package_dist)}" |
| 607 | + ), |
| 608 | + comes_from=pylock_path_or_url, |
| 609 | + ) |
| 610 | + elif isinstance(package_dist, pylock.PackageArchive): |
| 611 | + return InstallRequirement( |
| 612 | + req=Requirement( |
| 613 | + f"{package.name} @ " |
| 614 | + f"{package_archive_requirement_url(pylock_path_or_url, package_dist)}" |
| 615 | + ), |
| 616 | + comes_from=pylock_path_or_url, |
| 617 | + hash_options=_pylock_hashes_to_hash_options(package_dist.hashes), |
| 618 | + ) |
| 619 | + elif isinstance(package_dist, pylock.PackageDirectory): |
| 620 | + if package_dist.editable: |
| 621 | + return install_req_from_editable( |
| 622 | + package_directory_requirement_url(pylock_path_or_url, package_dist), |
| 623 | + comes_from=pylock_path_or_url, |
| 624 | + ) |
| 625 | + else: |
| 626 | + return install_req_from_line( |
| 627 | + package_directory_requirement_url(pylock_path_or_url, package_dist), |
| 628 | + comes_from=pylock_path_or_url, |
| 629 | + ) |
| 630 | + else: |
| 631 | + # wheel or sdist |
| 632 | + allow_binary = "binary" in format_control.get_allowed_formats(package.name) |
| 633 | + if isinstance(package_dist, pylock.PackageWheel) and not allow_binary: |
| 634 | + if not package.sdist: |
| 635 | + raise InstallationError( |
| 636 | + f"binaries are not permitted for package {package.name!r} and " |
| 637 | + f"there is no source distribution for it in {pylock_path_or_url!r}" |
| 638 | + ) |
| 639 | + package_dist = package.sdist |
| 640 | + version = package.version |
| 641 | + if isinstance(package_dist, pylock.PackageWheel): |
| 642 | + if not version: |
| 643 | + _, version, _, _ = parse_wheel_filename(package_dist.filename) |
| 644 | + requirement_url = package_wheel_requirement_url( |
| 645 | + pylock_path_or_url, package_dist |
| 646 | + ) |
| 647 | + elif isinstance(package_dist, pylock.PackageSdist): |
| 648 | + if not version: |
| 649 | + _, version = parse_sdist_filename(package_dist.filename) |
| 650 | + requirement_url = package_sdist_requirement_url( |
| 651 | + pylock_path_or_url, package_dist |
| 652 | + ) |
| 653 | + ireq = InstallRequirement( |
| 654 | + req=Requirement(f"{package.name}=={version}"), |
| 655 | + comes_from=pylock_path_or_url, |
| 656 | + link=Link(requirement_url), |
| 657 | + hash_options=_pylock_hashes_to_hash_options(package_dist.hashes), |
| 658 | + ) |
| 659 | + ireq.original_link = None # not a direct URL |
| 660 | + return ireq |
0 commit comments