Skip to content

Add a variant of a nox script runner that entirely delegates to uv run - #1095

Open
agriyakhetarpal wants to merge 11 commits into
wntrblm:mainfrom
agriyakhetarpal:nox-uv-script-runner
Open

Add a variant of a nox script runner that entirely delegates to uv run#1095
agriyakhetarpal wants to merge 11 commits into
wntrblm:mainfrom
agriyakhetarpal:nox-uv-script-runner

Conversation

@agriyakhetarpal

@agriyakhetarpal agriyakhetarpal commented May 29, 2026

Copy link
Copy Markdown
Contributor

This PR adds a session.uv_run_script() to complement the session.install_and_run_script() session method. While install_and_run_script installs PEP 723 dependencies into the session's own virtualenv and runs with Python, uv_run_script delegates the entire run to uv run, so uv owns environment creation, dependency resolution, caching, and so on.

I've added docs and tests, and some test plumbing in this PR that I found useful to include.

cc: @henryiii
xref pypa/cibuildwheel#2873 (comment)

some use cases

  • Scripts that use tool.uv.sources (git, path, or workspace overrides, etc.), tool.uv.index for custom indices, or tool.uv.exclude-newer are silently ignored by install_and_run_script but respected if you use uv run to run them.
  • Faster repeated runs via uv's global cache, without reinstalling into the session venv (not a big help by any sense, but still pretty useful)
  • Pinning the script to a specific Python version if one wants, via uv_args=["--python", "3.12"]
  • Packages not declared in the script block can also be injected, via uv_args=["--with", "pkg"] and the like

Of course, this raises an error if nox[uv] isn't present. My idea with this is that this feature is along the lines of Python packaging tools such as pypa/build passing on to uv as the installer with build[uv] and so on.

caveats

There are two that I can note:

  • The script runs outside the session's virtualenv, so packages installed earlier in the session are not visible. I'd argue this is by design, because making it venv-aware introduces tricky questions, such as which resolver wins when there's a conflict between the session's installed packages and the script's dependencies, and suchlike.
  • install_and_run_script is better to use when the script needs access to the session's environment.

AI disclosure

I used Claude Sonnet 4.6 to draw up an initial plan for the PR when I started it. The code was partly written by me and partly by Claude Code, especially for the test plumbing that I felt lazy to write myself. I authored the docs and used the model to review the additions.

@henryiii

Copy link
Copy Markdown
Collaborator

What is the difference to just using session.run("uv", "run", ...)? We don't have any other command that are uv-specific, normally they work in all backends.

@agriyakhetarpal

Copy link
Copy Markdown
Contributor Author

Feedback on the design welcome! The conda test failures are unrelated; I'm investigating them.

@agriyakhetarpal

agriyakhetarpal commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

What is the difference to just using session.run("uv", "run", ...)? We don't have any other command that are uv-specific, normally they work in all backends.

@henryiii I'd say that it's just nicer. We sidestep the fact that we could be using the wrong/different uv binary on PATH, and this should always use the correct one. That said, I'm open to the view that this is too uv-specific for a core session method and session.run(nox.virtualenv.UV, "run", <...>) would work fine for me, but that PEP 723 scripts with uv-specific declarative metadata in them can use nox's uv integration feels a bit more ergonomic.

@henryiii

Copy link
Copy Markdown
Collaborator

We already have special handling to ensure "uv" is always correct, IIRC. Though I think it only kicks in for uv-based sessions; what you really want here is an "none" session but uv support.

@henryiii

Copy link
Copy Markdown
Collaborator

Or a generic .run_script that doesn't install, and has a fallback if uv isn't present.

@agriyakhetarpal

Copy link
Copy Markdown
Contributor Author

Hmm, I think we could. Do you mean something like:

def run_script(self, script, *args, uv_args=(), ...):
    if nox.virtualenv.HAS_UV:
        # uv owns the environment
        return self.run(nox.virtualenv.UV, "run", *uv_args, script, *args, external=True, ...)
    else:
        # fallback: install deps into session venv, run with python
        if uv_args:
            msg = "uv_args requires uv to be installed."
            raise ValueError(msg)
        deps = (nox.project.load_toml(script) or {}).get("dependencies", [])
        self.install(*deps)
        return self.run("python", script, *args, ...)

I considered that at first, but I didn't do it because it felt a bit odd, and uv_run_script made it unambiguous that it's uv-specific.

Or do you think it's better to close this PR? Thanks!

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants