Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requesting dependencies in a noxfile #848

Open
henryiii opened this issue Sep 10, 2024 · 3 comments
Open

Requesting dependencies in a noxfile #848

henryiii opened this issue Sep 10, 2024 · 3 comments

Comments

@henryiii
Copy link
Collaborator

How would this feature be useful?

This is just a wild idea, nothing might come of it, so take it with a grain of salt!

I’d like to have the ability to define and use packages inside the noxfile itself. Since nox knows how to make venvs and install packages, it seems like it should be able to request packages and even new nox versions. This would be a key prerequisite for supporting plugins, and 80% of the functionality of plugins would come from just being able to add packages; since noxfiles are just Python, you could write a package that adds common sessions, for example, and just use it in the noxfile, no need for a plugin system. An actual plugin system could be for things like new venv backends, locking, etc, and is not addressed yet by this proposal.

Describe the solution you'd like

The core idea here is that nox could read PEP 723 data. This is dependencies, requires-python, and tool.nox. For the initial proposal, I'm suggesting using the standard dependencies and requires-python.

Nox would evaluate these two fields before it reads the noxfile.py. If the conditions are not met, it would try to make a special “_nox_self” environment (session) with the requirements and then run nox from there. This would only happen once - this new run would not be allowed to do this again (though it should always pass since you installed those requirements). requires-python would be respected (though this could be implemented in a follow-up). Due to the way this works, you kind of get nox.needs-version for free!

# /// script
# dependencies = [“nox>=2024.12.31”, “nox-some-standard-sessions”, "pyyaml"]
# requires-python = ">=3.10"
# ///

If any of the packages are not installed, then the requirements list doesn’t pass and a new environment with a new nox is created, then called.

There are two downsides to not using our own tool.nox section above:

  • You would not be able to specify this in pyproject.toml. Don’t think that’s too important, I don't think these need to be specified in pyproject.toml.
  • This is not runnable by standardized runners, but only by nox.

For the second point, I think we could actually provide a way to make a noxfile runnable via these tools. I played with it, and since we require nox above in the dependencies, and you can nearly fake it now with a if __name__ == “__main__”: nox.__main__.main() block. We could probably add a way to do this and make noxfiles (with a minor user addition) valid PEP 723 files. The real question would be, though, is that required, or can we just use it in this way for now? If the answer is no, anything with dependencies/requires-python must be runnable by standardized runners (which I don't think is the case), we can replace this with tool.nox.* settings instead.

Describe alternatives you've considered

Using tool.nox.* is mentioned above. If we did do that, we wouldn't require nox to be in the "tool.nox.requirements" list. I've also considered following nox.needs-version's design, but that is fragile, and now post PEP 723 I don't think it's the right way to do this. We could even add tool.nox.needs-version, but since it's mostly covered by the dependencies above, I didn't think it was needed.

In the past, I've also played with the idea of nox downloading into the current environment, but that's fragile and you can't upgrade anything. This would even allow you to upgrade nox itself, at the cost of being a bit slower. Nox could always reuse the environment if the requirements still pass, and uv makes this very fast, and I think we are erring on the side of ease-of-use over raw speed, so I think this is fine. We could have an argument that controls this behavior (which then could also be used to disable the behavior on the second call).

Anything else?

No response

@brettcannon
Copy link
Contributor

I actually had Nox and this use case in mind when asking for PEP 722/723 and I approved it. 😁

I think if there was a nox.main() in the API - which I was just looking for to implement this very idea -- then you could then rely on, e.g., pipx run noxfile.py to make everything go and not require folks install Nox upfront.

@henryiii
Copy link
Collaborator Author

henryiii commented Oct 10, 2024

Adding this works today, actually, since nox sets __name__ to user_nox_module:

# /// script
# dependencies = ["nox"]
# ///

... # exiting noxfile here

if __name__ == "__main__":
    import nox.__main__

    nox.__main__.main()
$ pipx run noxfile.py --list
Sessions defined in /Users/henryschreiner/git/software/python-pyproject-metadata/noxfile.py:

* mypy -> Run a type checker.
* test-3.7 -> Run the test suite.
* test-3.8 -> Run the test suite.
* test-3.9 -> Run the test suite.
* test-3.10 -> Run the test suite.
* test-3.11 -> Run the test suite.
* test-3.12 -> Run the test suite.
* test-3.13 -> Run the test suite.
- docs -> Build the docs. Use "--non-interactive" to avoid serving. Pass "-b linkcheck" to check links.

sessions marked with * are selected, sessions marked with - are skipped.

@jamesharris-garmin
Copy link

I noticed in your mechanism for requesting this that you mention it would be wise to configure the backend that controls the install.

I worry about virtualenv being the fallback here because virtualenv will try to update to the latest pip and friends in some circumstances that makes runs non-deterministic.

A more deterministic default would be uv|venv.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants