1
0
mirror of https://github.com/fedora-python/tox-current-env.git synced 2024-12-23 16:46:14 +01:00

Add --print-dependency-groups-to

Fixes https://github.com/fedora-python/tox-current-env/issues/81
This commit is contained in:
Miro Hrončok 2024-10-22 15:38:10 +02:00
parent 0cf27856f8
commit e1ce72ca96
6 changed files with 245 additions and 23 deletions

View File

@ -28,7 +28,15 @@ The ``tox-current-env`` plugin adds these options:
This is useful for preparing the current environment for ``tox --current-env``. This is useful for preparing the current environment for ``tox --current-env``.
Use ``-`` for ``FILE`` to print to standard output. 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. ``tox --print-dependency-groups-to=FILE``
Instead of running any ``commands``, simply prints the names of the
`declared dependency_groups <https://tox.wiki/en/latest/config.html#dependency_groups>`_
in ``dependency_groups`` to the specified ``FILE``.
This is useful for preparing the current environment for ``tox --current-env``.
Use ``-`` for ``FILE`` to print to standard output.
This option only exists with tox 4 and requires at least tox 4.22.
It is possible to use the three 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. 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. Any deviation from this behavior is considered a bug.
@ -93,7 +101,7 @@ Usage
----- -----
When the plugin is installed, When the plugin is installed,
use ``tox`` with ``--current-env``, ``--print-deps-to`` or ``--print-extras-to`` use ``tox`` with ``--current-env``, ``--print-deps-to``, ``--print-extras-to`` or ``--print-dependency-groups-to``
and all the other options as usual. and all the other options as usual.
Assuming your ``tox`` is installed on Python 3.7: Assuming your ``tox`` is installed on Python 3.7:
@ -153,6 +161,20 @@ To get a list of names of extras, run:
py37: commands succeeded py37: commands succeeded
congratulations :) congratulations :)
To get a list of names of dependency groups, run:
.. code-block:: console
$ tox -e py37 --print-dependency-groups-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'
group1
...
___________________________________ summary ____________________________________
py37: commands succeeded
congratulations :)
Caveats, warnings and limitations Caveats, warnings and limitations
--------------------------------- ---------------------------------
@ -167,6 +189,7 @@ The plugin is available also for tox 4. Differences in behavior between tox 3 an
- The plugin does not check the requested Python version nor the environment name. - The plugin does not check the requested Python version nor the environment name.
If you let it run for multiple environments they'll all use the same Python. If you let it run for multiple environments they'll all use the same Python.
- Deprecated ``--print-deps-only`` option is no longer available. - Deprecated ``--print-deps-only`` option is no longer available.
- The ``--print-dependency-groups-to`` is only defined on tox 4.
Use an isolated environment Use an isolated environment
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -56,13 +56,23 @@ def tox_add_option(parser):
help="Don't run tests, only print the names of the required extras to the given file " help="Don't run tests, only print the names of the required extras to the given file "
+ "(use `-` for stdout)", + "(use `-` for stdout)",
) )
parser.add_argument(
"--print-dependency-groups-to",
"--print-dependency-groups-to-file",
action="store",
type=argparse.FileType("w"),
metavar="FILE",
default=False,
help="Don't run tests, only print the names of the required dependency-groups to the given file "
+ "(use `-` for stdout)",
)
@impl @impl
def tox_add_core_config(core_conf, state): def tox_add_core_config(core_conf, state):
opt = state.conf.options opt = state.conf.options
if opt.current_env or opt.print_deps_to or opt.print_extras_to: if opt.current_env or opt.print_deps_to or opt.print_extras_to or opt.print_dependency_groups_to:
# We do not want to install the main package. # We do not want to install the main package.
# no_package is the same as skipsdist. # no_package is the same as skipsdist.
loader = MemoryLoader(no_package=True) loader = MemoryLoader(no_package=True)
@ -72,14 +82,14 @@ def tox_add_core_config(core_conf, state):
opt.default_runner = "current-env" opt.default_runner = "current-env"
return return
if getattr(opt.print_deps_to, "name", object()) == getattr( exclusive = [getattr(getattr(opt, o), "name", object())
opt.print_extras_to, "name", object() for o in ("print_deps_to", "print_extras_to", "print_dependency_groups_to")]
): if len(exclusive) != len(set(exclusive)):
raise RuntimeError( raise RuntimeError(
"The paths given to --print-deps-to and --print-extras-to cannot be identical." "The paths given to --print-*-to options cannot be identical."
) )
if opt.print_deps_to or opt.print_extras_to: if opt.print_deps_to or opt.print_extras_to or opt.print_dependency_groups_to:
opt.default_runner = "print-env" opt.default_runner = "print-env"
return return
@ -98,9 +108,8 @@ def tox_add_env_config(env_conf, state):
if opt.current_env: if opt.current_env:
allow_external_cmds = MemoryLoader(allowlist_externals=["*"], pass_env=["*"]) allow_external_cmds = MemoryLoader(allowlist_externals=["*"], pass_env=["*"])
env_conf.loaders.insert(0, allow_external_cmds) env_conf.loaders.insert(0, allow_external_cmds)
# For print-deps-to and print-extras-to, use empty # For print-*-to, use empty list of commands so that tox does nothing.
# list of commands so the tox does nothing. if opt.print_deps_to or opt.print_extras_to or opt.print_dependency_groups_to:
if opt.print_deps_to or opt.print_extras_to:
empty_commands = MemoryLoader(commands=[], commands_pre=[], commands_post=[]) empty_commands = MemoryLoader(commands=[], commands_pre=[], commands_post=[])
env_conf.loaders.insert(0, empty_commands) env_conf.loaders.insert(0, empty_commands)
@ -261,10 +270,21 @@ class PrintEnv(CurrentEnv):
) )
self.options.print_extras_to.flush() self.options.print_extras_to.flush()
if self.options.print_dependency_groups_to:
if "dependency_groups" not in self.conf:
raise RuntimeError(
"tox is too old to know about dependency_groups."
)
print(
*self.conf["dependency_groups"],
sep="\n",
file=self.options.print_dependency_groups_to,
)
self.options.print_dependency_groups_to.flush()
# https://github.com/fedora-python/tox-current-env/issues/75 # https://github.com/fedora-python/tox-current-env/issues/75
return super().prepend_env_var_path() return super().prepend_env_var_path()
@staticmethod @staticmethod
def id(): def id():
return "print-env" return "print-env"

View File

@ -2,7 +2,7 @@ import os
import shutil import shutil
import pytest import pytest
from utils import FIXTURES_DIR, TOX4, modify_config, drop_unsupported_pythons from utils import FIXTURES_DIR, TOX_VERSION, TOX4, modify_config, drop_unsupported_pythons
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -41,3 +41,16 @@ def print_deps_stdout_arg(request):
def print_extras_stdout_arg(request): def print_extras_stdout_arg(request):
"""Argument for printing extras to stdout""" """Argument for printing extras to stdout"""
return request.param return request.param
@pytest.fixture
def dependency_groups_support():
"""Support for dependency groups"""
if (TOX_VERSION.major, TOX_VERSION.minor) < (4, 22):
raise pytest.skip(reason="requires tox 4.22 or higher")
@pytest.fixture(params=("--print-dependency-groups-to-file=-", "--print-dependency-groups-to=-"))
def print_dependency_groups_stdout_arg(request, dependency_groups_support):
"""Argument for printing dependency groups to stdout"""
return request.param

View File

@ -1,3 +1,6 @@
[build-system] [build-system]
requires = ["setuptools"] requires = ["setuptools"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
[dependency-groups]
dg1 = ["build>=1"]

View File

@ -11,6 +11,8 @@ deps =
extras = extras =
dev dev
full full
dependency_groups =
dg1
commands = commands =
python -c 'import os, sys; print(os.path.realpath(sys.exec_prefix), "is the exec_prefix")' python -c 'import os, sys; print(os.path.realpath(sys.exec_prefix), "is the exec_prefix")'
# we explicitly clear this because the inner tox does not need to know # we explicitly clear this because the inner tox does not need to know

View File

@ -138,6 +138,30 @@ def test_print_extras(toxenv, print_extras_stdout_arg):
) )
@pytest.mark.parametrize("toxenv", envs_from_tox_ini())
def test_print_dependency_groups(toxenv, print_dependency_groups_stdout_arg):
result = tox("-e", toxenv, print_dependency_groups_stdout_arg)
expected = textwrap.dedent(
f"""
dg1
{tox_footer(toxenv)}
"""
).lstrip()
assert sorted(prep_tox_output(result.stdout).splitlines()) == sorted(
expected.splitlines()
)
@pytest.mark.parametrize("toxenv", envs_from_tox_ini())
def test_print_dependency_groups_empty(projdir, toxenv, print_dependency_groups_stdout_arg):
with modify_config(projdir / 'tox.ini') as config:
del config["testenv"]["dependency_groups"]
result = tox("-e", toxenv, print_dependency_groups_stdout_arg)
expected = [l.strip() for l in tox_footer(toxenv).splitlines() if l.strip()]
got = [l.strip() for l in prep_tox_output(result.stdout).splitlines() if l.strip()]
assert got == expected
@pytest.mark.parametrize("toxenv", envs_from_tox_ini()) @pytest.mark.parametrize("toxenv", envs_from_tox_ini())
@pytest.mark.parametrize("pre_post", ["pre", "post", "both"]) @pytest.mark.parametrize("pre_post", ["pre", "post", "both"])
def test_print_extras_with_commands_pre_post(projdir, toxenv, pre_post, print_extras_stdout_arg): def test_print_extras_with_commands_pre_post(projdir, toxenv, pre_post, print_extras_stdout_arg):
@ -183,6 +207,17 @@ def test_allenvs_print_extras(print_extras_stdout_arg):
assert sorted(prep_tox_output(result.stdout).splitlines()) == sorted(expected) assert sorted(prep_tox_output(result.stdout).splitlines()) == sorted(expected)
def test_allenvs_print_dependency_groups(print_dependency_groups_stdout_arg):
result = tox(print_dependency_groups_stdout_arg)
expected = []
for env in envs_from_tox_ini():
expected.extend(("dg1", f"{env}: OK"))
expected.pop() # The last "py310: OK" is not there
expected.append(tox_footer(spaces=0))
expected = ("\n".join(expected)).splitlines()
assert sorted(prep_tox_output(result.stdout).splitlines()) == sorted(expected)
@pytest.mark.parametrize("toxenv", envs_from_tox_ini()) @pytest.mark.parametrize("toxenv", envs_from_tox_ini())
def test_print_deps_to_file(toxenv, tmp_path): def test_print_deps_to_file(toxenv, tmp_path):
depspath = tmp_path / "deps" depspath = tmp_path / "deps"
@ -203,6 +238,15 @@ def test_print_extras_to_file(toxenv, tmp_path):
assert prep_tox_output(result.stdout) == expected assert prep_tox_output(result.stdout) == expected
@pytest.mark.parametrize("toxenv", envs_from_tox_ini())
def test_print_dependency_groups_to_file(toxenv, tmp_path, dependency_groups_support):
groupspath = tmp_path / "dependency_groups"
result = tox("-e", toxenv, "--print-dependency-groups-to", str(groupspath))
assert sorted(groupspath.read_text().splitlines()) == ["dg1"]
expected = tox_footer(toxenv, spaces=0) + "\n"
assert prep_tox_output(result.stdout) == expected
@pytest.mark.parametrize("option", ("--print-deps-to", "--print-deps-to-file")) @pytest.mark.parametrize("option", ("--print-deps-to", "--print-deps-to-file"))
def test_allenvs_print_deps_to_file(tmp_path, option): def test_allenvs_print_deps_to_file(tmp_path, option):
depspath = tmp_path / "deps" depspath = tmp_path / "deps"
@ -231,6 +275,20 @@ def test_allenvs_print_extras_to_file(tmp_path, option):
assert prep_tox_output(result.stdout) == expected assert prep_tox_output(result.stdout) == expected
@pytest.mark.parametrize("option", ("--print-dependency-groups-to", "--print-dependency-groups-to-file"))
def test_allenvs_print_dependency_groups_to_file(tmp_path, option, dependency_groups_support):
groupspath = tmp_path / "dependency_groups"
result = tox(option, str(groupspath))
assert sorted(groupspath.read_text().splitlines()) == (
["dg1"] * len(envs_from_tox_ini())
)
expected = ""
for env in envs_from_tox_ini()[:-1]:
expected += f"{env}: OK\n"
expected += tox_footer(spaces=0) + "\n"
assert prep_tox_output(result.stdout) == expected
def test_allenvs_print_deps_to_existing_file(tmp_path): def test_allenvs_print_deps_to_existing_file(tmp_path):
depspath = tmp_path / "deps" depspath = tmp_path / "deps"
depspath.write_text("nada") depspath.write_text("nada")
@ -251,26 +309,28 @@ def test_allenvs_print_extras_to_existing_file(tmp_path):
assert "full" in lines assert "full" in lines
def test_allenvs_print_dependency_groups_to_existing_file(tmp_path, dependency_groups_support):
groupspath = tmp_path / "dependency_groups"
groupspath.write_text("nada")
_ = tox("--print-dependency-groups-to", str(groupspath))
lines = groupspath.read_text().splitlines()
assert "nada" not in lines
assert "dg1" in lines
@pytest.mark.parametrize("deps_stdout", [True, False]) @pytest.mark.parametrize("deps_stdout", [True, False])
@pytest.mark.parametrize("extras_stdout", [True, False]) @pytest.mark.parametrize("extras_stdout", [True, False])
def test_allenvs_print_deps_to_file_print_extras_to_other_file( def test_allenvs_print_deps_to_file_print_extras_to_other_file(
tmp_path, deps_stdout, extras_stdout tmp_path, deps_stdout, extras_stdout
): ):
if deps_stdout and extras_stdout: if deps_stdout and extras_stdout:
pytest.xfail("Unsupported combination of parameters") pytest.skip("Unsupported combination of parameters")
depspath = "-" if deps_stdout else tmp_path / "deps" depspath = "-" if deps_stdout else tmp_path / "deps"
extraspath = "-" if extras_stdout else tmp_path / "extras" extraspath = "-" if extras_stdout else tmp_path / "extras"
result = tox("--print-deps-to", str(depspath), "--print-extras-to", str(extraspath)) result = tox("--print-deps-to", str(depspath), "--print-extras-to", str(extraspath))
if deps_stdout: depslines = result.stdout.splitlines() if deps_stdout else depspath.read_text().splitlines()
depslines = result.stdout.splitlines() extraslines = result.stdout.splitlines() if extras_stdout else extraspath.read_text().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 "six" in depslines
assert "py" in depslines assert "py" in depslines
@ -283,6 +343,45 @@ def test_allenvs_print_deps_to_file_print_extras_to_other_file(
assert "dev" not in depslines assert "dev" not in depslines
@pytest.mark.parametrize("deps_stdout", [True, False])
@pytest.mark.parametrize("extras_stdout", [True, False])
@pytest.mark.parametrize("dependency_groups_stdout", [True, False])
def test_allenvs_print_deps_to_file_print_extras_to_other_file_print_dependency_groups_to_other_file(
tmp_path, deps_stdout, extras_stdout, dependency_groups_stdout, dependency_groups_support
):
if deps_stdout + extras_stdout + dependency_groups_stdout > 1:
pytest.skip("Unsupported combination of parameters")
depspath = "-" if deps_stdout else tmp_path / "deps"
extraspath = "-" if extras_stdout else tmp_path / "extras"
groupspath = "-" if dependency_groups_stdout else tmp_path / "dependency_groups"
result = tox("--print-deps-to", str(depspath),
"--print-extras-to", str(extraspath),
"--print-dependency-groups-to", str(groupspath))
depslines = result.stdout.splitlines() if deps_stdout else depspath.read_text().splitlines()
extraslines = result.stdout.splitlines() if extras_stdout else extraspath.read_text().splitlines()
groupslines = result.stdout.splitlines() if dependency_groups_stdout else groupspath.read_text().splitlines()
assert "six" in depslines
assert "py" in depslines
assert "full" in extraslines
assert "dev" in extraslines
assert "dg1" in groupslines
assert "six" not in extraslines
assert "py" not in extraslines
assert "dg1" not in extraslines
assert "full" not in depslines
assert "dev" not in depslines
assert "dg1" not in depslines
assert "six" not in groupslines
assert "py" not in groupslines
assert "full" not in groupslines
assert "dev" not in groupslines
def test_print_deps_extras_to_same_file_is_not_possible(tmp_path): def test_print_deps_extras_to_same_file_is_not_possible(tmp_path):
depsextraspath = tmp_path / "depsextras" depsextraspath = tmp_path / "depsextras"
result = tox( result = tox(
@ -298,6 +397,36 @@ def test_print_deps_extras_to_same_file_is_not_possible(tmp_path):
assert "cannot be identical" in result.stderr assert "cannot be identical" in result.stderr
def test_print_deps_dependency_groups_to_same_file_is_not_possible(tmp_path, dependency_groups_support):
depsgroupspath = tmp_path / "depsgroups"
result = tox(
"-e",
NATIVE_TOXENV,
"--print-deps-to",
str(depsgroupspath),
"--print-dependency-groups-to",
str(depsgroupspath),
check=False,
)
assert result.returncode > 0
assert "cannot be identical" in result.stderr
def test_print_extras_dependency_groups_to_same_file_is_not_possible(tmp_path, dependency_groups_support):
extrasgroupspath = tmp_path / "extrasgroups"
result = tox(
"-e",
NATIVE_TOXENV,
"--print-extras-to",
str(extrasgroupspath),
"--print-dependency-groups-to",
str(extrasgroupspath),
check=False,
)
assert result.returncode > 0
assert "cannot be identical" in result.stderr
def test_print_deps_extras_to_stdout_is_not_possible( def test_print_deps_extras_to_stdout_is_not_possible(
tmp_path, tmp_path,
print_deps_stdout_arg, print_deps_stdout_arg,
@ -314,6 +443,38 @@ def test_print_deps_extras_to_stdout_is_not_possible(
assert "cannot be identical" in result.stderr assert "cannot be identical" in result.stderr
def test_print_deps_dependency_groups_to_stdout_is_not_possible(
tmp_path,
print_deps_stdout_arg,
print_dependency_groups_stdout_arg,
):
result = tox(
"-e",
NATIVE_TOXENV,
print_deps_stdout_arg,
print_dependency_groups_stdout_arg,
check=False,
)
assert result.returncode > 0
assert "cannot be identical" in result.stderr
def test_print_extras_dependency_groups_to_stdout_is_not_possible(
tmp_path,
print_extras_stdout_arg,
print_dependency_groups_stdout_arg,
):
result = tox(
"-e",
NATIVE_TOXENV,
print_extras_stdout_arg,
print_dependency_groups_stdout_arg,
check=False,
)
assert result.returncode > 0
assert "cannot be identical" in result.stderr
@needs_all_pythons @needs_all_pythons
def test_regular_run(): def test_regular_run():
result = tox() result = tox()