Skip to content

Commit b6d736b

Browse files
authored
Ability to specify package requirements for the tox run #783 (#936)
Done via the ``tox.ini`` (``tox`` section under key ``requires`` - PEP-508 style). Can be used to specify both plugin requirements or build dependencies until we'll have PEP-517 support. Using ``pkg_resources.Requirement``. Note tox will refuse to run if cannot satisfy dependencies. It's the users responsibility to ensure dependencies are satisfied. ``pkg_resources`` is part of setuptools so added setuptools as dependency. Realized pkg_resources contain everything we used from packaging, dropped packaging as a dependency.
1 parent 10e35bf commit b6d736b

File tree

6 files changed

+60
-7
lines changed

6 files changed

+60
-7
lines changed

changelog/783.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ability to specify package requirements for the tox run via the ``tox.ini`` (``tox`` section under key ``requires`` - PEP-508 style): can be used to specify both plugin requirements or build dependencies. - by :user:`gaborbernat`

doc/config.rst

+11
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ and will first lookup global tox settings in this section:
7777
is identified. In a future version of tox, this warning will become an
7878
error.
7979

80+
.. confval:: requires=LIST
81+
82+
Specify python packages that need to exist alongside the tox installation for the tox build
83+
to be able to start. Use this to specify plugin requirements and build dependencies.
84+
85+
.. code-block:: ini
86+
87+
[tox]
88+
requires = setuptools >= 30.0.0
89+
py
90+
8091
8192
Virtualenv test environment settings
8293
------------------------------------

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def main():
6161
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
6262
setup_requires=["setuptools_scm"],
6363
install_requires=[
64-
"packaging >= 17.1",
64+
"setuptools >= 30.0.0",
6565
"pluggy >= 0.3.0, <1",
6666
"py >= 1.4.17, <2",
6767
"six >= 1.0.0, <2",

src/tox/config.py

+21-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import pkg_resources
1717
import pluggy
1818
import py
19-
from packaging.version import parse
2019

2120
import tox
2221
from tox.interpreters import Interpreters
@@ -908,14 +907,17 @@ def __init__(self, config, inipath): # noqa
908907
# prevent parsing of tox.ini this must be the first thing checked.
909908
config.minversion = reader.getstring("minversion", None)
910909
if config.minversion:
911-
tox_version = parse(tox.__version__)
912-
config_min_version = parse(self.config.minversion)
910+
tox_version = pkg_resources.parse_version(tox.__version__)
911+
config_min_version = pkg_resources.parse_version(self.config.minversion)
913912
if config_min_version > tox_version:
914913
raise tox.exception.MinVersionError(
915914
"tox version is {}, required is at least {}".format(
916915
tox.__version__, self.config.minversion
917916
)
918917
)
918+
919+
self.ensure_requires_satisfied(reader.getlist("requires"))
920+
919921
if config.option.workdir is None:
920922
config.toxworkdir = reader.getpath("toxworkdir", "{toxinidir}/.tox")
921923
else:
@@ -1000,6 +1002,22 @@ def __init__(self, config, inipath): # noqa
10001002

10011003
config.skipsdist = reader.getbool("skipsdist", all_develop)
10021004

1005+
@staticmethod
1006+
def ensure_requires_satisfied(specified):
1007+
fail = False
1008+
for s in specified:
1009+
try:
1010+
pkg_resources.get_distribution(s)
1011+
except pkg_resources.RequirementParseError:
1012+
raise
1013+
except Exception:
1014+
fail = True
1015+
print(
1016+
"requirement missing {}".format(pkg_resources.Requirement(s)), file=sys.stderr
1017+
)
1018+
if fail:
1019+
raise RuntimeError("not all requirements satisfied, install them alongside tox")
1020+
10031021
def _list_section_factors(self, section):
10041022
factors = set()
10051023
if section in self._cfg:

src/tox/session.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
import sys
1414
import time
1515

16+
import pkg_resources
1617
import py
17-
from packaging.version import InvalidVersion, Version
1818

1919
import tox
2020
from tox.config import parseconfig
@@ -779,6 +779,7 @@ def get_version_from_filename(basename):
779779
return None
780780
version = m.group(1)
781781
try:
782-
return Version(version)
783-
except InvalidVersion:
782+
783+
return pkg_resources.packaging.version.Version(version)
784+
except pkg_resources.packaging.version.InvalidVersion:
784785
return None

tests/test_config.py

+22
Original file line numberDiff line numberDiff line change
@@ -2716,3 +2716,25 @@ def test_commands_with_backslash(self, newconfig):
27162716
)
27172717
envconfig = config.envconfigs["py36"]
27182718
assert envconfig.commands[0] == ["some", r"hello\world"]
2719+
2720+
2721+
def test_plugin_require(newconfig, capsys):
2722+
inisource = """
2723+
[tox]
2724+
requires = tox
2725+
name[foo,bar]>=2,<3; python_version>"2.0" and os_name=='a'
2726+
b
2727+
"""
2728+
with pytest.raises(
2729+
RuntimeError, match="not all requirements satisfied, install them alongside tox"
2730+
):
2731+
newconfig([], inisource)
2732+
2733+
out, err = capsys.readouterr()
2734+
assert err.strip() == "\n".join(
2735+
[
2736+
'requirement missing name[bar,foo]<3,>=2; python_version > "2.0" and os_name == "a"',
2737+
"requirement missing b",
2738+
]
2739+
)
2740+
assert not out

0 commit comments

Comments
 (0)