summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernát Gábor <bgabor8@bloomberg.net>2019-05-15 17:30:50 +0100
committerGitHub <noreply@github.com>2019-05-15 17:30:50 +0100
commitdd6619346306181c7d8313a86afa4ad7be6f2178 (patch)
treef7a7c5cd971a2fc894aff28ac7b001823f20cd9b
parentbfd22c64acb181955e3e3c126af4aa8da3938828 (diff)
downloadtox-git-dd6619346306181c7d8313a86afa4ad7be6f2178.tar.gz
show config now shows all config, filter-able, contains host tox python and package versions (#1298)
and package versions
-rw-r--r--docs/changelog/1298.feature.rst11
-rw-r--r--src/tox/config/__init__.py26
-rw-r--r--src/tox/session/commands/show_config.py96
-rw-r--r--tests/unit/config/test_config.py49
-rw-r--r--tests/unit/session/test_show_config.py117
-rw-r--r--tox.ini2
6 files changed, 215 insertions, 86 deletions
diff --git a/docs/changelog/1298.feature.rst b/docs/changelog/1298.feature.rst
new file mode 100644
index 00000000..1375c507
--- /dev/null
+++ b/docs/changelog/1298.feature.rst
@@ -0,0 +1,11 @@
+``--showconfig`` overhaul:
+
+- now fully generated via the config parser, so anyone can load it by using the built-in python config parser
+- the ``tox`` section contains all configuration data from config
+- the ``tox`` section contains a ``host_python`` key detailing the path of the host python
+- the ``tox:version`` section contains the versions of all packages tox depends on with their version
+- passing ``-l`` now allows only listing default target envs
+- allows showing config for a given set of tox environments only via the ``-e`` cli flag or the ``TOXENV`` environment
+ variable, in this case the ``tox`` and ``tox:version`` section is only shown if at least one verbosity flag is passed
+
+this should help inspecting the options.
diff --git a/src/tox/config/__init__.py b/src/tox/config/__init__.py
index 418cca9f..6551e0cd 100644
--- a/src/tox/config/__init__.py
+++ b/src/tox/config/__init__.py
@@ -392,7 +392,8 @@ def tox_addoption(parser):
parser.add_argument(
"--showconfig",
action="store_true",
- help="show configuration information for all environments. ",
+ help="show live configuration (by default all env, with -l only default targets,"
+ " specific via TOXENV/-e)",
)
parser.add_argument(
"-l",
@@ -1077,7 +1078,8 @@ class ParseIni(object):
self.handle_provision(config, reader)
self.parse_build_isolation(config, reader)
- config.envlist, all_envs, config.envlist_default = self._getenvdata(reader, config)
+ res = self._getenvdata(reader, config)
+ config.envlist, all_envs, config.envlist_default, config.envlist_explicit = res
# factors used in config or predefined
known_factors = self._list_section_factors("testenv")
@@ -1268,18 +1270,19 @@ class ParseIni(object):
from_config = reader.getstring("envlist", replace=False)
env_list = []
+ envlist_explicit = False
if (from_option and "ALL" in from_option) or (
not from_option and from_environ and "ALL" in from_environ.split(",")
):
all_envs = self._getallenvs(reader)
else:
candidates = (
- os.environ.get(PARALLEL_ENV_VAR_KEY),
- from_option,
- from_environ,
- from_config,
+ (os.environ.get(PARALLEL_ENV_VAR_KEY), True),
+ (from_option, True),
+ (from_environ, True),
+ (from_config, False),
)
- env_str = next((i for i in candidates if i), [])
+ env_str, envlist_explicit = next(((i, e) for i, e in candidates if i), ([], False))
env_list = _split_env(env_str)
all_envs = self._getallenvs(reader, env_list)
@@ -1293,7 +1296,7 @@ class ParseIni(object):
if config.isolated_build is True and package_env in env_list:
msg = "isolated_build_env {} cannot be part of envlist".format(package_env)
raise tox.exception.ConfigError(msg)
- return env_list, all_envs, _split_env(from_config)
+ return env_list, all_envs, _split_env(from_config), envlist_explicit
def _split_env(env):
@@ -1353,21 +1356,22 @@ class DepConfig:
self.name = name
self.indexserver = indexserver
- def __str__(self):
+ def __repr__(self):
if self.indexserver:
if self.indexserver.name == "default":
return self.name
return ":{}:{}".format(self.indexserver.name, self.name)
return str(self.name)
- __repr__ = __str__
-
class IndexServerConfig:
def __init__(self, name, url=None):
self.name = name
self.url = url
+ def __repr__(self):
+ return "IndexServerConfig(name={}, url={})".format(self.name, self.url)
+
is_section_substitution = re.compile(r"{\[[^{}\s]+\]\S+?}").match
"""Check value matches substitution form of referencing value from other section.
diff --git a/src/tox/session/commands/show_config.py b/src/tox/session/commands/show_config.py
index d588ac80..f307cc18 100644
--- a/src/tox/session/commands/show_config.py
+++ b/src/tox/session/commands/show_config.py
@@ -1,31 +1,77 @@
-import subprocess
import sys
+from collections import OrderedDict
-from tox import reporter as report
-from tox.version import __version__
+from six import StringIO
+from six.moves import configparser
+
+from tox import reporter
+
+DO_NOT_SHOW_CONFIG_ATTRIBUTES = (
+ "interpreters",
+ "envconfigs",
+ "envlist",
+ "pluginmanager",
+ "envlist_explicit",
+)
def show_config(config):
- info_versions()
- report.keyvalue("config-file:", config.option.configfile)
- report.keyvalue("toxinipath: ", config.toxinipath)
- report.keyvalue("toxinidir: ", config.toxinidir)
- report.keyvalue("toxworkdir: ", config.toxworkdir)
- report.keyvalue("setupdir: ", config.setupdir)
- report.keyvalue("distshare: ", config.distshare)
- report.keyvalue("skipsdist: ", config.skipsdist)
- report.line("")
- for envconfig in config.envconfigs.values():
- report.line("[testenv:{}]".format(envconfig.envname), bold=True)
- for attr in config._parser._testenv_attr:
- report.line(" {:<15} = {}".format(attr.name, getattr(envconfig, attr.name)))
-
-
-def info_versions():
- versions = ["tox-{}".format(__version__)]
- proc = subprocess.Popen(
- (sys.executable, "-m", "virtualenv", "--version"), stdout=subprocess.PIPE
+ parser = configparser.ConfigParser()
+
+ if not config.envlist_explicit or reporter.verbosity() >= reporter.Verbosity.INFO:
+ tox_info(config, parser)
+ version_info(parser)
+ tox_envs_info(config, parser)
+
+ content = StringIO()
+ parser.write(content)
+ value = content.getvalue().rstrip()
+ reporter.verbosity0(value)
+
+
+def tox_envs_info(config, parser):
+ if config.envlist_explicit:
+ env_list = config.envlist
+ elif config.option.listenvs:
+ env_list = config.envlist_default
+ else:
+ env_list = list(config.envconfigs.keys())
+ for name in env_list:
+ env_config = config.envconfigs[name]
+ values = OrderedDict(
+ (attr.name, str(getattr(env_config, attr.name)))
+ for attr in config._parser._testenv_attr
+ )
+ section = "testenv:{}".format(name)
+ set_section(parser, section, values)
+
+
+def tox_info(config, parser):
+ info = OrderedDict(
+ (i, str(getattr(config, i)))
+ for i in sorted(dir(config))
+ if not i.startswith("_") and i not in DO_NOT_SHOW_CONFIG_ATTRIBUTES
)
- out, _ = proc.communicate()
- versions.append("virtualenv-{}".format(out.decode("UTF-8").strip()))
- report.keyvalue("tool-versions:", " ".join(versions))
+ info["host_python"] = sys.executable
+ set_section(parser, "tox", info)
+
+
+def version_info(parser):
+ import pkg_resources
+
+ versions = OrderedDict()
+ visited = set()
+ to_visit = {"tox"}
+ while to_visit:
+ current = to_visit.pop()
+ visited.add(current)
+ current_dist = pkg_resources.get_distribution(current)
+ to_visit.update(i.name for i in current_dist.requires() if i.name not in visited)
+ versions[current] = current_dist.version
+ set_section(parser, "tox:versions", versions)
+
+
+def set_section(parser, section, values):
+ parser.add_section(section)
+ for key, value in values.items():
+ parser.set(section, key, value)
diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py
index c64ec1be..206fde8d 100644
--- a/tests/unit/config/test_config.py
+++ b/tests/unit/config/test_config.py
@@ -2722,12 +2722,6 @@ class TestCmdInvocation:
assert "some-repr" in version_info
assert "1.0" in version_info
- def test_config_specific_ini(self, tmpdir, cmd):
- ini = tmpdir.ensure("hello.ini")
- result = cmd("-c", ini, "--showconfig")
- assert not result.ret
- assert result.outlines[1] == "config-file: {}".format(ini)
-
def test_no_tox_ini(self, cmd, initproj):
initproj("noini-0.5")
result = cmd()
@@ -2736,49 +2730,6 @@ class TestCmdInvocation:
assert result.err == msg
assert not result.out
- def test_override_workdir(self, cmd, initproj):
- baddir = "badworkdir-123"
- gooddir = "overridden-234"
- initproj(
- "overrideworkdir-0.5",
- filedefs={
- "tox.ini": """
- [tox]
- toxworkdir={}
- """.format(
- baddir
- )
- },
- )
- result = cmd("--workdir", gooddir, "--showconfig")
- assert not result.ret
- assert gooddir in result.out
- assert baddir not in result.out
- assert py.path.local(gooddir).check()
- assert not py.path.local(baddir).check()
-
- def test_showconfig_with_force_dep_version(self, cmd, initproj):
- initproj(
- "force_dep_version",
- filedefs={
- "tox.ini": """
- [tox]
-
- [testenv]
- deps=
- dep1==2.3
- dep2
- """
- },
- )
- result = cmd("--showconfig")
- result.assert_success(is_run_test_env=False)
- assert any(re.match(r".*deps.*dep1==2.3, dep2.*", l) for l in result.outlines)
- # override dep1 specific version, and force version for dep2
- result = cmd("--showconfig", "--force-dep=dep1", "--force-dep=dep2==5.0")
- result.assert_success(is_run_test_env=False)
- assert any(re.match(r".*deps.*dep1, dep2==5.0.*", l) for l in result.outlines)
-
@pytest.mark.parametrize(
"cli_args,run_envlist",
diff --git a/tests/unit/session/test_show_config.py b/tests/unit/session/test_show_config.py
new file mode 100644
index 00000000..1a01d1d8
--- /dev/null
+++ b/tests/unit/session/test_show_config.py
@@ -0,0 +1,117 @@
+import py
+import pytest
+from six import StringIO
+from six.moves import configparser
+
+
+def load_config(args, cmd):
+ result = cmd(*args)
+ result.assert_success(is_run_test_env=False)
+ parser = configparser.ConfigParser()
+ output = StringIO(result.out)
+ parser.readfp(output)
+ return parser
+
+
+def test_showconfig_with_force_dep_version(cmd, initproj):
+ initproj(
+ "force_dep_version",
+ filedefs={
+ "tox.ini": """
+ [tox]
+
+ [testenv]
+ deps=
+ dep1==2.3
+ dep2
+ """
+ },
+ )
+ parser = load_config(("--showconfig",), cmd)
+ assert parser.get("testenv:python", "deps") == "[dep1==2.3, dep2]"
+
+ parser = load_config(("--showconfig", "--force-dep=dep1", "--force-dep=dep2==5.0"), cmd)
+ assert parser.get("testenv:python", "deps") == "[dep1, dep2==5.0]"
+
+
+@pytest.fixture()
+def setup_mixed_conf(initproj):
+ initproj(
+ "force_dep_version",
+ filedefs={
+ "tox.ini": """
+ [tox]
+ envlist = py37,py27,pypi,docs
+
+ [testenv:notincluded]
+ changedir = whatever
+
+ [testenv:docs]
+ changedir = docs
+ """
+ },
+ )
+
+
+@pytest.mark.parametrize(
+ "args, expected",
+ [
+ (
+ ["--showconfig"],
+ [
+ "tox",
+ "tox:versions",
+ "testenv:py37",
+ "testenv:py27",
+ "testenv:pypi",
+ "testenv:docs",
+ "testenv:notincluded",
+ ],
+ ),
+ (
+ ["--showconfig", "-l"],
+ [
+ "tox",
+ "tox:versions",
+ "testenv:py37",
+ "testenv:py27",
+ "testenv:pypi",
+ "testenv:docs",
+ ],
+ ),
+ (["--showconfig", "-e", "py37,py36"], ["testenv:py37", "testenv:py36"]),
+ ],
+ ids=["all", "default_only", "-e"],
+)
+def test_showconfig(cmd, setup_mixed_conf, args, expected):
+ parser = load_config(args, cmd)
+ found_sections = parser.sections()
+ assert found_sections == expected
+
+
+def test_config_specific_ini(tmpdir, cmd):
+ ini = tmpdir.ensure("hello.ini")
+ output = load_config(("-c", ini, "--showconfig"), cmd)
+ assert output.get("tox", "toxinipath") == ini
+
+
+def test_override_workdir(cmd, initproj):
+ baddir = "badworkdir-123"
+ gooddir = "overridden-234"
+ initproj(
+ "overrideworkdir-0.5",
+ filedefs={
+ "tox.ini": """
+ [tox]
+ toxworkdir={}
+ """.format(
+ baddir
+ )
+ },
+ )
+ result = cmd("--workdir", gooddir, "--showconfig")
+ assert not result.ret
+ assert gooddir in result.out
+ assert baddir not in result.out
+ assert py.path.local(gooddir).check()
+ assert not py.path.local(baddir).check()
diff --git a/tox.ini b/tox.ini
index 02cab4c3..dc192ae0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -20,7 +20,7 @@ setenv = PIP_DISABLE_VERSION_CHECK = 1
COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}/.coverage.{envname}}
VIRTUALENV_NO_DOWNLOAD = 1
passenv = http_proxy https_proxy no_proxy SSL_CERT_FILE PYTEST_*
-deps = pip == 19.0.3
+deps = pip == 19.1.1
extras = testing
commands = pytest \
--cov "{envsitepackagesdir}/tox" \