Skip to content

Commit e92560b

Browse files
authored
Merge pull request #6212 from ncoghlan/issue-6163-use-setuptools-build-meta-legacy-backend
Fix #6163: Default to setuptools.build_meta:__legacy__
2 parents 5a61475 + 682cff7 commit e92560b

File tree

7 files changed

+114
-22
lines changed

7 files changed

+114
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ nosetests.xml
2727
coverage.xml
2828
*.cover
2929
tests/data/common_wheels/
30+
pip-wheel-metadata
3031

3132
# Misc
3233
*~

docs/html/reference/pip.rst

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -145,26 +145,28 @@ explicitly manage the build environment. For such workflows, build isolation
145145
can be problematic. If this is the case, pip provides a
146146
``--no-build-isolation`` flag to disable build isolation. Users supplying this
147147
flag are responsible for ensuring the build environment is managed
148-
appropriately.
148+
appropriately (including ensuring that all required build dependencies are
149+
installed).
149150

150-
By default, pip will continue to use the legacy (``setuptools`` based) build
151-
processing for projects that do not have a ``pyproject.toml`` file. Projects
152-
with a ``pyproject.toml`` file will use a :pep:`517` backend. Projects with
153-
a ``pyproject.toml`` file, but which don't have a ``build-system`` section,
151+
By default, pip will continue to use the legacy (direct ``setup.py`` execution
152+
based) build processing for projects that do not have a ``pyproject.toml`` file.
153+
Projects with a ``pyproject.toml`` file will use a :pep:`517` backend. Projects
154+
with a ``pyproject.toml`` file, but which don't have a ``build-system`` section,
154155
will be assumed to have the following backend settings::
155156

156157
[build-system]
157-
requires = ["setuptools>=40.2.0", "wheel"]
158-
build-backend = "setuptools.build_meta"
158+
requires = ["setuptools>=40.8.0", "wheel"]
159+
build-backend = "setuptools.build_meta:__legacy__"
159160

160161
.. note::
161162

162-
``setuptools`` 40.2.0 is the first version of setuptools with full
163-
:pep:`517` support.
164-
165-
If a project has ``[build-system]``, but no ``build-backend``, pip will use
166-
``setuptools.build_meta``, but will assume the project requirements include
167-
``setuptools>=40.2.0`` and ``wheel`` (and will report an error if not).
163+
``setuptools`` 40.8.0 is the first version of setuptools that offers a
164+
:pep:`517` backend that closely mimics directly executing ``setup.py``.
165+
166+
If a project has ``[build-system]``, but no ``build-backend``, pip will also use
167+
``setuptools.build_meta:__legacy__``, but will expect the project requirements
168+
to include ``setuptools`` and ``wheel`` (and will report an error if the
169+
installed version of ``setuptools`` is not recent enough).
168170

169171
If a user wants to explicitly request :pep:`517` handling even though a project
170172
doesn't have a ``pyproject.toml`` file, this can be done using the

news/6163.bugfix

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
The implicit default backend used for projects that provide a ``pyproject.toml``
2+
file without explicitly specifying ``build-backend`` now behaves more like direct
3+
execution of ``setup.py``, and hence should restore compatibility with projects
4+
that were unable to be installed with ``pip`` 19.0. This raised the minimum
5+
required version of ``setuptools`` for such builds to 40.8.0.

src/pip/_internal/pyproject.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,13 @@ def load_pyproject_toml(
111111
# section, or the user has no pyproject.toml, but has opted in
112112
# explicitly via --use-pep517.
113113
# In the absence of any explicit backend specification, we
114-
# assume the setuptools backend, and require wheel and a version
115-
# of setuptools that supports that backend.
114+
# assume the setuptools backend that most closely emulates the
115+
# traditional direct setup.py execution, and require wheel and
116+
# a version of setuptools that supports that backend.
117+
116118
build_system = {
117-
"requires": ["setuptools>=40.2.0", "wheel"],
118-
"build-backend": "setuptools.build_meta",
119+
"requires": ["setuptools>=40.8.0", "wheel"],
120+
"build-backend": "setuptools.build_meta:__legacy__",
119121
}
120122

121123
# If we're using PEP 517, we have build system information (either
@@ -154,7 +156,7 @@ def load_pyproject_toml(
154156
# If the user didn't specify a backend, we assume they want to use
155157
# the setuptools backend. But we can't be sure they have included
156158
# a version of setuptools which supplies the backend, or wheel
157-
# (which is neede by the backend) in their requirements. So we
159+
# (which is needed by the backend) in their requirements. So we
158160
# make a note to check that those requirements are present once
159161
# we have set up the environment.
160162
# This is quite a lot of work to check for a very specific case. But
@@ -163,7 +165,7 @@ def load_pyproject_toml(
163165
# execute setup.py, but never considered needing to mention the build
164166
# tools themselves. The original PEP 518 code had a similar check (but
165167
# implemented in a different way).
166-
backend = "setuptools.build_meta"
167-
check = ["setuptools>=40.2.0", "wheel"]
168+
backend = "setuptools.build_meta:__legacy__"
169+
check = ["setuptools>=40.8.0", "wheel"]
168170

169171
return (requires, backend, check)

tests/functional/test_install.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_pep518_refuses_conflicting_requires(script, data):
6262
result.returncode != 0 and
6363
('Some build dependencies for %s conflict with PEP 517/518 supported '
6464
'requirements: setuptools==1.0 is incompatible with '
65-
'setuptools>=40.2.0.' % path_to_url(project_dir)) in result.stderr
65+
'setuptools>=40.8.0.' % path_to_url(project_dir)) in result.stderr
6666
), str(result)
6767

6868

tests/functional/test_pep517.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,78 @@ def test_pep517_install_with_no_cache_dir(script, tmpdir, data):
123123
project_dir,
124124
)
125125
result.assert_installed('project', editable=False)
126+
127+
128+
def make_pyproject_with_setup(tmpdir, build_system=True, set_backend=True):
129+
project_dir = (tmpdir / 'project').mkdir()
130+
setup_script = (
131+
'from setuptools import setup\n'
132+
)
133+
expect_script_dir_on_path = True
134+
if build_system:
135+
buildsys = {
136+
'requires': ['setuptools', 'wheel'],
137+
}
138+
if set_backend:
139+
buildsys['build-backend'] = 'setuptools.build_meta'
140+
expect_script_dir_on_path = False
141+
project_data = pytoml.dumps({'build-system': buildsys})
142+
else:
143+
project_data = ''
144+
145+
if expect_script_dir_on_path:
146+
setup_script += (
147+
'from pep517_test import __version__\n'
148+
)
149+
else:
150+
setup_script += (
151+
'try:\n'
152+
' import pep517_test\n'
153+
'except ImportError:\n'
154+
' pass\n'
155+
'else:\n'
156+
' raise RuntimeError("Source dir incorrectly on sys.path")\n'
157+
)
158+
159+
setup_script += (
160+
'setup(name="pep517_test", version="0.1", packages=["pep517_test"])'
161+
)
162+
163+
project_dir.join('pyproject.toml').write(project_data)
164+
project_dir.join('setup.py').write(setup_script)
165+
package_dir = (project_dir / "pep517_test").mkdir()
166+
package_dir.join('__init__.py').write('__version__ = "0.1"')
167+
return project_dir, "pep517_test"
168+
169+
170+
def test_no_build_system_section(script, tmpdir, data, common_wheels):
171+
"""Check builds with setup.py, pyproject.toml, but no build-system section.
172+
"""
173+
project_dir, name = make_pyproject_with_setup(tmpdir, build_system=False)
174+
result = script.pip(
175+
'install', '--no-cache-dir', '--no-index', '-f', common_wheels,
176+
project_dir,
177+
)
178+
result.assert_installed(name, editable=False)
179+
180+
181+
def test_no_build_backend_entry(script, tmpdir, data, common_wheels):
182+
"""Check builds with setup.py, pyproject.toml, but no build-backend entry.
183+
"""
184+
project_dir, name = make_pyproject_with_setup(tmpdir, set_backend=False)
185+
result = script.pip(
186+
'install', '--no-cache-dir', '--no-index', '-f', common_wheels,
187+
project_dir,
188+
)
189+
result.assert_installed(name, editable=False)
190+
191+
192+
def test_explicit_setuptools_backend(script, tmpdir, data, common_wheels):
193+
"""Check builds with setup.py, pyproject.toml, and a build-backend entry.
194+
"""
195+
project_dir, name = make_pyproject_with_setup(tmpdir)
196+
result = script.pip(
197+
'install', '--no-cache-dir', '--no-index', '-f', common_wheels,
198+
project_dir,
199+
)
200+
result.assert_installed(name, editable=False)
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1-
setuptools
1+
# Create local setuptools wheel files for testing by:
2+
# 1. Cloning setuptools and checking out the branch of interest
3+
# 2. Running `python3 bootstrap.py` in that directory
4+
# 3. Running `python3 -m pip wheel --no-cache -w /tmp/setuptools_build_meta_legacy/ .`
5+
# 4. Replacing the `setuptools` entry below with a `file:///...` URL
6+
# (Adjust artifact directory used based on preference and operating system)
7+
8+
setuptools >= 40.8.0
29
wheel

0 commit comments

Comments
 (0)