Skip to content

Commit

Permalink
Support building via PyPA/build
Browse files Browse the repository at this point in the history
This commit adds support for using the PyPA build backend
(https://pypa-build.readthedocs.io/en/latest/index.html) to build the project
wheels in an isolated virtualenv as prescribed by PEP517. This is similar to
the existing PEP517 support except that build will first create an sdist and
then produce the wheel from that, thus validating the sdist as well as the
wheel.

This behaviour is controlled by the wheel_pep517 tox testenv attribute - this
was a bool but is now a string. An empty string or missing attribute gives
the legacy behaviour, the string "build" gives the new behaviour, and any other
value gives the previous pip based PEP517 build.

In essence the change is in the command run to build the wheel, switching from
"pip wheel --use-pep517" to "python -Im build". Because there is an extra build
artefact (the sdist), we filter the distdir for wheels only before returning
the first one. Because build is not part of the standard library, it must be
installed in the tox virtualenv to be used - this is accomplished by
implementing the tox_testenv_install_deps() hook, if the wheel_pep517 parameter
is set to "build" then the build package will be installed. Currently it is
necessary to install it with the [virtualenv] option specified, build normally
uses venv to create its isolated environment but that doesn't work inside tox
because venvs currently cannot be created inside virtualenvs. As venv becomes
more accepted (and possibly the internal backend for virtualenv) this
requirement may go away.

In terms of testing, I have simply added two tests (and a fixture) to match
the existing PEP517 behaviour testing.

build has the same requirements of Python 3.6 or above that tox-wheel has so I
have not implemented any kind of checks based on different versions. Locally it
is passing tests on Python 3.8 and 3.9.
  • Loading branch information
Ben Rowland committed Jan 21, 2022
1 parent ec9049c commit 05b0aea
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 5 deletions.
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Authors
* Antonio Botelho - https://github.com/botant
* Thomas Grainger - https://github.com/graingert
* Michael Rans - https://github.com/mcarans
* Ben Rowland - https://github.com/bennyrowland
41 changes: 36 additions & 5 deletions src/tox_wheel/plugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from contextlib import contextmanager
from functools import partial
import os.path

import pluggy
import py
Expand Down Expand Up @@ -31,9 +32,12 @@ def tox_addoption(parser):
)
parser.add_testenv_attribute(
name="wheel_pep517",
type="bool",
default=False,
help="Build wheel using PEP 517/518"
type="string",
default="",
help=(
"Build wheel using PEP 517/518 (pass true to build with pip or "
"build to build with build)"
),
)
parser.add_testenv_attribute(
name="wheel_dirty",
Expand All @@ -59,6 +63,13 @@ def patch(obj, attr, value):
setattr(obj, attr, original)


@hookimpl
def tox_testenv_install_deps(venv, action):
if venv.envconfig.wheel_pep517 == "build":
venv.run_install_command(["build[virtualenv]==0.7.0"], action)
return None


@hookimpl
def tox_package(session, venv):
if hasattr(session, "package"):
Expand Down Expand Up @@ -146,16 +157,36 @@ def wheel_build_pep517(config, session, venv):
action.setactivity("wheel-make", "cleaning up build directory ...")
ensure_empty_dir(config.setupdir.join("build"))
ensure_empty_dir(config.distdir)
if venv.envconfig.wheel_pep517 == "build":
commands = [
"python",
"-Im",
"build",
"--outdir",
config.distdir,
config.setupdir,
]
else:
commands = [
"pip",
"wheel",
config.setupdir,
"--no-deps",
"--use-pep517",
"--wheel-dir",
config.distdir,
]
venv.test(
name="wheel-make",
commands=[["pip", "wheel", config.setupdir, "--no-deps", "--use-pep517", "--wheel-dir", config.distdir]],
commands=[commands],
redirect=False,
ignore_outcome=False,
ignore_errors=False,
display_hash_seed=False,
)
try:
dists = config.distdir.listdir()
# we need to filter our list of dists to include only wheels
dists = [dist for dist in config.distdir.listdir() if os.path.splitext(dist)[1] == ".whl"]
except py.error.ENOENT:
reporter.error(
"No dist directory found. Please check pyproject.toml, e.g with:\n"
Expand Down
55 changes: 55 additions & 0 deletions tests/test_tox_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ def testdir_pep517(testdir):
return testdir


@pytest.fixture
def testdir_pep517_build(testdir):
testdir.tmpdir.join('tox.ini').write("""
[tox]
envlist = py-{a,b}
[testenv]
wheel = true
wheel_pep517 = build
""")
testdir.tmpdir.join('setup.py').write("""
from setuptools import setup
setup(name='foobar')
""")
testdir.tmpdir.join('pyproject.toml').write("""
[build-system]
requires = [
"setuptools >= 35.0.2"
]
build-backend = "setuptools.build_meta"
""")
testdir.tmpdir.join('build').ensure(dir=1)
return testdir


@pytest.fixture(params=['', '--parallel 1 --parallel-live'], ids=['sequential', 'parallel'])
def options(request):
return ['-e', 'py-a,py-b'] + request.param.split()
Expand Down Expand Up @@ -93,6 +119,16 @@ def test_enabled_pep517(testdir_pep517, options):
assert result.ret == 0


def test_enabled_pep517_build(testdir_pep517_build, options):
result = testdir_pep517_build.run('tox', *options)
result.stdout.fnmatch_lines([
'py* wheel-make: *',
])
build_string = 'Successfully built foobar-0.0.0.tar.gz and foobar-0.0.0-py3-none-any.whl'
assert result.stdout.str().count(build_string) == 2
assert result.ret == 0


def test_build_env_legacy(testdir_legacy, options):
testdir_legacy.tmpdir.join('setup.cfg').write("""
[bdist_wheel]
Expand Down Expand Up @@ -135,6 +171,25 @@ def test_build_env_pep517(testdir_pep517, options):
assert result.ret == 0


def test_build_env_pep517_build(testdir_pep517_build, options):
testdir_pep517_build.tmpdir.join('setup.cfg').write("""
[bdist_wheel]
universal = 1
""")
testdir_pep517_build.tmpdir.join('tox.ini').write("""
wheel_build_env = build
[testenv:build]
""", mode='a')
result = testdir_pep517_build.run('tox', *options)
result.stdout.fnmatch_lines([
'build wheel-make: *',
])
build_string = 'Successfully built foobar-0.0.0.tar.gz and foobar-0.0.0-py2.py3-none-any.whl'
assert result.stdout.str().count(build_string) == 1
assert result.ret == 0


@pytest.mark.parametrize('wheel_build_env', ['', 'wheel_build_env'])
def test_skip_usedevelop(testdir_legacy, options, wheel_build_env):
testdir_legacy.tmpdir.join('tox.ini').write("""
Expand Down

0 comments on commit 05b0aea

Please sign in to comment.