Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
keewenaw
GitHub Repository: keewenaw/ethereum-wallet-cracker
Path: blob/main/test/lib/python3.9/site-packages/pip/_internal/pyproject.py
4799 views
1
import importlib.util
2
import os
3
from collections import namedtuple
4
from typing import Any, List, Optional
5
6
from pip._vendor import tomli
7
from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
8
9
from pip._internal.exceptions import (
10
InstallationError,
11
InvalidPyProjectBuildRequires,
12
MissingPyProjectBuildRequires,
13
)
14
15
16
def _is_list_of_str(obj: Any) -> bool:
17
return isinstance(obj, list) and all(isinstance(item, str) for item in obj)
18
19
20
def make_pyproject_path(unpacked_source_directory: str) -> str:
21
return os.path.join(unpacked_source_directory, "pyproject.toml")
22
23
24
BuildSystemDetails = namedtuple(
25
"BuildSystemDetails", ["requires", "backend", "check", "backend_path"]
26
)
27
28
29
def load_pyproject_toml(
30
use_pep517: Optional[bool], pyproject_toml: str, setup_py: str, req_name: str
31
) -> Optional[BuildSystemDetails]:
32
"""Load the pyproject.toml file.
33
34
Parameters:
35
use_pep517 - Has the user requested PEP 517 processing? None
36
means the user hasn't explicitly specified.
37
pyproject_toml - Location of the project's pyproject.toml file
38
setup_py - Location of the project's setup.py file
39
req_name - The name of the requirement we're processing (for
40
error reporting)
41
42
Returns:
43
None if we should use the legacy code path, otherwise a tuple
44
(
45
requirements from pyproject.toml,
46
name of PEP 517 backend,
47
requirements we should check are installed after setting
48
up the build environment
49
directory paths to import the backend from (backend-path),
50
relative to the project root.
51
)
52
"""
53
has_pyproject = os.path.isfile(pyproject_toml)
54
has_setup = os.path.isfile(setup_py)
55
56
if not has_pyproject and not has_setup:
57
raise InstallationError(
58
f"{req_name} does not appear to be a Python project: "
59
f"neither 'setup.py' nor 'pyproject.toml' found."
60
)
61
62
if has_pyproject:
63
with open(pyproject_toml, encoding="utf-8") as f:
64
pp_toml = tomli.loads(f.read())
65
build_system = pp_toml.get("build-system")
66
else:
67
build_system = None
68
69
# The following cases must use PEP 517
70
# We check for use_pep517 being non-None and falsey because that means
71
# the user explicitly requested --no-use-pep517. The value 0 as
72
# opposed to False can occur when the value is provided via an
73
# environment variable or config file option (due to the quirk of
74
# strtobool() returning an integer in pip's configuration code).
75
if has_pyproject and not has_setup:
76
if use_pep517 is not None and not use_pep517:
77
raise InstallationError(
78
"Disabling PEP 517 processing is invalid: "
79
"project does not have a setup.py"
80
)
81
use_pep517 = True
82
elif build_system and "build-backend" in build_system:
83
if use_pep517 is not None and not use_pep517:
84
raise InstallationError(
85
"Disabling PEP 517 processing is invalid: "
86
"project specifies a build backend of {} "
87
"in pyproject.toml".format(build_system["build-backend"])
88
)
89
use_pep517 = True
90
91
# If we haven't worked out whether to use PEP 517 yet,
92
# and the user hasn't explicitly stated a preference,
93
# we do so if the project has a pyproject.toml file
94
# or if we cannot import setuptools.
95
96
# We fallback to PEP 517 when without setuptools,
97
# so setuptools can be installed as a default build backend.
98
# For more info see:
99
# https://discuss.python.org/t/pip-without-setuptools-could-the-experience-be-improved/11810/9
100
elif use_pep517 is None:
101
use_pep517 = has_pyproject or not importlib.util.find_spec("setuptools")
102
103
# At this point, we know whether we're going to use PEP 517.
104
assert use_pep517 is not None
105
106
# If we're using the legacy code path, there is nothing further
107
# for us to do here.
108
if not use_pep517:
109
return None
110
111
if build_system is None:
112
# Either the user has a pyproject.toml with no build-system
113
# section, or the user has no pyproject.toml, but has opted in
114
# explicitly via --use-pep517.
115
# In the absence of any explicit backend specification, we
116
# assume the setuptools backend that most closely emulates the
117
# traditional direct setup.py execution, and require wheel and
118
# a version of setuptools that supports that backend.
119
120
build_system = {
121
"requires": ["setuptools>=40.8.0", "wheel"],
122
"build-backend": "setuptools.build_meta:__legacy__",
123
}
124
125
# If we're using PEP 517, we have build system information (either
126
# from pyproject.toml, or defaulted by the code above).
127
# Note that at this point, we do not know if the user has actually
128
# specified a backend, though.
129
assert build_system is not None
130
131
# Ensure that the build-system section in pyproject.toml conforms
132
# to PEP 518.
133
134
# Specifying the build-system table but not the requires key is invalid
135
if "requires" not in build_system:
136
raise MissingPyProjectBuildRequires(package=req_name)
137
138
# Error out if requires is not a list of strings
139
requires = build_system["requires"]
140
if not _is_list_of_str(requires):
141
raise InvalidPyProjectBuildRequires(
142
package=req_name,
143
reason="It is not a list of strings.",
144
)
145
146
# Each requirement must be valid as per PEP 508
147
for requirement in requires:
148
try:
149
Requirement(requirement)
150
except InvalidRequirement as error:
151
raise InvalidPyProjectBuildRequires(
152
package=req_name,
153
reason=f"It contains an invalid requirement: {requirement!r}",
154
) from error
155
156
backend = build_system.get("build-backend")
157
backend_path = build_system.get("backend-path", [])
158
check: List[str] = []
159
if backend is None:
160
# If the user didn't specify a backend, we assume they want to use
161
# the setuptools backend. But we can't be sure they have included
162
# a version of setuptools which supplies the backend, or wheel
163
# (which is needed by the backend) in their requirements. So we
164
# make a note to check that those requirements are present once
165
# we have set up the environment.
166
# This is quite a lot of work to check for a very specific case. But
167
# the problem is, that case is potentially quite common - projects that
168
# adopted PEP 518 early for the ability to specify requirements to
169
# execute setup.py, but never considered needing to mention the build
170
# tools themselves. The original PEP 518 code had a similar check (but
171
# implemented in a different way).
172
backend = "setuptools.build_meta:__legacy__"
173
check = ["setuptools>=40.8.0", "wheel"]
174
175
return BuildSystemDetails(requires, backend, check, backend_path)
176
177