A utility that transforms single-file PEP723-style Python scripts into installable packages using uv tool install, making them available as command-line tools.
uvs bridges the gap between single-file Python scripts and the standard Python packaging ecosystem. It allows you to:
- Convert self-contained single-file scripts into proper Python packages
- Install them as command-line tools using
uv tool install - Maintain a registry linking installed tools back to their source files
- Update installed tools when their source changes
This is particularly useful for developers who prefer the simplicity of single-file scripts but want the convenience of standard tool installation and management.
While uv provides excellent tool management for traditional Python packages, it doesn't directly support installing single-file scripts as tools. The naive approach of uv tool install --script foobar.py doesn't work because uv expects a proper package structure.
uvs solves this by automatically generating the necessary package structure from a single-file script and then using uv tool install to install it.
- uv installed and available in your PATH
Install uvs as a command-line tool:
uv tool install https://github.com/your-repo/uvs.gitNow you can use uvs directly:
uvs --helpFor contributors or those who want to modify uvs:
# Clone this repository
git clone https://github.com/your-repo/uvs.git
cd uvs
# Run the installer directly
uv run scripts/uvs.py --help-
Create a single-file script with PEP 723 inline metadata (see
uvs-example.pyfor an example). -
Install it as a command-line tool:
uvs your-script.py- Use your new command:
your-script- Find the source of an installed tool:
uvs --which your-scriptuvs converts single-file Python scripts into installable packages:
- Parse PEP 723 metadata from the script header
- Extract script body (removing header and
if __name__ == "__main__"block) - Generate package structure with
pyproject.tomlandsrc/<module>/__init__.py - Run
uv tool installon the generated package - Track installations in a local registry file
Installations are tracked in a platform-specific registry file (~/.config/uvs/registry.json on Linux, ~/Library/Application Support/uvs/registry.json on macOS, and %APPDATA%/uvs/registry.json on Windows) with tool names, source paths, hashes, and versions for reliable updates and management.
uvs reads PEP 723 inline script metadata to extract dependency and Python version requirements. The tool supports the standard requires-python and dependencies fields. If no metadata is present, sensible defaults are used.
Generated packages follow this structure:
my-tool/
├── pyproject.toml # Project metadata and dependencies
├── README.md # Installation info
└── src/
└── my_tool/
└── __init__.py # Script body as module
uvs [OPTIONS] <script-or-dir>--dry-run: Generate the package but don't install it--editable: Attempt an editable install (limited functionality)--all: Install all.pyfiles in a directory--list: List all registered scripts--which <tool>: Show source path for an installed tool--update: Update an installed tool if the source changed--name <name>: Override the derived tool name--version <version>: Set the initial package version--tempdir <path>: Specify where to generate the package--python <specifier>: Select Python version for installation
# Dry run to inspect generated package
uvs install --dry-run example.py
# Install with custom name
uvs install --name my-tool example.py
# Update an existing installation
uvs update example.py
# Install all scripts in a directory
uvs install --all ./scripts/
# List all installed scripts
uvs list
# Uninstall a specific tool
uvs uninstall my-tool
# Uninstall all tools
uvs uninstall --all
# Preview what would be uninstalled
uvs uninstall --dry-run my-tooluvs provides a comprehensive uninstall command that works with both the uvs registry and uv's tool management system.
uvs uninstall [OPTIONS] TOOL_NAME
uvs uninstall --all [OPTIONS]--all: Uninstall all installed tools--dry-run: Show what would be uninstalled without actually uninstalling--backup/--no-backup: Create a backup of the registry before uninstalling (default: --backup)--force: Force uninstall without confirmation prompts
The uninstall process involves several steps:
- Registry Lookup:
uvschecks its registry to find the tool - Backup Creation: Optionally creates a backup of the registry
- UV Uninstall: Calls
uv tool uninstallto remove the tool from uv's environment - Verification: Confirms the tool is no longer available
- Registry Cleanup: Removes the tool entry from uvs registry
uvs maintains a registry of all installed tools in a platform-specific location:
- Linux:
~/.config/uvs/registry.json - macOS:
~/Library/Application Support/uvs/registry.json - Windows:
%APPDATA%/uvs/registry.json
When uninstalling, uvs:
- Removes the tool from uv's environment using
uv tool uninstall - Cleans up the registry entry
- Optionally creates a backup of the registry before making changes
# Uninstall a specific tool
uvs uninstall my-tool
# Uninstall all tools with confirmation
uvs uninstall --all
# Uninstall without confirmation prompts
uvs uninstall --force my-tool
# Preview what would be uninstalled
uvs uninstall --dry-run my-tool
# Uninstall all tools without creating a registry backup
uvs uninstall --all --no-backupThe uninstall command handles various error scenarios:
- Tool not found in registry: Shows an error message with available tools
- UV uninstall failure: Attempts to clean up registry entries if the tool is already gone
- Permission issues: Provides guidance on fixing access problems
- Registry corruption: Creates backups and attempts recovery
uvs uninstall works in conjunction with uv tool uninstall:
uvsmanages the registry tracking tool originsuvhandles the actual tool removal from the environmentuvsverifies the removal and cleans up its registry
This dual approach ensures tools are completely removed from both the uv environment and uvs tracking system.
Packages are generated in temporary directories by default to keep your original scripts as the single source of truth and avoid cluttering your project.
The registry.json file is stored in the standard platform-specific configuration directory (~/.config/uvs/ on Linux, ~/Library/Application Support/uvs/ on macOS, and %APPDATA%/uvs/ on Windows), making it user-global rather than project-specific and allowing tools to be managed across all projects.
Editable installs have significant limitations - changes to source scripts aren't automatically reflected, and updates require manual reinstallation. Use --update instead for iterative development.
-
"Script not found"
- Check that the script path is correct
- Use absolute paths if running from a different directory
-
"uv tool install failed"
- Ensure
uvis installed and in your PATH - Check that the script has a proper
main()function - Verify the
requires-pythonspecification matches your environment
- Ensure
-
"Permission denied"
- Check write permissions for the user config directory (platform-specific:
~/.config/uvs/on Linux,~/Library/Application Support/uvs/on macOS,%APPDATA%/uvs/on Windows) - Use
--tempdirto specify a writable location for package generation
- Check write permissions for the user config directory (platform-specific:
-
"Module not found" after installation
- Ensure all dependencies are listed in the PEP723 header
- Check that the script exposes a
main()function
- Use
--dry-runto inspect generated packages without installing - Check the global registry file at the platform-specific location (
~/.config/uvs/registry.jsonon Linux,~/Library/Application Support/uvs/registry.jsonon macOS,%APPDATA%/uvs/registry.jsonon Windows) to see what's been installed - Use
uv tool listto see whatuvhas installed
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Update documentation as needed
- Submit a pull request
For contributors or those who want to modify uvs:
# Clone the Repository
git clone https://github.com/your-repo/uvs.git
# place uvs in PATH in editable mode
uv tool install --editable uvs
# verify available
uvs --help
cd uvs
# hack, hack, ...
# Run tests
uv run pytestuvs includes a comprehensive end-to-end test suite that focuses on user journeys and observable behavior rather than internal implementation details. This approach ensures reliability by testing complete workflows as users would experience them.
User Journeys & Observable Behavior:
- Complete installation workflows (single scripts, batch operations, custom names)
- Tool management (listing, showing details, finding sources)
- Update workflows (detecting changes, version bumping, registry updates)
- Error scenarios and edge cases (missing files, malformed scripts, security)
- Configuration management and persistence
- Unicode and large script handling
- Registry backup and recovery
What is Not Tested:
- Internal implementation details (parsing logic, package generation internals)
- Unit-level function behavior (except where it affects user experience)
- Performance micro-optimizations
# Run all tests
uv run pytest
# Run with duration reporting (shows slowest tests)
uv run pytest --durations=10
# Run specific test categories
uv run pytest tests/test_e2e.py -v # End-to-end tests
uv run pytest tests/test_cli.py -v # CLI component testsThe test suite has been optimized for speed and reliability:
- Fast Execution: Uses in-memory registries and mocked subprocess calls to avoid slow I/O operations
- Deterministic Results: Controlled test environments prevent flaky tests from external dependencies
- Comprehensive Coverage: Tests simulate real user workflows end-to-end while maintaining fast execution
- Reliable CI/CD: Tests run consistently across different environments without external dependencies
The current test suite achieves comprehensive coverage of user-facing functionality while maintaining execution times under 30 seconds for the full suite.
- uv: The Python package installer and resolver
- PEP 723: Inline script metadata
- pipx: Install and run Python applications in isolated environments
This project is licensed under the MIT License - see the LICENSE file for details.
- Installer script:
src/uvs/uvs.py - Example script:
uvs-example.py - Registry file: Platform-specific location (
~/.config/uvs/registry.jsonon Linux,~/Library/Application Support/uvs/registry.jsonon macOS,%APPDATA%/uvs/registry.jsonon Windows) - Detailed documentation:
README.md - Quick start guide:
QUICKSTART.md - Examples:
examples/