Add Plugin Support similar to Pytest (through pluggy)
How would this feature be useful?
For sufficiently complex CI/CD pipelines, the noxfile can get a bit out of hand in terms of length. In my case, the cookiecutter I am working on has gotten to the point that I have a scripts folder for running sufficiently complex steps.
The goal here would be to enable the use of remotely defined CI/CD plugins that can be partially/fully overwritten locally if desired, while making use of pytest's system to aid in defining out a solid system for accomplishing this.
Some other benefits that could come from this are:
- Enabling partial overwrites of portions of nox sessions. (Think pytest fixtures, like how you can overwrite pytest plugin fixtures as needed)
- plugins using maturin for any internal logic, allowing for faster builds without sacrificing the ability to overwrite portions locally
- Easier grouping of dependencies for portions of CI. For example, rather than 5 different sphinx plugin installs, it could just be plugin "nox-sphinx" has its own dependencies.
- Having nox recipes available as plugins that you can just use or overwrite as needed, rather than having to copy paste into every project
Describe the solution you'd like
There is already a ton of groundwork laid out between pytest and tox both using pluggy. It might make sense to then try and parody many of pytest's existing structures.
For an example of a user based view of this, here is a small demo project kind of showing what comes to mind: https://github.com/56kyle/nox-plugin-proposal
Granted there is a ton of flexibility that could be brought over from pytest that may not be useful, so I'm hesitant to begin any implementation before at least feeling out what people may find useful if anything.
Describe alternatives you've considered
Some things I have considered:
- Swapping to tox
- Would require way more complex templating logic in cookiecutter
- Would lose support surrounding envs not using any python venv
- overall just a bunch of QoL stuff that would be lost
- Local imports in utility package
- Would need an init.py in the repo root, which am definitely avoiding
- Doesn't allow for nested overwriting of select parts the same way that plugins do
- Swapping to just
- Trying to avoid implicit dependencies for CICD's sake
- Would lose out on convenient python testing across versions
Anything else?
I appreciate you taking the time to read this! This may be a bit of a long shot, but it really feels like a nice fit at first glance, so may as well see if anyone else is interested in this idea.
If anyone has any ideas that I may not have thought of for better approaching the problems I described, I would greatly appreciate any advice!
I would not use pluggy; as far as I can tell it doesn't really add anything over the modern standard library entry-point feature.
And I don't think it makes much sense to support plugins that must be pre-installed; for example, I install nox via homebrew, so I can't install other stuff into my nox install. Anyone using nox would have to somehow know that they also need to install other stuff before running nox, which is kind of the point of nox. You use nox to install all the plugins pytest needs, but who manages nox?
Tox does have a feature where it downloads a plugin it needs before running, but we actually have the same feature, thanks to PEP 723! And you don't need any special system for it, since nox is written in Python. For example, let's say you have custom scripts at https://github.com/my/repo. Then you could do:
# /// script
# dependencies = ["nox>=2025.02.09", "repo @ git+https://github.com/my/repo"]
# ///
import nox
import repo
repo.do_fancy_stuff()
Now, when you run nox, it will make a session and rerun itself from inside that session, with the dependencies you requested. As you see above, you can install anything pip/uv allows, and do anything Python allows.
The only thing a more explicit plugin system would allow would be a way to override core parts of nox itself, but there aren't many - just installer backends, things like that - most user code is implemented in Python.
I really appreciate the heads up about PEP 723, that definitely solves a pretty large aspect of what I found myself running into! Am currently working on implementing it, and will make sure to update this with results on what all has changed