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.pyinstead of:
uv run --project /path/to/script/project [options] /path/to/script/project/script.pyKey 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.
Prerequisite: uv must be installed and available on your PATH.
To install uvr, use the following command:
uv tool install uvror
uv tool install --from git+https://github.com/karnigen/uvr uvrTo upgrade uvr, use the following command:
uv tool upgrade uvrSeveral ways to run your Python scripts with uv:
-
Using
uv run --project <project_path> <script_path>:-
This command explicitly tells
uvto 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]
-
-
Using
uvr script.py:-
This is a more direct way to execute your Python script (
script.py) usinguvr. -
uvrautomatically determines the project directory based on the script path, effectively mimicking the--projectflag's behavior. -
Example:
uvr [options] [--] script.py [script_options]
-
For ambiguity and edge cases, use
--(see the section General Rule for Using the--Separator).
-
-
Shebang Usage:
-
Example:
#!/usr/bin/env -S uvr [options] [--] # Your Python code here...
-
Note on
-Sflag: The-Sflag allows passing multiple arguments to the interpreter. It is optional if yourenvimplementation supports it (most modern systems do). However:- Without
-S: You can only use#!/usr/bin/env uvrwithout 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
-Sflag inenv
- Without
-
If you pass script arguments, use
--to separateuvr/uvoptions from script arguments.
-
-
Scripts without
.pyor.pywextension:-
Automatic
--scriptoption is added if not already present (--scriptor--gui-script) in options. -
Without this,
uvcan in some cases mis-handle execution flow. -
Example: For a
fooscript:#!/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--scriptor--gui-script. -
Or, to be more explicit, you can include the
--scriptflag 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,uvrwill not automatically add the--scriptor--gui-scriptoption. This behavior ensuresuvrcan correctly pass through commands that are executables within the virtual environment (e.g.,uvr black .,uvr pytest), rather than a Python script file.
-
-
Debug usage:
- Example:
uvr -v [options] [--] script.py [script_options] uvr -vv [options] [--] script.py [script_options]
- Example:
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:
uvremploys 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 resembleuvr/uvarguments. -
Ensuring Precise Argument Passing: By using
--, users guarantee that all subsequent arguments are correctly delivered to their script, bypassinguvr'sargument parsing logic.
Recommendation: Utilize the -- separator whenever precise control over argument distribution between uvr/uv and the target script is required.
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(SIGINTis signal number2). - This keeps output clean while still signaling to the parent shell/process that execution was interrupted.
Platform note:
- On Linux and macOS,
130matches the common signal-derived convention (128 + SIGINT 2). - On Windows,
130is used intentionally as a consistent, cross-platform interruption code foruvr.
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
PATHcould resolve a maliciousuvbinary.
Recommended protections:
- Run only trusted scripts and trusted dependency sources.
- Do not run
uvras 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
PATHresolves to the expecteduvexecutable.
Scope note:
uvris not a sandbox. It is a command runner helper and should be used with standard secure development practices.