Skip to content

Commit

Permalink
Ability to specify package requirements for the tox run tox-dev#783
Browse files Browse the repository at this point in the history
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 dependency.
  • Loading branch information
gaborbernat committed Aug 9, 2018
1 parent e557705 commit b996cac
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 7 deletions.
1 change: 1 addition & 0 deletions changelog/783.feature.rst
@@ -0,0 +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`
11 changes: 11 additions & 0 deletions doc/config.rst
Expand Up @@ -77,6 +77,17 @@ and will first lookup global tox settings in this section:
is identified. In a future version of tox, this warning will become an
error.

.. confval:: requires=LIST

Specify python packages that need to exist alongside the tox installation for the tox build
to be able to start. Use this to specify plugin requirements and build dependencies.

.. code-block:: ini
[tox]
requires = setuptools >= 30.0.0
tox-venv
Virtualenv test environment settings
------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -61,7 +61,7 @@ def main():
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
setup_requires=["setuptools_scm"],
install_requires=[
"packaging >= 17.1",
"setuptools >= 30.0.0",
"pluggy >= 0.3.0, <1",
"py >= 1.4.17, <2",
"six >= 1.0.0, <2",
Expand Down
24 changes: 21 additions & 3 deletions src/tox/config.py
Expand Up @@ -15,7 +15,6 @@
import pkg_resources
import pluggy
import py
from packaging.version import parse

import tox
from tox.interpreters import Interpreters
Expand Down Expand Up @@ -901,14 +900,17 @@ def __init__(self, config, inipath):
# prevent parsing of tox.ini this must be the first thing checked.
config.minversion = reader.getstring("minversion", None)
if config.minversion:
tox_version = parse(tox.__version__)
config_min_version = parse(self.config.minversion)
tox_version = pkg_resources.parse_version(tox.__version__)
config_min_version = pkg_resources.parse_version(self.config.minversion)
if config_min_version > tox_version:
raise tox.exception.MinVersionError(
"tox version is {}, required is at least {}".format(
tox.__version__, self.config.minversion
)
)

self.ensure_requires_satisfied(reader.getlist("requires"))

if config.option.workdir is None:
config.toxworkdir = reader.getpath("toxworkdir", "{toxinidir}/.tox")
else:
Expand Down Expand Up @@ -989,6 +991,22 @@ def __init__(self, config, inipath):

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

@staticmethod
def ensure_requires_satisfied(specified):
fail = False
for s in specified:
try:
pkg_resources.get_distribution(s)
except pkg_resources.RequirementParseError:
raise
except Exception:
fail = True
print(
"requirement missing {}".format(pkg_resources.Requirement(s)), file=sys.stderr
)
if fail:
raise RuntimeError("not all requirements satisfied, install them alongside tox")

def _list_section_factors(self, section):
factors = set()
if section in self._cfg:
Expand Down
7 changes: 4 additions & 3 deletions src/tox/session.py
Expand Up @@ -13,8 +13,8 @@
import sys
import time

import pkg_resources
import py
from packaging.version import InvalidVersion, Version

import tox
from tox.config import parseconfig
Expand Down Expand Up @@ -775,6 +775,7 @@ def get_version_from_filename(basename):
return None
version = m.group(1)
try:
return Version(version)
except InvalidVersion:

return pkg_resources.packaging.version.Version(version)
except pkg_resources.packaging.version.InvalidVersion:
return None
22 changes: 22 additions & 0 deletions tests/test_config.py
Expand Up @@ -2716,3 +2716,25 @@ def test_commands_with_backslash(self, newconfig):
)
envconfig = config.envconfigs["py36"]
assert envconfig.commands[0] == ["some", r"hello\world"]


def test_plugin_require(newconfig, capsys):
inisource = """
[tox]
requires = tox
name[foo,bar]>=2,<3; python_version>"2.0" and os_name=='a'
b
"""
with pytest.raises(
RuntimeError, match="not all requirements satisfied, install them alongside tox"
):
newconfig([], inisource)

out, err = capsys.readouterr()
assert err.strip() == "\n".join(
[
'requirement missing name[bar,foo]<3,>=2; python_version > "2.0" and os_name == "a"',
"requirement missing b",
]
)
assert not out

0 comments on commit b996cac

Please sign in to comment.