Skip to main content

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.

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]
      

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.

Metadata

Release files for uvr 0.1.38

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for uvr 0.1.38
File Size Uploaded
uvr-0.1.38.tar.gz 5.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for uvr 0.1.38
File Interpreter ABI Platform
uvr-0.1.38-py3-none-any.whl Python 3 none any Details

Total release size: 12.7 kB

Release files / uvr-0.1.38.tar.gz

Download URL uvr-0.1.38.tar.gz
Size 5.9 kB
Tags Source
SHA-256 checksum
How to use checksums
79ab9f4ea8693aed426898345192e08daf9a33fb7e4f5d3779a3f39e6bd2f6a6
BLAKE2b-256 checksum
How to use checksums
5bb4add4d508f592b2afc5cb3a58bfb887618624af90e0c6705d8d7514105967
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.24

Release files / uvr-0.1.38-py3-none-any.whl

Download URL uvr-0.1.38-py3-none-any.whl
Size 6.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0539caf81e09d3231d841d6b5fc2f1153fde61d47b615aac5bd2accba51cbb42
BLAKE2b-256 checksum
How to use checksums
78b6e185502d10da05c0c52641671830acc6ae232c474bb481271b1d9f590313
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.24

Release history Release notifications | RSS feed

0.1.40

2 release files

This release

0.1.38 This release

2 release files

0.1.28

2 release files

0.1.27

2 release files

0.1.26

2 release files

0.1.25

2 release files

0.1.23

2 release files

0.1.22

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page