pip 25.2__py3-none-any.whl → 25.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pip/__init__.py +1 -1
- pip/_internal/__init__.py +0 -0
- pip/_internal/build_env.py +71 -3
- pip/_internal/cache.py +1 -1
- pip/_internal/cli/cmdoptions.py +43 -71
- pip/_internal/cli/parser.py +3 -3
- pip/_internal/cli/req_command.py +46 -26
- pip/_internal/commands/download.py +4 -7
- pip/_internal/commands/install.py +19 -14
- pip/_internal/commands/lock.py +3 -6
- pip/_internal/commands/wheel.py +5 -10
- pip/_internal/configuration.py +1 -2
- pip/_internal/distributions/sdist.py +13 -14
- pip/_internal/exceptions.py +20 -3
- pip/_internal/index/package_finder.py +3 -3
- pip/_internal/metadata/__init__.py +7 -2
- pip/_internal/metadata/importlib/_dists.py +8 -2
- pip/_internal/models/link.py +1 -1
- pip/_internal/models/wheel.py +5 -66
- pip/_internal/network/cache.py +6 -11
- pip/_internal/network/lazy_wheel.py +5 -3
- pip/_internal/operations/build/wheel.py +4 -4
- pip/_internal/operations/build/wheel_editable.py +4 -4
- pip/_internal/operations/prepare.py +7 -1
- pip/_internal/pyproject.py +2 -61
- pip/_internal/req/__init__.py +1 -3
- pip/_internal/req/constructors.py +42 -38
- pip/_internal/req/req_file.py +0 -1
- pip/_internal/req/req_install.py +32 -141
- pip/_internal/resolution/resolvelib/candidates.py +20 -11
- pip/_internal/resolution/resolvelib/factory.py +31 -0
- pip/_internal/resolution/resolvelib/provider.py +9 -0
- pip/_internal/resolution/resolvelib/reporter.py +21 -8
- pip/_internal/resolution/resolvelib/resolver.py +2 -6
- pip/_internal/self_outdated_check.py +11 -3
- pip/_internal/utils/filesystem.py +12 -0
- pip/_internal/utils/unpacking.py +25 -0
- pip/_internal/wheel_builder.py +23 -96
- pip/_vendor/README.rst +180 -0
- pip/_vendor/cachecontrol/LICENSE.txt +13 -0
- pip/_vendor/certifi/LICENSE +20 -0
- pip/_vendor/certifi/__init__.py +1 -1
- pip/_vendor/certifi/cacert.pem +62 -40
- pip/_vendor/dependency_groups/LICENSE.txt +9 -0
- pip/_vendor/distlib/LICENSE.txt +284 -0
- pip/_vendor/distro/LICENSE +202 -0
- pip/_vendor/idna/LICENSE.md +31 -0
- pip/_vendor/msgpack/COPYING +14 -0
- pip/_vendor/msgpack/__init__.py +2 -2
- pip/_vendor/packaging/LICENSE +3 -0
- pip/_vendor/packaging/LICENSE.APACHE +177 -0
- pip/_vendor/packaging/LICENSE.BSD +23 -0
- pip/_vendor/pkg_resources/LICENSE +17 -0
- pip/_vendor/platformdirs/LICENSE +21 -0
- pip/_vendor/platformdirs/api.py +1 -1
- pip/_vendor/platformdirs/macos.py +10 -8
- pip/_vendor/platformdirs/version.py +16 -3
- pip/_vendor/pygments/LICENSE +25 -0
- pip/_vendor/pyproject_hooks/LICENSE +21 -0
- pip/_vendor/requests/LICENSE +175 -0
- pip/_vendor/requests/__version__.py +2 -2
- pip/_vendor/requests/adapters.py +17 -40
- pip/_vendor/requests/sessions.py +1 -1
- pip/_vendor/resolvelib/LICENSE +13 -0
- pip/_vendor/resolvelib/__init__.py +1 -1
- pip/_vendor/resolvelib/resolvers/abstract.py +3 -3
- pip/_vendor/resolvelib/resolvers/resolution.py +5 -0
- pip/_vendor/rich/LICENSE +19 -0
- pip/_vendor/rich/style.py +7 -11
- pip/_vendor/tomli/LICENSE +21 -0
- pip/_vendor/tomli/__init__.py +1 -1
- pip/_vendor/tomli/_parser.py +28 -21
- pip/_vendor/tomli/_re.py +8 -5
- pip/_vendor/tomli_w/LICENSE +21 -0
- pip/_vendor/truststore/LICENSE +21 -0
- pip/_vendor/truststore/__init__.py +1 -1
- pip/_vendor/truststore/_api.py +14 -6
- pip/_vendor/truststore/_openssl.py +3 -1
- pip/_vendor/urllib3/LICENSE.txt +21 -0
- pip/_vendor/vendor.txt +8 -8
- {pip-25.2.dist-info → pip-25.3.dist-info}/METADATA +9 -10
- {pip-25.2.dist-info → pip-25.3.dist-info}/RECORD +106 -90
- {pip-25.2.dist-info → pip-25.3.dist-info}/WHEEL +1 -2
- pip-25.3.dist-info/entry_points.txt +4 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/AUTHORS.txt +9 -0
- pip/_internal/operations/build/metadata_legacy.py +0 -73
- pip/_internal/operations/build/wheel_legacy.py +0 -119
- pip/_internal/operations/install/editable_legacy.py +0 -48
- pip/_internal/utils/setuptools_build.py +0 -149
- pip-25.2.dist-info/entry_points.txt +0 -3
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE-HEADER +0 -3
- pip-25.2.dist-info/top_level.txt +0 -1
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/LICENSE.txt +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/certifi/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/distlib/LICENSE.txt +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/distro/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/idna/LICENSE.md +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/msgpack/COPYING +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/packaging/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/packaging/LICENSE.BSD +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/pkg_resources/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/platformdirs/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/pygments/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/requests/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/resolvelib/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/rich/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/tomli/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/tomli_w/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/truststore/LICENSE +0 -0
- {pip-25.2.dist-info → pip-25.3.dist-info}/licenses/src/pip/_vendor/urllib3/LICENSE.txt +0 -0
pip/_internal/commands/lock.py
CHANGED
|
@@ -11,9 +11,6 @@ from pip._internal.cli.req_command import (
|
|
|
11
11
|
from pip._internal.cli.status_codes import SUCCESS
|
|
12
12
|
from pip._internal.models.pylock import Pylock, is_valid_pylock_file_name
|
|
13
13
|
from pip._internal.operations.build.build_tracker import get_build_tracker
|
|
14
|
-
from pip._internal.req.req_install import (
|
|
15
|
-
check_legacy_setup_py_options,
|
|
16
|
-
)
|
|
17
14
|
from pip._internal.utils.logging import getLogger
|
|
18
15
|
from pip._internal.utils.misc import (
|
|
19
16
|
get_pip_version,
|
|
@@ -59,6 +56,7 @@ class LockCommand(RequirementCommand):
|
|
|
59
56
|
)
|
|
60
57
|
self.cmd_opts.add_option(cmdoptions.requirements())
|
|
61
58
|
self.cmd_opts.add_option(cmdoptions.constraints())
|
|
59
|
+
self.cmd_opts.add_option(cmdoptions.build_constraints())
|
|
62
60
|
self.cmd_opts.add_option(cmdoptions.no_deps())
|
|
63
61
|
self.cmd_opts.add_option(cmdoptions.pre())
|
|
64
62
|
|
|
@@ -69,7 +67,6 @@ class LockCommand(RequirementCommand):
|
|
|
69
67
|
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
|
70
68
|
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
|
71
69
|
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
|
72
|
-
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
|
73
70
|
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
|
74
71
|
|
|
75
72
|
self.cmd_opts.add_option(cmdoptions.config_settings())
|
|
@@ -98,6 +95,8 @@ class LockCommand(RequirementCommand):
|
|
|
98
95
|
"without prior warning."
|
|
99
96
|
)
|
|
100
97
|
|
|
98
|
+
cmdoptions.check_build_constraints(options)
|
|
99
|
+
|
|
101
100
|
session = self.get_default_session(options)
|
|
102
101
|
|
|
103
102
|
finder = self._build_package_finder(
|
|
@@ -114,7 +113,6 @@ class LockCommand(RequirementCommand):
|
|
|
114
113
|
)
|
|
115
114
|
|
|
116
115
|
reqs = self.get_requirements(args, options, finder, session)
|
|
117
|
-
check_legacy_setup_py_options(options, reqs)
|
|
118
116
|
|
|
119
117
|
wheel_cache = WheelCache(options.cache_dir)
|
|
120
118
|
|
|
@@ -142,7 +140,6 @@ class LockCommand(RequirementCommand):
|
|
|
142
140
|
ignore_installed=True,
|
|
143
141
|
ignore_requires_python=options.ignore_requires_python,
|
|
144
142
|
upgrade_strategy="to-satisfy-only",
|
|
145
|
-
use_pep517=options.use_pep517,
|
|
146
143
|
)
|
|
147
144
|
|
|
148
145
|
self.trace_basic_info(finder)
|
pip/_internal/commands/wheel.py
CHANGED
|
@@ -11,7 +11,6 @@ from pip._internal.exceptions import CommandError
|
|
|
11
11
|
from pip._internal.operations.build.build_tracker import get_build_tracker
|
|
12
12
|
from pip._internal.req.req_install import (
|
|
13
13
|
InstallRequirement,
|
|
14
|
-
check_legacy_setup_py_options,
|
|
15
14
|
)
|
|
16
15
|
from pip._internal.utils.misc import ensure_dir, normalize_path
|
|
17
16
|
from pip._internal.utils.temp_dir import TempDirectory
|
|
@@ -57,9 +56,9 @@ class WheelCommand(RequirementCommand):
|
|
|
57
56
|
self.cmd_opts.add_option(cmdoptions.prefer_binary())
|
|
58
57
|
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
|
59
58
|
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
|
60
|
-
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
|
61
59
|
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
|
62
60
|
self.cmd_opts.add_option(cmdoptions.constraints())
|
|
61
|
+
self.cmd_opts.add_option(cmdoptions.build_constraints())
|
|
63
62
|
self.cmd_opts.add_option(cmdoptions.editable())
|
|
64
63
|
self.cmd_opts.add_option(cmdoptions.requirements())
|
|
65
64
|
self.cmd_opts.add_option(cmdoptions.src())
|
|
@@ -76,8 +75,6 @@ class WheelCommand(RequirementCommand):
|
|
|
76
75
|
)
|
|
77
76
|
|
|
78
77
|
self.cmd_opts.add_option(cmdoptions.config_settings())
|
|
79
|
-
self.cmd_opts.add_option(cmdoptions.build_options())
|
|
80
|
-
self.cmd_opts.add_option(cmdoptions.global_options())
|
|
81
78
|
|
|
82
79
|
self.cmd_opts.add_option(
|
|
83
80
|
"--pre",
|
|
@@ -101,6 +98,8 @@ class WheelCommand(RequirementCommand):
|
|
|
101
98
|
|
|
102
99
|
@with_cleanup
|
|
103
100
|
def run(self, options: Values, args: list[str]) -> int:
|
|
101
|
+
cmdoptions.check_build_constraints(options)
|
|
102
|
+
|
|
104
103
|
session = self.get_default_session(options)
|
|
105
104
|
|
|
106
105
|
finder = self._build_package_finder(options, session)
|
|
@@ -117,7 +116,6 @@ class WheelCommand(RequirementCommand):
|
|
|
117
116
|
)
|
|
118
117
|
|
|
119
118
|
reqs = self.get_requirements(args, options, finder, session)
|
|
120
|
-
check_legacy_setup_py_options(options, reqs)
|
|
121
119
|
|
|
122
120
|
wheel_cache = WheelCache(options.cache_dir)
|
|
123
121
|
|
|
@@ -138,13 +136,14 @@ class WheelCommand(RequirementCommand):
|
|
|
138
136
|
options=options,
|
|
139
137
|
wheel_cache=wheel_cache,
|
|
140
138
|
ignore_requires_python=options.ignore_requires_python,
|
|
141
|
-
use_pep517=options.use_pep517,
|
|
142
139
|
)
|
|
143
140
|
|
|
144
141
|
self.trace_basic_info(finder)
|
|
145
142
|
|
|
146
143
|
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
|
|
147
144
|
|
|
145
|
+
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
|
146
|
+
|
|
148
147
|
reqs_to_build: list[InstallRequirement] = []
|
|
149
148
|
for req in requirement_set.requirements.values():
|
|
150
149
|
if req.is_wheel:
|
|
@@ -152,15 +151,11 @@ class WheelCommand(RequirementCommand):
|
|
|
152
151
|
else:
|
|
153
152
|
reqs_to_build.append(req)
|
|
154
153
|
|
|
155
|
-
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
|
156
|
-
|
|
157
154
|
# build wheels
|
|
158
155
|
build_successes, build_failures = build(
|
|
159
156
|
reqs_to_build,
|
|
160
157
|
wheel_cache=wheel_cache,
|
|
161
158
|
verify=(not options.no_verify),
|
|
162
|
-
build_options=options.build_options or [],
|
|
163
|
-
global_options=options.global_options or [],
|
|
164
159
|
)
|
|
165
160
|
for req in build_successes:
|
|
166
161
|
assert req.link and req.link.is_wheel
|
pip/_internal/configuration.py
CHANGED
|
@@ -53,8 +53,7 @@ logger = getLogger(__name__)
|
|
|
53
53
|
def _normalize_name(name: str) -> str:
|
|
54
54
|
"""Make a name consistent regardless of source (environment or file)"""
|
|
55
55
|
name = name.lower().replace("_", "-")
|
|
56
|
-
|
|
57
|
-
name = name[2:] # only prefer long opts
|
|
56
|
+
name = name.removeprefix("--") # only prefer long opts
|
|
58
57
|
return name
|
|
59
58
|
|
|
60
59
|
|
|
@@ -20,7 +20,7 @@ class SourceDistribution(AbstractDistribution):
|
|
|
20
20
|
"""Represents a source distribution.
|
|
21
21
|
|
|
22
22
|
The preparation step for these needs metadata for the packages to be
|
|
23
|
-
generated
|
|
23
|
+
generated.
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
26
|
@property
|
|
@@ -38,28 +38,27 @@ class SourceDistribution(AbstractDistribution):
|
|
|
38
38
|
build_isolation: bool,
|
|
39
39
|
check_build_deps: bool,
|
|
40
40
|
) -> None:
|
|
41
|
-
# Load pyproject.toml
|
|
41
|
+
# Load pyproject.toml
|
|
42
42
|
self.req.load_pyproject_toml()
|
|
43
43
|
|
|
44
44
|
# Set up the build isolation, if this requirement should be isolated
|
|
45
|
-
|
|
46
|
-
if should_isolate:
|
|
45
|
+
if build_isolation:
|
|
47
46
|
# Setup an isolated environment and install the build backend static
|
|
48
47
|
# requirements in it.
|
|
49
48
|
self._prepare_build_backend(build_env_installer)
|
|
50
|
-
# Check that
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
|
|
55
|
-
# UNKNOWN.egg-info when running get_requires_for_build_wheel on a directory
|
|
56
|
-
# without setup.py nor setup.cfg.
|
|
57
|
-
self.req.isolated_editable_sanity_check()
|
|
49
|
+
# Check that the build backend supports PEP 660. This cannot be done
|
|
50
|
+
# earlier because we need to setup the build backend to verify it
|
|
51
|
+
# supports build_editable, nor can it be done later, because we want
|
|
52
|
+
# to avoid installing build requirements needlessly.
|
|
53
|
+
self.req.editable_sanity_check()
|
|
58
54
|
# Install the dynamic build requirements.
|
|
59
55
|
self._install_build_reqs(build_env_installer)
|
|
56
|
+
else:
|
|
57
|
+
# When not using build isolation, we still need to check that
|
|
58
|
+
# the build backend supports PEP 660.
|
|
59
|
+
self.req.editable_sanity_check()
|
|
60
60
|
# Check if the current environment provides build dependencies
|
|
61
|
-
|
|
62
|
-
if should_check_deps:
|
|
61
|
+
if check_build_deps:
|
|
63
62
|
pyproject_requires = self.req.pyproject_requires
|
|
64
63
|
assert pyproject_requires is not None
|
|
65
64
|
conflicting, missing = self.req.build_env.check_requirements(
|
pip/_internal/exceptions.py
CHANGED
|
@@ -190,6 +190,23 @@ class InstallationError(PipError):
|
|
|
190
190
|
"""General exception during installation"""
|
|
191
191
|
|
|
192
192
|
|
|
193
|
+
class FailedToPrepareCandidate(InstallationError):
|
|
194
|
+
"""Raised when we fail to prepare a candidate (i.e. fetch and generate metadata).
|
|
195
|
+
|
|
196
|
+
This is intentionally not a diagnostic error, since the output will be presented
|
|
197
|
+
above this error, when this occurs. This should instead present information to the
|
|
198
|
+
user.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
def __init__(
|
|
202
|
+
self, *, package_name: str, requirement_chain: str, failed_step: str
|
|
203
|
+
) -> None:
|
|
204
|
+
super().__init__(f"Failed to build '{package_name}' when {failed_step.lower()}")
|
|
205
|
+
self.package_name = package_name
|
|
206
|
+
self.requirement_chain = requirement_chain
|
|
207
|
+
self.failed_step = failed_step
|
|
208
|
+
|
|
209
|
+
|
|
193
210
|
class MissingPyProjectBuildRequires(DiagnosticPipError):
|
|
194
211
|
"""Raised when pyproject.toml has `build-system`, but no `build-system.requires`."""
|
|
195
212
|
|
|
@@ -384,7 +401,7 @@ class InstallationSubprocessError(DiagnosticPipError, InstallationError):
|
|
|
384
401
|
output_lines: list[str] | None,
|
|
385
402
|
) -> None:
|
|
386
403
|
if output_lines is None:
|
|
387
|
-
output_prompt = Text("
|
|
404
|
+
output_prompt = Text("No available output.")
|
|
388
405
|
else:
|
|
389
406
|
output_prompt = (
|
|
390
407
|
Text.from_markup(f"[red][{len(output_lines)} lines of output][/]\n")
|
|
@@ -412,7 +429,7 @@ class InstallationSubprocessError(DiagnosticPipError, InstallationError):
|
|
|
412
429
|
return f"{self.command_description} exited with {self.exit_code}"
|
|
413
430
|
|
|
414
431
|
|
|
415
|
-
class MetadataGenerationFailed(
|
|
432
|
+
class MetadataGenerationFailed(DiagnosticPipError, InstallationError):
|
|
416
433
|
reference = "metadata-generation-failed"
|
|
417
434
|
|
|
418
435
|
def __init__(
|
|
@@ -420,7 +437,7 @@ class MetadataGenerationFailed(InstallationSubprocessError, InstallationError):
|
|
|
420
437
|
*,
|
|
421
438
|
package_details: str,
|
|
422
439
|
) -> None:
|
|
423
|
-
super(
|
|
440
|
+
super().__init__(
|
|
424
441
|
message="Encountered error while generating package metadata.",
|
|
425
442
|
context=escape(package_details),
|
|
426
443
|
hint_stmt="See above for details.",
|
|
@@ -17,7 +17,7 @@ from typing import (
|
|
|
17
17
|
|
|
18
18
|
from pip._vendor.packaging import specifiers
|
|
19
19
|
from pip._vendor.packaging.tags import Tag
|
|
20
|
-
from pip._vendor.packaging.utils import canonicalize_name
|
|
20
|
+
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
|
|
21
21
|
from pip._vendor.packaging.version import InvalidVersion, _BaseVersion
|
|
22
22
|
from pip._vendor.packaging.version import parse as parse_version
|
|
23
23
|
|
|
@@ -127,7 +127,7 @@ class LinkEvaluator:
|
|
|
127
127
|
def __init__(
|
|
128
128
|
self,
|
|
129
129
|
project_name: str,
|
|
130
|
-
canonical_name:
|
|
130
|
+
canonical_name: NormalizedName,
|
|
131
131
|
formats: frozenset[str],
|
|
132
132
|
target_python: TargetPython,
|
|
133
133
|
allow_yanked: bool,
|
|
@@ -201,7 +201,7 @@ class LinkEvaluator:
|
|
|
201
201
|
LinkType.format_invalid,
|
|
202
202
|
"invalid wheel filename",
|
|
203
203
|
)
|
|
204
|
-
if
|
|
204
|
+
if wheel.name != self._canonical_name:
|
|
205
205
|
reason = f"wrong project name (not {self.project_name})"
|
|
206
206
|
return (LinkType.different_project, reason)
|
|
207
207
|
|
|
@@ -4,13 +4,16 @@ import contextlib
|
|
|
4
4
|
import functools
|
|
5
5
|
import os
|
|
6
6
|
import sys
|
|
7
|
-
from typing import Literal, Protocol, cast
|
|
7
|
+
from typing import TYPE_CHECKING, Literal, Protocol, cast
|
|
8
8
|
|
|
9
9
|
from pip._internal.utils.deprecation import deprecated
|
|
10
10
|
from pip._internal.utils.misc import strtobool
|
|
11
11
|
|
|
12
12
|
from .base import BaseDistribution, BaseEnvironment, FilesystemWheel, MemoryWheel, Wheel
|
|
13
13
|
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from pip._vendor.packaging.utils import NormalizedName
|
|
16
|
+
|
|
14
17
|
__all__ = [
|
|
15
18
|
"BaseDistribution",
|
|
16
19
|
"BaseEnvironment",
|
|
@@ -131,7 +134,9 @@ def get_directory_distribution(directory: str) -> BaseDistribution:
|
|
|
131
134
|
return select_backend().Distribution.from_directory(directory)
|
|
132
135
|
|
|
133
136
|
|
|
134
|
-
def get_wheel_distribution(
|
|
137
|
+
def get_wheel_distribution(
|
|
138
|
+
wheel: Wheel, canonical_name: NormalizedName
|
|
139
|
+
) -> BaseDistribution:
|
|
135
140
|
"""Get the representation of the specified wheel's distribution metadata.
|
|
136
141
|
|
|
137
142
|
This returns a Distribution instance from the chosen backend based on
|
|
@@ -28,6 +28,7 @@ from pip._internal.utils.temp_dir import TempDirectory
|
|
|
28
28
|
from pip._internal.utils.wheel import parse_wheel, read_wheel_metadata_file
|
|
29
29
|
|
|
30
30
|
from ._compat import (
|
|
31
|
+
BadMetadata,
|
|
31
32
|
BasePath,
|
|
32
33
|
get_dist_canonical_name,
|
|
33
34
|
parse_name_and_version_from_info_directory,
|
|
@@ -165,9 +166,14 @@ class Distribution(BaseDistribution):
|
|
|
165
166
|
|
|
166
167
|
@property
|
|
167
168
|
def version(self) -> Version:
|
|
168
|
-
|
|
169
|
+
try:
|
|
170
|
+
version = (
|
|
171
|
+
parse_name_and_version_from_info_directory(self._dist)[1]
|
|
172
|
+
or self._dist.version
|
|
173
|
+
)
|
|
169
174
|
return parse_version(version)
|
|
170
|
-
|
|
175
|
+
except TypeError:
|
|
176
|
+
raise BadMetadata(self._dist, reason="invalid metadata entry `version`")
|
|
171
177
|
|
|
172
178
|
@property
|
|
173
179
|
def raw_version(self) -> str:
|
pip/_internal/models/link.py
CHANGED
pip/_internal/models/wheel.py
CHANGED
|
@@ -4,91 +4,30 @@ name that have meaning.
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import re
|
|
8
7
|
from collections.abc import Iterable
|
|
9
8
|
|
|
10
9
|
from pip._vendor.packaging.tags import Tag
|
|
11
|
-
from pip._vendor.packaging.utils import BuildTag, parse_wheel_filename
|
|
12
10
|
from pip._vendor.packaging.utils import (
|
|
13
11
|
InvalidWheelFilename as _PackagingInvalidWheelFilename,
|
|
14
12
|
)
|
|
13
|
+
from pip._vendor.packaging.utils import parse_wheel_filename
|
|
15
14
|
|
|
16
15
|
from pip._internal.exceptions import InvalidWheelFilename
|
|
17
|
-
from pip._internal.utils.deprecation import deprecated
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
class Wheel:
|
|
21
19
|
"""A wheel file"""
|
|
22
20
|
|
|
23
|
-
legacy_wheel_file_re = re.compile(
|
|
24
|
-
r"""^(?P<namever>(?P<name>[^\s-]+?)-(?P<ver>[^\s-]*?))
|
|
25
|
-
((-(?P<build>\d[^-]*?))?-(?P<pyver>[^\s-]+?)-(?P<abi>[^\s-]+?)-(?P<plat>[^\s-]+?)
|
|
26
|
-
\.whl|\.dist-info)$""",
|
|
27
|
-
re.VERBOSE,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
21
|
def __init__(self, filename: str) -> None:
|
|
31
22
|
self.filename = filename
|
|
32
23
|
|
|
33
|
-
# To make mypy happy specify type hints that can come from either
|
|
34
|
-
# parse_wheel_filename or the legacy_wheel_file_re match.
|
|
35
|
-
self.name: str
|
|
36
|
-
self._build_tag: BuildTag | None = None
|
|
37
|
-
|
|
38
24
|
try:
|
|
39
25
|
wheel_info = parse_wheel_filename(filename)
|
|
40
|
-
self.name, _version, self._build_tag, self.file_tags = wheel_info
|
|
41
|
-
self.version = str(_version)
|
|
42
26
|
except _PackagingInvalidWheelFilename as e:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
deprecated(
|
|
49
|
-
reason=(
|
|
50
|
-
f"Wheel filename {filename!r} is not correctly normalised. "
|
|
51
|
-
"Future versions of pip will raise the following error:\n"
|
|
52
|
-
f"{e.args[0]}\n\n"
|
|
53
|
-
),
|
|
54
|
-
replacement=(
|
|
55
|
-
"to rename the wheel to use a correctly normalised "
|
|
56
|
-
"name (this may require updating the version in "
|
|
57
|
-
"the project metadata)"
|
|
58
|
-
),
|
|
59
|
-
gone_in="25.3",
|
|
60
|
-
issue=12938,
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
self.name = legacy_wheel_info.group("name").replace("_", "-")
|
|
64
|
-
self.version = legacy_wheel_info.group("ver").replace("_", "-")
|
|
65
|
-
|
|
66
|
-
# Generate the file tags from the legacy wheel filename
|
|
67
|
-
pyversions = legacy_wheel_info.group("pyver").split(".")
|
|
68
|
-
abis = legacy_wheel_info.group("abi").split(".")
|
|
69
|
-
plats = legacy_wheel_info.group("plat").split(".")
|
|
70
|
-
self.file_tags = frozenset(
|
|
71
|
-
Tag(interpreter=py, abi=abi, platform=plat)
|
|
72
|
-
for py in pyversions
|
|
73
|
-
for abi in abis
|
|
74
|
-
for plat in plats
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
@property
|
|
78
|
-
def build_tag(self) -> BuildTag:
|
|
79
|
-
if self._build_tag is not None:
|
|
80
|
-
return self._build_tag
|
|
81
|
-
|
|
82
|
-
# Parse the build tag from the legacy wheel filename
|
|
83
|
-
legacy_wheel_info = self.legacy_wheel_file_re.match(self.filename)
|
|
84
|
-
assert legacy_wheel_info is not None, "guaranteed by filename validation"
|
|
85
|
-
build_tag = legacy_wheel_info.group("build")
|
|
86
|
-
match = re.match(r"^(\d+)(.*)$", build_tag)
|
|
87
|
-
assert match is not None, "guaranteed by filename validation"
|
|
88
|
-
build_tag_groups = match.groups()
|
|
89
|
-
self._build_tag = (int(build_tag_groups[0]), build_tag_groups[1])
|
|
90
|
-
|
|
91
|
-
return self._build_tag
|
|
27
|
+
raise InvalidWheelFilename(e.args[0]) from None
|
|
28
|
+
|
|
29
|
+
self.name, _version, self.build_tag, self.file_tags = wheel_info
|
|
30
|
+
self.version = str(_version)
|
|
92
31
|
|
|
93
32
|
def get_formatted_file_tags(self) -> list[str]:
|
|
94
33
|
"""Return the wheel's tags as a sorted list of strings."""
|
pip/_internal/network/cache.py
CHANGED
|
@@ -13,7 +13,11 @@ from pip._vendor.cachecontrol.cache import SeparateBodyBaseCache
|
|
|
13
13
|
from pip._vendor.cachecontrol.caches import SeparateBodyFileCache
|
|
14
14
|
from pip._vendor.requests.models import Response
|
|
15
15
|
|
|
16
|
-
from pip._internal.utils.filesystem import
|
|
16
|
+
from pip._internal.utils.filesystem import (
|
|
17
|
+
adjacent_tmp_file,
|
|
18
|
+
copy_directory_permissions,
|
|
19
|
+
replace,
|
|
20
|
+
)
|
|
17
21
|
from pip._internal.utils.misc import ensure_dir
|
|
18
22
|
|
|
19
23
|
|
|
@@ -82,16 +86,7 @@ class SafeFileCache(SeparateBodyBaseCache):
|
|
|
82
86
|
writer_func(f)
|
|
83
87
|
# Inherit the read/write permissions of the cache directory
|
|
84
88
|
# to enable multi-user cache use-cases.
|
|
85
|
-
|
|
86
|
-
os.stat(self.directory).st_mode
|
|
87
|
-
& 0o666 # select read/write permissions of cache directory
|
|
88
|
-
| 0o600 # set owner read/write permissions
|
|
89
|
-
)
|
|
90
|
-
# Change permissions only if there is no risk of following a symlink.
|
|
91
|
-
if os.chmod in os.supports_fd:
|
|
92
|
-
os.chmod(f.fileno(), mode)
|
|
93
|
-
elif os.chmod in os.supports_follow_symlinks:
|
|
94
|
-
os.chmod(f.name, mode, follow_symlinks=False)
|
|
89
|
+
copy_directory_permissions(self.directory, f)
|
|
95
90
|
|
|
96
91
|
replace(f.name, path)
|
|
97
92
|
|
|
@@ -11,7 +11,7 @@ from tempfile import NamedTemporaryFile
|
|
|
11
11
|
from typing import Any
|
|
12
12
|
from zipfile import BadZipFile, ZipFile
|
|
13
13
|
|
|
14
|
-
from pip._vendor.packaging.utils import
|
|
14
|
+
from pip._vendor.packaging.utils import NormalizedName
|
|
15
15
|
from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response
|
|
16
16
|
|
|
17
17
|
from pip._internal.metadata import BaseDistribution, MemoryWheel, get_wheel_distribution
|
|
@@ -23,7 +23,9 @@ class HTTPRangeRequestUnsupported(Exception):
|
|
|
23
23
|
pass
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def dist_from_wheel_url(
|
|
26
|
+
def dist_from_wheel_url(
|
|
27
|
+
name: NormalizedName, url: str, session: PipSession
|
|
28
|
+
) -> BaseDistribution:
|
|
27
29
|
"""Return a distribution object from the given wheel URL.
|
|
28
30
|
|
|
29
31
|
This uses HTTP range requests to only fetch the portion of the wheel
|
|
@@ -37,7 +39,7 @@ def dist_from_wheel_url(name: str, url: str, session: PipSession) -> BaseDistrib
|
|
|
37
39
|
wheel = MemoryWheel(zf.name, zf) # type: ignore
|
|
38
40
|
# After context manager exit, wheel.name
|
|
39
41
|
# is an invalid file by intention.
|
|
40
|
-
return get_wheel_distribution(wheel,
|
|
42
|
+
return get_wheel_distribution(wheel, name)
|
|
41
43
|
|
|
42
44
|
|
|
43
45
|
class LazyZipOverHTTP:
|
|
@@ -14,7 +14,7 @@ def build_wheel_pep517(
|
|
|
14
14
|
name: str,
|
|
15
15
|
backend: BuildBackendHookCaller,
|
|
16
16
|
metadata_directory: str,
|
|
17
|
-
|
|
17
|
+
wheel_directory: str,
|
|
18
18
|
) -> str | None:
|
|
19
19
|
"""Build one InstallRequirement using the PEP 517 build process.
|
|
20
20
|
|
|
@@ -22,17 +22,17 @@ def build_wheel_pep517(
|
|
|
22
22
|
"""
|
|
23
23
|
assert metadata_directory is not None
|
|
24
24
|
try:
|
|
25
|
-
logger.debug("Destination directory: %s",
|
|
25
|
+
logger.debug("Destination directory: %s", wheel_directory)
|
|
26
26
|
|
|
27
27
|
runner = runner_with_spinner_message(
|
|
28
28
|
f"Building wheel for {name} (pyproject.toml)"
|
|
29
29
|
)
|
|
30
30
|
with backend.subprocess_runner(runner):
|
|
31
31
|
wheel_name = backend.build_wheel(
|
|
32
|
-
|
|
32
|
+
wheel_directory=wheel_directory,
|
|
33
33
|
metadata_directory=metadata_directory,
|
|
34
34
|
)
|
|
35
35
|
except Exception:
|
|
36
36
|
logger.error("Failed building wheel for %s", name)
|
|
37
37
|
return None
|
|
38
|
-
return os.path.join(
|
|
38
|
+
return os.path.join(wheel_directory, wheel_name)
|
|
@@ -14,7 +14,7 @@ def build_wheel_editable(
|
|
|
14
14
|
name: str,
|
|
15
15
|
backend: BuildBackendHookCaller,
|
|
16
16
|
metadata_directory: str,
|
|
17
|
-
|
|
17
|
+
wheel_directory: str,
|
|
18
18
|
) -> str | None:
|
|
19
19
|
"""Build one InstallRequirement using the PEP 660 build process.
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ def build_wheel_editable(
|
|
|
22
22
|
"""
|
|
23
23
|
assert metadata_directory is not None
|
|
24
24
|
try:
|
|
25
|
-
logger.debug("Destination directory: %s",
|
|
25
|
+
logger.debug("Destination directory: %s", wheel_directory)
|
|
26
26
|
|
|
27
27
|
runner = runner_with_spinner_message(
|
|
28
28
|
f"Building editable for {name} (pyproject.toml)"
|
|
@@ -30,7 +30,7 @@ def build_wheel_editable(
|
|
|
30
30
|
with backend.subprocess_runner(runner):
|
|
31
31
|
try:
|
|
32
32
|
wheel_name = backend.build_editable(
|
|
33
|
-
|
|
33
|
+
wheel_directory=wheel_directory,
|
|
34
34
|
metadata_directory=metadata_directory,
|
|
35
35
|
)
|
|
36
36
|
except HookMissing as e:
|
|
@@ -44,4 +44,4 @@ def build_wheel_editable(
|
|
|
44
44
|
except Exception:
|
|
45
45
|
logger.error("Failed building editable for %s", name)
|
|
46
46
|
return None
|
|
47
|
-
return os.path.join(
|
|
47
|
+
return os.path.join(wheel_directory, wheel_name)
|
|
@@ -444,7 +444,7 @@ class RequirementPreparer:
|
|
|
444
444
|
return None
|
|
445
445
|
|
|
446
446
|
wheel = Wheel(link.filename)
|
|
447
|
-
name =
|
|
447
|
+
name = wheel.name
|
|
448
448
|
logger.info(
|
|
449
449
|
"Obtaining dependency information from %s %s",
|
|
450
450
|
name,
|
|
@@ -531,6 +531,12 @@ class RequirementPreparer:
|
|
|
531
531
|
metadata_dist = self._fetch_metadata_only(req)
|
|
532
532
|
if metadata_dist is not None:
|
|
533
533
|
req.needs_more_preparation = True
|
|
534
|
+
req.set_dist(metadata_dist)
|
|
535
|
+
# Ensure download_info is available even in dry-run mode
|
|
536
|
+
if req.download_info is None:
|
|
537
|
+
req.download_info = direct_url_from_link(
|
|
538
|
+
req.link, req.source_dir
|
|
539
|
+
)
|
|
534
540
|
return metadata_dist
|
|
535
541
|
|
|
536
542
|
# None of the optimizations worked, fully prepare the requirement
|
pip/_internal/pyproject.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import importlib.util
|
|
4
3
|
import os
|
|
5
4
|
from collections import namedtuple
|
|
6
5
|
from typing import Any
|
|
@@ -30,13 +29,11 @@ BuildSystemDetails = namedtuple(
|
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
def load_pyproject_toml(
|
|
33
|
-
|
|
34
|
-
) -> BuildSystemDetails
|
|
32
|
+
pyproject_toml: str, setup_py: str, req_name: str
|
|
33
|
+
) -> BuildSystemDetails:
|
|
35
34
|
"""Load the pyproject.toml file.
|
|
36
35
|
|
|
37
36
|
Parameters:
|
|
38
|
-
use_pep517 - Has the user requested PEP 517 processing? None
|
|
39
|
-
means the user hasn't explicitly specified.
|
|
40
37
|
pyproject_toml - Location of the project's pyproject.toml file
|
|
41
38
|
setup_py - Location of the project's setup.py file
|
|
42
39
|
req_name - The name of the requirement we're processing (for
|
|
@@ -69,57 +66,7 @@ def load_pyproject_toml(
|
|
|
69
66
|
else:
|
|
70
67
|
build_system = None
|
|
71
68
|
|
|
72
|
-
# The following cases must use PEP 517
|
|
73
|
-
# We check for use_pep517 being non-None and falsy because that means
|
|
74
|
-
# the user explicitly requested --no-use-pep517. The value 0 as
|
|
75
|
-
# opposed to False can occur when the value is provided via an
|
|
76
|
-
# environment variable or config file option (due to the quirk of
|
|
77
|
-
# strtobool() returning an integer in pip's configuration code).
|
|
78
|
-
if has_pyproject and not has_setup:
|
|
79
|
-
if use_pep517 is not None and not use_pep517:
|
|
80
|
-
raise InstallationError(
|
|
81
|
-
"Disabling PEP 517 processing is invalid: "
|
|
82
|
-
"project does not have a setup.py"
|
|
83
|
-
)
|
|
84
|
-
use_pep517 = True
|
|
85
|
-
elif build_system and "build-backend" in build_system:
|
|
86
|
-
if use_pep517 is not None and not use_pep517:
|
|
87
|
-
raise InstallationError(
|
|
88
|
-
"Disabling PEP 517 processing is invalid: "
|
|
89
|
-
"project specifies a build backend of {} "
|
|
90
|
-
"in pyproject.toml".format(build_system["build-backend"])
|
|
91
|
-
)
|
|
92
|
-
use_pep517 = True
|
|
93
|
-
|
|
94
|
-
# If we haven't worked out whether to use PEP 517 yet,
|
|
95
|
-
# and the user hasn't explicitly stated a preference,
|
|
96
|
-
# we do so if the project has a pyproject.toml file
|
|
97
|
-
# or if we cannot import setuptools or wheels.
|
|
98
|
-
|
|
99
|
-
# We fallback to PEP 517 when without setuptools or without the wheel package,
|
|
100
|
-
# so setuptools can be installed as a default build backend.
|
|
101
|
-
# For more info see:
|
|
102
|
-
# https://discuss.python.org/t/pip-without-setuptools-could-the-experience-be-improved/11810/9
|
|
103
|
-
# https://github.com/pypa/pip/issues/8559
|
|
104
|
-
elif use_pep517 is None:
|
|
105
|
-
use_pep517 = (
|
|
106
|
-
has_pyproject
|
|
107
|
-
or not importlib.util.find_spec("setuptools")
|
|
108
|
-
or not importlib.util.find_spec("wheel")
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
# At this point, we know whether we're going to use PEP 517.
|
|
112
|
-
assert use_pep517 is not None
|
|
113
|
-
|
|
114
|
-
# If we're using the legacy code path, there is nothing further
|
|
115
|
-
# for us to do here.
|
|
116
|
-
if not use_pep517:
|
|
117
|
-
return None
|
|
118
|
-
|
|
119
69
|
if build_system is None:
|
|
120
|
-
# Either the user has a pyproject.toml with no build-system
|
|
121
|
-
# section, or the user has no pyproject.toml, but has opted in
|
|
122
|
-
# explicitly via --use-pep517.
|
|
123
70
|
# In the absence of any explicit backend specification, we
|
|
124
71
|
# assume the setuptools backend that most closely emulates the
|
|
125
72
|
# traditional direct setup.py execution, and require wheel and
|
|
@@ -130,12 +77,6 @@ def load_pyproject_toml(
|
|
|
130
77
|
"build-backend": "setuptools.build_meta:__legacy__",
|
|
131
78
|
}
|
|
132
79
|
|
|
133
|
-
# If we're using PEP 517, we have build system information (either
|
|
134
|
-
# from pyproject.toml, or defaulted by the code above).
|
|
135
|
-
# Note that at this point, we do not know if the user has actually
|
|
136
|
-
# specified a backend, though.
|
|
137
|
-
assert build_system is not None
|
|
138
|
-
|
|
139
80
|
# Ensure that the build-system section in pyproject.toml conforms
|
|
140
81
|
# to PEP 518.
|
|
141
82
|
|