Make external packaging environments only run once.
What's the problem this feature will solve?
I have a tox file like this:
[tox]
envlist = py39,docs
[testenv:.pkg]
deps = build
package_glob = {envtmpdir}/dist/*.whl
commands = python -m build -o {envtmpdir}/dist
[testenv]
package = external
package_env = .pkg
commands = pytest
[testenv:docs]
commands = sphinx-build docs {envtmpdir}/html
When I build this, first my .bld env is run to create a .whl of my package, this is installed into py39 and tests are run, and then .bld is run again to generate an identical wheel to the first time, to be installed into the docs env. On my system building a skeleton project takes nearly a minute, but I have some complicated projects which are compiling extensions etc. which can take several minutes to complete. Re-running the build environment to produce the same .whl is a pointless waste of time.
Describe the solution you'd like
It would be nice if each tox env knew the package (just as a path should be fine) that it had installed into itself (if it has been run), then passing package_env=X would either get the current env to just try and install the package already installed into X, or X would run first, then supply its package to the current env to be installed.
This could apply only to packaging environments but could equally be useful if the main env is building the package internally, but the docs env just wants to install the same .sdist or same .whl. Also this would be useful when you are building a wheel which is compatible with multiple Python versions and want to re-use it to test across different versions. At the moment this is supported for the package=wheel option with the wheel_build_env option, but there is nothing equivalent for the package-external option.
Alternative Solutions
I was formerly solving this problem with the plugin tox-wheel, which has exactly this kind of caching of the package on venvs, so each env can request the package from any other env. However, the tox_package() plugin hook that this relied on seems to have been removed in tox 4. The external packaging environments in tox 4 are a great feature that I really want to use, but until builds can be re-used they are just too slow.
Additional context
If this is a feature that the maintainers would support including, I am happy to work on a PR myself (with a little guidance).
PR welcome 👍
This would be nice to have, but in the meantime I asked about this in SO and figured out a workaround. I won't copy-paste the whole answer here but in essence, I'm using the tox hook tox_on_install and relying to the fact, that (luckily) the hook is called on the special environment .pkg_external also in the case when install_requires (or install_deps or both) is cached. Since that is called exactly once before any commands of other environments are called, I create a dummy file /dist/.TOX-ASKS-REBUILD during the execution of the hook. Then, in the tox.ini [.pkg_external] I have this:
[testenv:.pkg_external]
deps =
build==1.1.1
commands =
python tests/build_mypkg.py
which calls a build script, which checks if the .TOX-ASKS-REBUILD is there.
- If
.TOX-ASKS-REBUILDexists, remove the/distfolder and rebuild (happens during first environment which does not haveskip_install=True) - If
.TOX-ASKS-REBUILDdoes not exist, do nothing. (happens all other environments which does not haveskip_install=True)
The downside of this is that it does not support parallel mode. But otherwise it cuts down the time tox requires a lot.