comparison lib/python3.8/site-packages/pip/_internal/pyproject.py @ 0:9e54283cc701 draft

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