mirror of
https://github.com/fedora-python/tox-current-env.git
synced 2024-12-24 09:06:15 +01:00
Add the --print-extras-to(-file) option
This commit is contained in:
parent
6feb98352a
commit
6dd32b21ce
44
README.rst
44
README.rst
@ -5,7 +5,7 @@ tox-current-env
|
||||
`tox <https://tox.readthedocs.io/>`_ plugin to run tests in current Python environment
|
||||
---------------------------------------------------------------------------------------
|
||||
|
||||
The ``tox-current-env`` plugin adds two options:
|
||||
The ``tox-current-env`` plugin adds these options:
|
||||
|
||||
``tox --current-env``
|
||||
Runs the tox testenv's ``commands`` in the current Python environment
|
||||
@ -15,11 +15,21 @@ The ``tox-current-env`` plugin adds two options:
|
||||
(if ``tox`` is invoked from an Python 3.7 environment, any non 3.7 testenv will fail).
|
||||
|
||||
``tox --print-deps-to=FILE``
|
||||
Instead of running any ``commands``,
|
||||
simply prints the declared dependencies in ``deps`` to the specified ``FILE``.
|
||||
This is useful for preparing the current environment for the above.
|
||||
Instead of running any ``commands``, simply prints the
|
||||
`declared dependencies <https://tox.readthedocs.io/en/latest/config.html#conf-deps>`_
|
||||
in ``deps`` to the specified ``FILE``.
|
||||
This is useful for preparing the current environment for ``tox --current-env``.
|
||||
Use ``-`` for ``FILE`` to print to standard output.
|
||||
|
||||
``tox --print-extras-to=FILE``
|
||||
Instead of running any ``commands``, simply prints the names of the
|
||||
`declared extras <https://tox.readthedocs.io/en/latest/config.html#conf-extras>`_
|
||||
in ``extras`` to the specified ``FILE``.
|
||||
This is useful for preparing the current environment for ``tox --current-env``.
|
||||
Use ``-`` for ``FILE`` to print to standard output.
|
||||
|
||||
It is possible to use the two printing options together, as long as the ``FILE`` is different.
|
||||
|
||||
Invoking ``tox`` without any of the above options should behave as regular ``tox`` invocation without this plugin.
|
||||
Any deviation from this behavior is considered a bug.
|
||||
|
||||
@ -82,7 +92,10 @@ and ``pip``-installing locally:
|
||||
Usage
|
||||
-----
|
||||
|
||||
When the plugin is installed, use ``tox`` with ``--current-env`` or ``--print-deps-to`` and all the other options as usual. Assuming your ``tox`` is installed on Python 3.7:
|
||||
When the plugin is installed,
|
||||
use ``tox`` with ``--current-env``, ``--print-deps-to`` or ``--print-extras-to``
|
||||
and all the other options as usual.
|
||||
Assuming your ``tox`` is installed on Python 3.7:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
@ -125,6 +138,21 @@ To get list of test dependencies, run:
|
||||
py37: commands succeeded
|
||||
congratulations :)
|
||||
|
||||
To get a list of names of extras, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox -e py37 --print-extras-to -
|
||||
py37 create: /home/pythonista/projects/holy-grail/tests/.tox/py37
|
||||
py37 installed: ...you can see almost anything here...
|
||||
py37 run-test-pre: PYTHONHASHSEED='3333333333'
|
||||
extra1
|
||||
extra2
|
||||
...
|
||||
___________________________________ summary ____________________________________
|
||||
py37: commands succeeded
|
||||
congratulations :)
|
||||
|
||||
|
||||
Caveats, warnings and limitations
|
||||
---------------------------------
|
||||
@ -159,8 +187,8 @@ Don't mix current-env and regular tox runs
|
||||
|
||||
Tox caches the virtualenvs it creates, and doesn't distinguish between
|
||||
regular virtualenvs and ``--current-env``.
|
||||
Don't mix ``tox --current-env`` or ``tox --print-deps-to`` runs
|
||||
and regular ``tox`` runs (without the flag).
|
||||
Don't mix ``tox --current-env``, ``tox --print-deps-to`` or ``tox --print-extras-to``
|
||||
runs and regular ``tox`` runs (without the flags provided by this plugin).
|
||||
If you ever need to do this, use tox's ``--recreate/-r`` flag to clear the cache.
|
||||
|
||||
The plugin should abort with a meaningful error message if this is detected,
|
||||
@ -183,7 +211,7 @@ Read `the documentation for passing environment variables to tox
|
||||
Other limitations and known bugs
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``installed:`` line in the output of ``tox --print-deps-to`` shows irrelevant output
|
||||
The ``installed:`` line in the output of ``tox --print-deps-to``/``tox --print-extras-to`` shows irrelevant output
|
||||
(based on the content of the real or faked virtual environment).
|
||||
|
||||
Regardless of any `Python flags <https://docs.python.org/3/using/cmdline.html>`_ used in the shebang of ``tox``,
|
||||
|
@ -38,6 +38,16 @@ def tox_addoption(parser):
|
||||
help="Don't run tests, only print the dependencies to the given file "
|
||||
+ "(use `-` for stdout)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--print-extras-to",
|
||||
"--print-extras-to-file",
|
||||
action="store",
|
||||
type=argparse.FileType('w'),
|
||||
metavar="FILE",
|
||||
default=None,
|
||||
help="Don't run tests, only print the names of the required extras to the given file "
|
||||
+ "(use `-` for stdout)",
|
||||
)
|
||||
|
||||
|
||||
@tox.hookimpl
|
||||
@ -55,11 +65,17 @@ def tox_configure(config):
|
||||
"--print-deps-only cannot be used together "
|
||||
+ "with --print-deps-to"
|
||||
)
|
||||
if config.option.current_env or config.option.print_deps_to:
|
||||
if config.option.current_env or config.option.print_deps_to or config.option.print_extras_to:
|
||||
config.skipsdist = True
|
||||
for testenv in config.envconfigs:
|
||||
config.envconfigs[testenv].whitelist_externals = "*"
|
||||
|
||||
if (getattr(config.option.print_deps_to, "name", object()) ==
|
||||
getattr(config.option.print_extras_to, "name", object())):
|
||||
raise tox.exception.ConfigError(
|
||||
"The paths given to --print-deps-to and --print-extras-to cannot be identical."
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@ -97,16 +113,17 @@ def rm_venv(venv):
|
||||
def unsupported_raise(config, venv):
|
||||
if config.option.recreate:
|
||||
return
|
||||
regular = not (config.option.current_env or config.option.print_deps_to)
|
||||
regular = not (config.option.current_env or config.option.print_deps_to or config.option.print_extras_to)
|
||||
if regular and is_current_env_link(venv):
|
||||
if hasattr(tox.hookspecs, "tox_cleanup"):
|
||||
raise tox.exception.ConfigError(
|
||||
"Looks like previous --current-env or --print-deps-to tox run didn't finish the cleanup. "
|
||||
"Looks like previous --current-env, --print-deps-to or --print-extras-to tox run didn't finish the cleanup. "
|
||||
"Run tox run with --recreate (-r) or manually remove the environment in .tox."
|
||||
)
|
||||
else:
|
||||
raise tox.exception.ConfigError(
|
||||
"Regular tox run after --current-env or --print-deps-to tox run is not supported without --recreate (-r)."
|
||||
"Regular tox run after --current-env, --print-deps-to or --print-extras-to tox run "
|
||||
"is not supported without --recreate (-r)."
|
||||
)
|
||||
elif config.option.current_env and is_proper_venv(venv):
|
||||
raise tox.exception.ConfigError(
|
||||
@ -119,7 +136,7 @@ def tox_testenv_create(venv, action):
|
||||
"""We create a fake virtualenv with just the symbolic link"""
|
||||
config = venv.envconfig.config
|
||||
create_fake_env = check_version = config.option.current_env
|
||||
if config.option.print_deps_to:
|
||||
if config.option.print_deps_to or config.option.print_extras_to:
|
||||
if is_any_env(venv):
|
||||
# We don't need anything
|
||||
return True
|
||||
@ -130,7 +147,7 @@ def tox_testenv_create(venv, action):
|
||||
# because it's cheaper, faster and won't install stuff
|
||||
create_fake_env = True
|
||||
if check_version:
|
||||
# With real --current-env, we check this, but not with --print-deps-to only
|
||||
# With real --current-env, we check this, but not with --print-deps/extras-to only
|
||||
version_info = venv.envconfig.python_info.version_info
|
||||
if version_info is None:
|
||||
raise tox.exception.InterpreterNotFound(venv.envconfig.basepython)
|
||||
@ -178,16 +195,30 @@ def tox_testenv_install_deps(venv, action):
|
||||
|
||||
@tox.hookimpl
|
||||
def tox_runtest(venv, redirect):
|
||||
"""If --print-deps-to, prints deps instead of running tests"""
|
||||
"""If --print-deps-to, prints deps instead of running tests.
|
||||
If --print-extras-to, prints extras instead of running tests.
|
||||
Both options can be used together."""
|
||||
config = venv.envconfig.config
|
||||
unsupported_raise(config, venv)
|
||||
ret = None
|
||||
|
||||
if config.option.print_deps_to:
|
||||
print(
|
||||
*venv.get_resolved_dependencies(),
|
||||
sep="\n",
|
||||
file=config.option.print_deps_to,
|
||||
)
|
||||
return True
|
||||
ret = True
|
||||
|
||||
if config.option.print_extras_to:
|
||||
print(
|
||||
*venv.envconfig.extras,
|
||||
sep="\n",
|
||||
file=config.option.print_extras_to,
|
||||
)
|
||||
ret = True
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@tox.hookimpl
|
||||
|
8
tests/fixtures/setup.py
vendored
8
tests/fixtures/setup.py
vendored
@ -1,3 +1,9 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(name="test")
|
||||
setup(
|
||||
name="test",
|
||||
extras_require={
|
||||
"dev": [],
|
||||
"full": [],
|
||||
}
|
||||
)
|
||||
|
3
tests/fixtures/tox.ini
vendored
3
tests/fixtures/tox.ini
vendored
@ -5,5 +5,8 @@ envlist = py36,py37,py38,py39
|
||||
deps =
|
||||
six
|
||||
py
|
||||
extras =
|
||||
dev
|
||||
full
|
||||
commands =
|
||||
python -c 'import os, sys; print(os.path.realpath(sys.exec_prefix), "is the exec_prefix")'
|
||||
|
@ -36,6 +36,12 @@ def print_deps_stdout_arg(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(params=('--print-extras-to-file=-', '--print-extras-to=-'))
|
||||
def print_extras_stdout_arg(request):
|
||||
"""Argument for printing extras to stdout"""
|
||||
return request.param
|
||||
|
||||
|
||||
def tox(*args, quiet=True, **kwargs):
|
||||
kwargs.setdefault("encoding", "utf-8")
|
||||
kwargs.setdefault("stdout", subprocess.PIPE)
|
||||
@ -121,6 +127,21 @@ def test_print_deps(toxenv, print_deps_stdout_arg):
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("toxenv", ["py36", "py37", "py38", "py39"])
|
||||
def test_print_extras(toxenv, print_extras_stdout_arg):
|
||||
result = tox("-e", toxenv, print_extras_stdout_arg)
|
||||
expected = textwrap.dedent(
|
||||
f"""
|
||||
dev
|
||||
full
|
||||
___________________________________ summary ____________________________________
|
||||
{toxenv}: commands succeeded
|
||||
congratulations :)
|
||||
"""
|
||||
).lstrip()
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("toxenv", ["py36", "py37", "py38", "py39"])
|
||||
def test_print_deps_only_deprecated(toxenv):
|
||||
result = tox(
|
||||
@ -157,6 +178,29 @@ def test_allenvs_print_deps(print_deps_stdout_arg):
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
def test_allenvs_print_extras(print_extras_stdout_arg):
|
||||
result = tox(print_extras_stdout_arg)
|
||||
expected = textwrap.dedent(
|
||||
"""
|
||||
dev
|
||||
full
|
||||
dev
|
||||
full
|
||||
dev
|
||||
full
|
||||
dev
|
||||
full
|
||||
___________________________________ summary ____________________________________
|
||||
py36: commands succeeded
|
||||
py37: commands succeeded
|
||||
py38: commands succeeded
|
||||
py39: commands succeeded
|
||||
congratulations :)
|
||||
"""
|
||||
).lstrip()
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("toxenv", ["py36", "py37", "py38", "py39"])
|
||||
def test_print_deps_to_file(toxenv, tmp_path):
|
||||
depspath = tmp_path / "deps"
|
||||
@ -172,6 +216,21 @@ def test_print_deps_to_file(toxenv, tmp_path):
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("toxenv", ["py36", "py37", "py38", "py39"])
|
||||
def test_print_extras_to_file(toxenv, tmp_path):
|
||||
extraspath = tmp_path / "extras"
|
||||
result = tox("-e", toxenv, "--print-extras-to", str(extraspath))
|
||||
assert extraspath.read_text().splitlines() == ["dev", "full"]
|
||||
expected = textwrap.dedent(
|
||||
f"""
|
||||
___________________________________ summary ____________________________________
|
||||
{toxenv}: commands succeeded
|
||||
congratulations :)
|
||||
"""
|
||||
).lstrip()
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize('option', ('--print-deps-to', '--print-deps-to-file'))
|
||||
def test_allenvs_print_deps_to_file(tmp_path, option):
|
||||
depspath = tmp_path / "deps"
|
||||
@ -190,6 +249,24 @@ def test_allenvs_print_deps_to_file(tmp_path, option):
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize('option', ('--print-extras-to', '--print-extras-to-file'))
|
||||
def test_allenvs_print_extras_to_file(tmp_path, option):
|
||||
extraspath = tmp_path / "extras"
|
||||
result = tox(option, str(extraspath))
|
||||
assert extraspath.read_text().splitlines() == ["dev", "full"] * 4
|
||||
expected = textwrap.dedent(
|
||||
"""
|
||||
___________________________________ summary ____________________________________
|
||||
py36: commands succeeded
|
||||
py37: commands succeeded
|
||||
py38: commands succeeded
|
||||
py39: commands succeeded
|
||||
congratulations :)
|
||||
"""
|
||||
).lstrip()
|
||||
assert result.stdout == expected
|
||||
|
||||
|
||||
def test_allenvs_print_deps_to_existing_file(tmp_path):
|
||||
depspath = tmp_path / "deps"
|
||||
depspath.write_text("nada")
|
||||
@ -200,6 +277,75 @@ def test_allenvs_print_deps_to_existing_file(tmp_path):
|
||||
assert "py" in lines
|
||||
|
||||
|
||||
def test_allenvs_print_extras_to_existing_file(tmp_path):
|
||||
extraspath = tmp_path / "extras"
|
||||
extraspath.write_text("nada")
|
||||
result = tox("--print-extras-to", str(extraspath))
|
||||
lines = extraspath.read_text().splitlines()
|
||||
assert "nada" not in lines
|
||||
assert "dev" in lines
|
||||
assert "full" in lines
|
||||
|
||||
|
||||
@pytest.mark.parametrize("deps_stdout", [True, False])
|
||||
@pytest.mark.parametrize("extras_stdout", [True, False])
|
||||
def test_allenvs_print_deps_to_file_print_extras_to_other_file(tmp_path, deps_stdout, extras_stdout):
|
||||
if deps_stdout and extras_stdout:
|
||||
pytest.xfail("Unsupported combination of parameters")
|
||||
|
||||
depspath = "-" if deps_stdout else tmp_path / "deps"
|
||||
extraspath = "-" if extras_stdout else tmp_path / "extras"
|
||||
result = tox("--print-deps-to", str(depspath),
|
||||
"--print-extras-to", str(extraspath))
|
||||
if deps_stdout:
|
||||
depslines = result.stdout.splitlines()
|
||||
extraslines = extraspath.read_text().splitlines()
|
||||
elif extras_stdout:
|
||||
depslines = depspath.read_text().splitlines()
|
||||
extraslines = result.stdout.splitlines()
|
||||
else:
|
||||
extraslines = extraspath.read_text().splitlines()
|
||||
depslines = depspath.read_text().splitlines()
|
||||
|
||||
assert "six" in depslines
|
||||
assert "py" in depslines
|
||||
assert "full" in extraslines
|
||||
assert "dev" in extraslines
|
||||
|
||||
assert "six" not in extraslines
|
||||
assert "py" not in extraslines
|
||||
assert "full" not in depslines
|
||||
assert "dev" not in depslines
|
||||
|
||||
|
||||
def test_print_deps_extras_to_same_file_is_not_possible(tmp_path):
|
||||
depsextraspath = tmp_path / "depsextras"
|
||||
result = tox(
|
||||
"-e",
|
||||
NATIVE_TOXENV,
|
||||
"--print-deps-to", str(depsextraspath),
|
||||
"--print-extras-to", str(depsextraspath),
|
||||
check=False,
|
||||
)
|
||||
assert result.returncode > 0
|
||||
assert "cannot be identical" in result.stderr
|
||||
|
||||
|
||||
def test_print_deps_extras_to_stdout_is_not_possible(
|
||||
tmp_path,
|
||||
print_deps_stdout_arg,
|
||||
print_extras_stdout_arg,):
|
||||
result = tox(
|
||||
"-e",
|
||||
NATIVE_TOXENV,
|
||||
print_deps_stdout_arg,
|
||||
print_extras_stdout_arg,
|
||||
check=False,
|
||||
)
|
||||
assert result.returncode > 0
|
||||
assert "cannot be identical" in result.stderr
|
||||
|
||||
|
||||
def test_print_deps_only_print_deps_to_file_are_mutually_exclusive():
|
||||
result = tox(
|
||||
"-e",
|
||||
@ -319,6 +465,16 @@ def test_current_after_print_deps(print_deps_stdout_arg):
|
||||
assert result.stdout.splitlines()[0] == NATIVE_EXEC_PREFIX_MSG
|
||||
|
||||
|
||||
def test_current_after_print_extras(print_extras_stdout_arg):
|
||||
# this is quite fast, so we can do it several times
|
||||
for _ in range(3):
|
||||
result = tox("-e", NATIVE_TOXENV, print_extras_stdout_arg)
|
||||
assert "bin/python" not in result.stdout
|
||||
assert "full" in result.stdout
|
||||
result = tox("-re", NATIVE_TOXENV, "--current-env")
|
||||
assert result.stdout.splitlines()[0] == NATIVE_EXEC_PREFIX_MSG
|
||||
|
||||
|
||||
def test_regular_recreate_after_print_deps(print_deps_stdout_arg):
|
||||
result = tox("-e", NATIVE_TOXENV, print_deps_stdout_arg)
|
||||
assert "bin/python" not in result.stdout
|
||||
|
Loading…
Reference in New Issue
Block a user