Skip to content

Commit

Permalink
Merge pull request #6212 from ncoghlan/issue-6163-use-setuptools-buil…
Browse files Browse the repository at this point in the history
…d-meta-legacy-backend

Fix #6163: Default to setuptools.build_meta:__legacy__
  • Loading branch information
pradyunsg authored Feb 6, 2019
2 parents 5a61475 + 682cff7 commit e92560b
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ nosetests.xml
coverage.xml
*.cover
tests/data/common_wheels/
pip-wheel-metadata

# Misc
*~
Expand Down
28 changes: 15 additions & 13 deletions docs/html/reference/pip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,26 +145,28 @@ explicitly manage the build environment. For such workflows, build isolation
can be problematic. If this is the case, pip provides a
``--no-build-isolation`` flag to disable build isolation. Users supplying this
flag are responsible for ensuring the build environment is managed
appropriately.
appropriately (including ensuring that all required build dependencies are
installed).

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

[build-system]
requires = ["setuptools>=40.2.0", "wheel"]
build-backend = "setuptools.build_meta"
requires = ["setuptools>=40.8.0", "wheel"]
build-backend = "setuptools.build_meta:__legacy__"

.. note::

``setuptools`` 40.2.0 is the first version of setuptools with full
:pep:`517` support.

If a project has ``[build-system]``, but no ``build-backend``, pip will use
``setuptools.build_meta``, but will assume the project requirements include
``setuptools>=40.2.0`` and ``wheel`` (and will report an error if not).
``setuptools`` 40.8.0 is the first version of setuptools that offers a
:pep:`517` backend that closely mimics directly executing ``setup.py``.

If a project has ``[build-system]``, but no ``build-backend``, pip will also use
``setuptools.build_meta:__legacy__``, but will expect the project requirements
to include ``setuptools`` and ``wheel`` (and will report an error if the
installed version of ``setuptools`` is not recent enough).

If a user wants to explicitly request :pep:`517` handling even though a project
doesn't have a ``pyproject.toml`` file, this can be done using the
Expand Down
5 changes: 5 additions & 0 deletions news/6163.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The implicit default backend used for projects that provide a ``pyproject.toml``
file without explicitly specifying ``build-backend`` now behaves more like direct
execution of ``setup.py``, and hence should restore compatibility with projects
that were unable to be installed with ``pip`` 19.0. This raised the minimum
required version of ``setuptools`` for such builds to 40.8.0.
16 changes: 9 additions & 7 deletions src/pip/_internal/pyproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,13 @@ def load_pyproject_toml(
# section, or the user has no pyproject.toml, but has opted in
# explicitly via --use-pep517.
# In the absence of any explicit backend specification, we
# assume the setuptools backend, and require wheel and a version
# of setuptools that supports that backend.
# assume the setuptools backend that most closely emulates the
# traditional direct setup.py execution, and require wheel and
# a version of setuptools that supports that backend.

build_system = {
"requires": ["setuptools>=40.2.0", "wheel"],
"build-backend": "setuptools.build_meta",
"requires": ["setuptools>=40.8.0", "wheel"],
"build-backend": "setuptools.build_meta:__legacy__",
}

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

return (requires, backend, check)
2 changes: 1 addition & 1 deletion tests/functional/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def test_pep518_refuses_conflicting_requires(script, data):
result.returncode != 0 and
('Some build dependencies for %s conflict with PEP 517/518 supported '
'requirements: setuptools==1.0 is incompatible with '
'setuptools>=40.2.0.' % path_to_url(project_dir)) in result.stderr
'setuptools>=40.8.0.' % path_to_url(project_dir)) in result.stderr
), str(result)


Expand Down
75 changes: 75 additions & 0 deletions tests/functional/test_pep517.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,78 @@ def test_pep517_install_with_no_cache_dir(script, tmpdir, data):
project_dir,
)
result.assert_installed('project', editable=False)


def make_pyproject_with_setup(tmpdir, build_system=True, set_backend=True):
project_dir = (tmpdir / 'project').mkdir()
setup_script = (
'from setuptools import setup\n'
)
expect_script_dir_on_path = True
if build_system:
buildsys = {
'requires': ['setuptools', 'wheel'],
}
if set_backend:
buildsys['build-backend'] = 'setuptools.build_meta'
expect_script_dir_on_path = False
project_data = pytoml.dumps({'build-system': buildsys})
else:
project_data = ''

if expect_script_dir_on_path:
setup_script += (
'from pep517_test import __version__\n'
)
else:
setup_script += (
'try:\n'
' import pep517_test\n'
'except ImportError:\n'
' pass\n'
'else:\n'
' raise RuntimeError("Source dir incorrectly on sys.path")\n'
)

setup_script += (
'setup(name="pep517_test", version="0.1", packages=["pep517_test"])'
)

project_dir.join('pyproject.toml').write(project_data)
project_dir.join('setup.py').write(setup_script)
package_dir = (project_dir / "pep517_test").mkdir()
package_dir.join('__init__.py').write('__version__ = "0.1"')
return project_dir, "pep517_test"


def test_no_build_system_section(script, tmpdir, data, common_wheels):
"""Check builds with setup.py, pyproject.toml, but no build-system section.
"""
project_dir, name = make_pyproject_with_setup(tmpdir, build_system=False)
result = script.pip(
'install', '--no-cache-dir', '--no-index', '-f', common_wheels,
project_dir,
)
result.assert_installed(name, editable=False)


def test_no_build_backend_entry(script, tmpdir, data, common_wheels):
"""Check builds with setup.py, pyproject.toml, but no build-backend entry.
"""
project_dir, name = make_pyproject_with_setup(tmpdir, set_backend=False)
result = script.pip(
'install', '--no-cache-dir', '--no-index', '-f', common_wheels,
project_dir,
)
result.assert_installed(name, editable=False)


def test_explicit_setuptools_backend(script, tmpdir, data, common_wheels):
"""Check builds with setup.py, pyproject.toml, and a build-backend entry.
"""
project_dir, name = make_pyproject_with_setup(tmpdir)
result = script.pip(
'install', '--no-cache-dir', '--no-index', '-f', common_wheels,
project_dir,
)
result.assert_installed(name, editable=False)
9 changes: 8 additions & 1 deletion tools/tests-common_wheels-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
setuptools
# Create local setuptools wheel files for testing by:
# 1. Cloning setuptools and checking out the branch of interest
# 2. Running `python3 bootstrap.py` in that directory
# 3. Running `python3 -m pip wheel --no-cache -w /tmp/setuptools_build_meta_legacy/ .`
# 4. Replacing the `setuptools` entry below with a `file:///...` URL
# (Adjust artifact directory used based on preference and operating system)

setuptools >= 40.8.0
wheel

0 comments on commit e92560b

Please sign in to comment.