Skip to content
OorteoPublic

About

A smart CLI wrapper for Astral's uv run that automatically detects project contexts. Enables clean shebangs and location-independent script execution without manually passing the --project flag.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Latest commit

 

History

65 Commits

Folders and files

Repository files navigation

Streamlined Script Execution with uvr

uv is a blazing fast, modern Python package manager and workflow tool. However, its project-centric design (uv run) prioritizes the current working directory (CWD) when looking for virtual environments and pyproject.toml files. This makes it cumbersome to execute a project-dependent script from outside its root directory, as it forces you to manually pass the --project flag with the absolute path to the script's home.

uvr (uv-runner) acts as an intelligent wrapper that resolves this pain point. It automatically detects the correct project context relative to the script being executed, allowing you to use a clean shebang (#!/usr/bin/env uvr) or call:

uvr [options] script.py

instead of:

uv run --project /path/to/script/project [options] /path/to/script/project/script.py

Key Value: It restores the true portability of standalone and project-tied Python scripts without polluting your command line or breaking your workflow when moving between directories. It also supports an optional offline mode that runs scripts directly against a project .venv without invoking uv run.

Installation

Prerequisite: uv must be installed and available on your PATH.

To install uvr, use the following command:

uv tool install uvr

To upgrade uvr, use the following command:

uv tool upgrade uvr

Windows Console Modes

Two entry points are installed:

  • uvr — console application. Use from a terminal or for scripts that need a command-line window.
  • uvr-gui — GUI application. Use for scripts started by double-click or for GUI-only programs that must not open a console window.

On Linux and macOS both commands behave the same.

Usage

Several ways to run your Python scripts with uv:

  1. Using uv run --project <project_path> <script_path>:

    • This command explicitly tells uv to run the specified Python script within the context of the project located at <project_path>.

    • This is useful when your script relies on dependencies defined within a specific project directory but is executed from elsewhere.

    • Example:

      uv run --project /path/to/project [options] /path/to/project/script.py [script_options]
  2. Using uvr script.py:

    • This is a more direct way to execute your Python script (script.py) using uvr.

    • uvr automatically determines the project directory based on the script path, effectively mimicking the --project flag's behavior.

    • Example:

      uvr [options] [--] script.py [script_options]
    • For ambiguity and edge cases, use -- (see the section General Rule for Using the -- Separator).

  3. Shebang Usage:

    • Example:

      #!/usr/bin/env -S uvr [options] [--]
      # Your Python code here...
    • Note on -S flag: The -S flag allows passing multiple arguments to the interpreter. It is optional if your env implementation supports it (most modern systems do). However:

      • Without -S: You can only use #!/usr/bin/env uvr without additional options or parameters
      • With -S: You can pass options like #!/usr/bin/env -S uvr --with dep1 --
      • Some older or minimal Unix-like systems may not support the -S flag in env
    • If you pass script arguments, use -- to separate uvr/uv options from script arguments.

  4. Scripts without .py or .pyw extension:

    • Automatic --script option is added if not already present (--script or --gui-script) in options.

    • Without this, uv can in some cases mis-handle execution flow.

    • Example: For a foo script:

      #!/usr/bin/env -S uvr [options] [--]
      # Your Python code here...

      This will be executed as uv run [options] --script ... if [options] do not already contain --script or --gui-script.

    • Or, to be more explicit, you can include the --script flag directly in the shebang:

      #!/usr/bin/env -S uvr --script
    • Important Exception for Non-Files: If the identified script_path (the argument immediately following options or --) does not point to an actual file on disk, uvr will not automatically add the --script or --gui-script option. This behavior ensures uvr can correctly pass through commands that are executables within the virtual environment (e.g., uvr black ., uvr pytest), rather than a Python script file.

  5. Debug usage:

    • Example:
      uvr -v [options] [--] script.py [script_options]
      uvr -vv [options] [--] script.py [script_options]
  6. Offline mode:

    • When UV_OFFLINE=1 is set or --offline is passed among the uvr/uv pre-options and a project .venv is found, uvr runs the script directly with the .venv Python interpreter instead of invoking uv run.
    • This is useful when you are disconnected from the network or want to skip uv's dependency resolution and lockfile checks entirely.
    • uvr first checks the already-activated virtual environment (VIRTUAL_ENV), then walks upward from the script looking for a .venv directory. The walk stops at the first project root marker (pyproject.toml or uv.lock) so it never escapes the project.
    • Examples:
      UV_OFFLINE=1 uvr script.py
      uvr --offline script.py
      uvr --offline -- script.py --some-script-arg
    • If no .venv is found, uvr falls back to the normal uv run path, even in offline mode.

General Rule for Using the -- Separator

The -- argument functions as a standard command-line delimiter. It explicitly separates options intended for uvr (and its underlying uv process) from arguments specifically designated for the Python script being executed.

Arguments appearing before the -- are processed by uvr (uv). Arguments appearing after the -- are passed directly to the invoked Python script.

This explicit separation is crucial for:

  • Preventing Ambiguity: uvr employs a basic heuristic to identify the script path (the first non-hyphenated argument). This can lead to misinterpretation if the script itself accepts options that resemble uvr/uv arguments.

  • Ensuring Precise Argument Passing: By using --, users guarantee that all subsequent arguments are correctly delivered to their script, bypassing uvr's argument parsing logic.

Recommendation: Utilize the -- separator whenever precise control over argument distribution between uvr/uv and the target script is required.

Ctrl+C (SIGINT) Handling

uvr handles KeyboardInterrupt to provide clean CLI behavior when interrupted with Ctrl+C.

  • It suppresses Python traceback noise (unwanted junk output) on user interruption.
  • It exits with status code 130, following the common Unix convention: 128 + 2 (SIGINT is signal number 2).
  • This keeps output clean while still signaling to the parent shell/process that execution was interrupted.

Platform note:

  • On Linux and macOS, 130 matches the common signal-derived convention (128 + SIGINT 2).
  • On Windows, 130 is used intentionally as a consistent, cross-platform interruption code for uvr.

Security Notes

uvr is a convenience wrapper around uv run. It does not add privileges by itself, but it will execute the script/command you pass to it.

Main risks:

  • Running untrusted scripts can execute arbitrary code.
  • Untrusted dependency sources can introduce supply-chain risk.
  • Running as root/Administrator increases impact if something goes wrong.
  • A compromised PATH could resolve a malicious uv binary.

Recommended protections:

  • Run only trusted scripts and trusted dependency sources.
  • Do not run uvr as root/Administrator unless strictly required.
  • In CI, pin dependencies and use a lockfile where possible.
  • Prefer explicit script paths for automation (script.py) over ambiguous invocations.
  • Keep build/runtime environments isolated (virtual environments, containers, CI runners).
  • Ensure your PATH resolves to the expected uv executable.

Scope note:

  • uvr is not a sandbox. It is a command runner helper and should be used with standard secure development practices.

About

A smart CLI wrapper for Astral's uv run that automatically detects project contexts. Enables clean shebangs and location-independent script execution without manually passing the --project flag.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages