uvs
You have a useful, self-contained Python script under source control. You want
to run it as a normal command from anywhere, without maintaining a package
project just to put it on PATH.
uvs fills that narrow gap. It turns one supported Python file into a small,
disposable package and asks uv to install it as
a persistent tool. It also remembers the source file so that a later
uvs update can install a new snapshot.
Project status:
uvs0.1 is experimental and seeking public validation. It works for the deliberately small contract below, but its usefulness beyond one person's workflow is still an open question. If you try it, please share whether it fits your work, including why it does not.
Is uvs a fit?
Choose uvs when:
- your tool is one self-contained, UTF-8 Python file with a synchronous,
top-level
main(); - you want an explicit installed snapshot, not a command that changes whenever its source file changes; and
- you already use
uvand want it to keep owning the tool environment and executable.
Do not choose uvs when:
- your code needs sibling modules, data files, or a project directory: package it as a normal Python project instead;
- you want to run directly from changing source:
uv run path/to/script.pyor a shell alias is a better fit; - you need an asynchronous, nested, or method-based entry point; or
- you want a replacement for
uv toolor a way to publish packages.
Try it, then remove the installed state
Requirements are Python 3.10 or newer and uv available on PATH. Install the
current 0.1 code from this repository:
uv tool install "git+https://github.com/maphew/uvs.git"
uvs --help
The distribution is named uvs-cli: the PyPI project
uvs is an unrelated tool. The installed
command is still uvs. Because uv gives each tool its own isolated
environment, the shared name inside the packages does not interfere with the
install above. Do not pip install both distributions into one environment.
If the shell cannot find uvs (or a tool installed later), run
uv tool update-shell and restart the shell. uv tool dir --bin prints the
executable directory if you prefer to add it to PATH yourself.
Save this as hello.py:
# /// script
# requires-python = ">=3.10"
# dependencies = []
# ///
def main() -> None:
print("Hello from uvs")
if __name__ == "__main__":
main()
Test the source, install it, and run the installed command:
uv run hello.py
uvs install hello.py
hello
Now edit hello.py so that its function prints different text:
def main() -> None:
print("Hello from a new snapshot")
Install and run the new snapshot:
uvs update hello.py
hello
The first command removes both the installed hello tool and its uvs
registry entry; the second removes uvs itself. Your source file remains
untouched:
uvs uninstall hello
uv tool uninstall uvs-cli
The test matrix covers Windows and Linux. macOS has not been verified.
Supported script contract
uvs supports one UTF-8 Python file at a time. The file must be valid Python
and define a synchronous main() function directly at module scope. An
async def main, a method, or a function nested inside another function is not
a supported entry point. A conventional if __name__ == "__main__": main()
guard is fine.
PEP 723 metadata is optional. When present, it may contain dependencies,
requires-python, and a tool table. Dependencies and the Python constraint
are copied into the generated package. Other top-level metadata fields are
rejected. The script, including its metadata comments, is copied verbatim into
the snapshot; uvs does not collect sibling modules, data files, or a project
directory.
The command name comes from the filename, with underscores changed to hyphens.
Use uvs install --name another-name hello.py to choose it explicitly.
Snapshots, updates, and ownership
The installed command is a snapshot. Editing the original .py file does not
change it. uvs update finds the registry entry by the source file's canonical
path and reinstalls the tool only when the source hash changed. The original
source path must still exist.
uvs install hello.py # create and install the first snapshot
uvs list # list entries tracked by uvs
uvs show hello # show source, version, hash, and install time
uvs update hello.py # reinstall if the source hash changed
uvs uninstall hello # remove the uv tool and uvs registry entry
Each changed update advances the generated package's PEP 440 version to the
next final release. Release tuples shorter than three components are padded
before their final component is incremented; epochs are preserved, while pre,
post, development, and local qualifiers are removed. For example, 1.2rc1
updates to 1.2.1, and 2!1.2.3.post1 updates to 2!1.2.4.
uv owns the installed tool environment and executable. uvs owns a small,
platform-specific registry.json containing the source path, source hash,
version, and install time for tools it installed. uvs list and uvs show
describe that registry, not every tool known to uv; use uv tool list for
the latter. Direct uv tool install operations do not appear in uvs list,
and removing a managed tool directly with uv can leave a stale uvs entry.
Prefer uvs uninstall for tools managed by uvs.
uvs show NAME --format simple emits five undecorated Label: value lines in
this fixed order: Name, Source, Version, Installed, and Hash. Unlike
the default Rich table, the simple format includes the complete source hash and
is stable for plain-text consumers.
The CLI exposes additional flags on some commands. They are not part of the
narrow contract documented here; consult uvs COMMAND --help for the current
interface.
Troubleshooting
uvis not found: install it using the official uv instructions and ensure it is onPATH.- An installed command is not found: run
uv tool update-shell, restart the shell, or useuv tool dir --binto find the directory to add toPATH. - The script is rejected: run
uv run path/to/script.py, check that it is UTF-8 and syntactically valid, and verify that it has a synchronous, top-leveldef main(...):. - PEP 723 metadata is rejected: use one closed
# /// scriptblock with valid TOML and only the supported top-level fields above. uvs updatecannot find the tool: pass the same source file used for installation. If it moved, uninstall by command name and install it again from the new path.uvs listanduv tool listdisagree: the former isuvsbookkeeping; the latter reports environments owned byuv. Reinstall withuvsor useuvs uninstallto reconcile a tracked tool.
Feedback and project policy
Success here means learning whether this small workflow is useful, and where it fails. Please use the focused form to share usefulness feedback or report a bug. Contributions are welcome; read CONTRIBUTING.md before starting. Report security concerns through SECURITY.md, not a public issue.
Project records: changelog, product contract, test inventory, and MIT license.
Development and tests
Create the locked development environment:
uv sync --dev --locked
Run the fast suite (the repository configuration excludes integration tests):
uv run pytest
Run only mocked subprocess workflow tests (these are component tests, not end-to-end tests):
uv run pytest -m mocked_workflow
Run the isolated lifecycle test against the real uv executable, serially:
uv run pytest -m integration -n 0
See examples/ for the minimal supported example.
Metadata
Release files for uvs-cli 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| uvs_cli-0.1.0.tar.gz | 18.8 kB | Without provenance | Details for uvs_cli-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| uvs_cli-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for uvs_cli-0.1.0-py3-none-any.whl |
Total release size: 39.4 kB
Release files / uvs_cli-0.1.0.tar.gz
| Download URL | uvs_cli-0.1.0.tar.gz |
|---|---|
| Size | 18.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac56449dc857852be81c0f2ac691dd48fbe1fe2d18fc1f1dac82a7c7fa47545a
|
|
BLAKE2b-256 checksum How to use checksums |
f16a676bd49c61c6020295c507c5a73a30114055f8f339745cac4b477dca0f2f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / uvs_cli-0.1.0-py3-none-any.whl
| Download URL | uvs_cli-0.1.0-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3b17280eaba642cf53e1e6273aee42cb5fff496e8d1f82e8b3e08aafa62151a1
|
|
BLAKE2b-256 checksum How to use checksums |
ec525e8e34591944a574fd787332a9b6c838237a89beebd6e9a29e32a08fc9b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for uvs-cli 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.