Practical UV
A VS Code extension for working with Python dependency files. Supports both uv / PEP 621 pyproject.toml and pip's requirements.txt. Provides TOML syntax highlighting, dependency version management via PyPI, known-vulnerability detection via the OSV advisory database, project version bumping, and a one-click move from pip to uv — which is also a command-line tool, @wizhut_tech/practical-uv, for any terminal.
Made by Wizhut.tech
Practical UV is built by Wizhut.tech: Mac apps, open-source developer tools and games, each one small and focused, plus Wizhut Research, where experiments are built as products you can use and their measurements are published beside them.
Apps
| Product |
What it does |
| EasyHomebrew |
Supply-chain hygiene for your Mac. Every installed Homebrew package is checked against a live CVE database, a menu-bar agent watches for new advisories, and a complete native package manager sits underneath. macOS 14+, €10 once. |
| Contain |
One window for the windows you already have open. Each one gets a tab, and letting it go puts it back at the exact position, size and screen it came from. macOS 13+, €6 once for three Macs, or on Setapp. |
| WizLook |
Quick Look previews for the files your Mac leaves blank: press Space in the Finder on an Excalidraw drawing, a Jupyter notebook, a canvas or a JSON file and see what is inside, or open it read-only in the app. macOS 14+, €6 once. |
Open source
| Project |
What it does |
| Practical UV |
This extension, and its pip → uv conversion as a CLI: @wizhut_tech/practical-uv. |
| Kyori |
String distance and similarity for JavaScript — the classic metrics, plus a ranking score built for autocomplete that folds case and accents and survives typos. @wizhut_tech/kyori |
| WizJS |
Everyday JavaScript utilities without becoming another lodash — Python's itertools, functools and collections, ported to JS with zero runtime dependencies. @wizhut_tech/wizjs |
| json2jsonl |
Turns one or many JSON files into a single JSON Lines output, so it pipes into whatever comes next. One static binary. |
| trimmer |
Strips the leading and trailing whitespace from whatever it reads — the whole input, or every line on its own. One static binary. |
Research
| Experiment |
What it asks |
| Kyori |
How well a string score alone can order an autocomplete list, measured on real searches against the libraries applications already use. |
| Promptivo |
Whether an AI prompt's quality can be measured without asking a model to judge it, so the same prompt always gets the same score. Free to use. |
Games
| Game |
What it is |
| Whokoban |
Sokoban for iPhone with one rule changed: filling every goal unlocks the exit, and Whoko still has to walk out through the warehouse he has just rearranged. |
| Showcase |
Every game you own on Steam, GOG, Epic Games, PlayStation, Xbox and Nintendo in one library on your Windows PC. Free. |
Features
🔍 Outdated Dependency Detection
Automatically checks your dependencies against PyPI and highlights outdated versions with inline diagnostics. Works in both pyproject.toml and requirements.txt.

🛡️ Security Advisories (opt-in)
Checks your declared dependencies against the OSV advisory database — the PyPA Advisory Database and GitHub Security Advisories — and reports known vulnerabilities as diagnostics, with the CVE, its severity, and the version that fixes it.
This is off by default. Enable uv.security.enabled to turn on background checking, or run UV: Check Dependencies for Security Advisories once from the command palette without changing the setting.
Findings appear in four places: as squiggles and Problems-panel entries (with a clickable link to the advisory on osv.dev), in the hover for the package, as a Upgrade … (fixes CVE-…) quick fix, and in a Security column in the dependency dashboard. When a package carries several advisories wanting different floors, the quick fix picks the highest version, so one bump clears them all.
Checking a single dependency
Press Cmd+. / Ctrl+. on any dependency and the code-action menu offers Check <package> for security advisories next to the usual version options — Re-check once results already exist. It checks that one package rather than the whole file, so it is available even while uv.security.enabled is off, and it leaves findings for the rest of the file untouched.
The result distinguishes clean from unverifiable. A dependency with no uv.lock entry and no == pin has no exact version to check against, so instead of reporting "no advisories" it tells you how many its declared range permits and points you at uv.security.includeRangeFindings.
How versions are resolved
An advisory applies to a concrete version, but a dependency is usually declared as a range. Two cases:
- Exact — the version comes from
uv.lock (if it sits next to your pyproject.toml) or from an == pin. The finding means you are affected.
- Range — no lockfile and no pin, so the check reports advisories your declared constraint merely permits. Accurate but noisy: an open constraint like
requests>=2.0 permits every advisory ever published for that package. These are hidden unless you set uv.security.includeRangeFindings.
Only your top-level declared dependencies are checked. uv.lock is read solely to pin those to exact versions — its transitive tree is never queried, so every finding is fixable by editing the file in front of you. The trade-off is that a vulnerability in a package you did not declare will not be reported.
Privacy
Enabling this sends the names and versions of your declared dependencies to api.osv.dev. Nothing else leaves your machine, and no request is made while the setting is off unless you run the command explicitly.
🐍 Pip / requirements.txt Support
The extension auto-detects pip-style files and applies the same outdated-detection, hover, code actions, and dashboard. Recognized files:
requirements.txt
requirements-*.txt and requirements_*.txt (e.g. requirements-dev.txt)
- Any
*.txt inside a requirements/ directory
Comments (#), blank lines, pip directives (-r, -e, -c, --index-url, …), direct URL specs (pkg @ https://…), and PEP 508 environment markers (; python_version >= "3.8") are handled correctly.
🚀 Convert pip Project to uv
When a requirements file is the active editor, a $(arrow-up) Convert to uv action appears in the status bar (and UV: Convert requirements.txt to uv project is available in the command palette). Nothing runs until you confirm, and the confirmation lists the exact commands.
They run in the integrated terminal, at the workspace folder root:
- If there is no
pyproject.toml yet: uv init --bare, which creates pyproject.toml and nothing else — no sample code, build backend, README.md, .python-version or git repository.
- Then
uv add -r <requirements file>, which imports the requirements into the project's dependencies, writes uv.lock and installs .venv.
Development requirements go in uv's dev group. When the file's name marks it as development requirements — requirements-dev.txt, requirements_test.txt, requirements/dev.txt, requirements/local.txt and the like (dev, test, lint, docs or local in the name) — the confirmation offers Dev Group first, which imports it with uv add --dev -r, and Main Dependencies as the alternative. A name that says neither, such as requirements-ml.txt, gets both choices with Main Dependencies first. requirements.txt itself, and runtime files such as requirements/base.txt, always go into the project's dependencies.
A development file that includes requirements.txt is split the right way. Most start with -r requirements.txt, and uv follows that line, so a dev-group import alone would copy every runtime package into the dev group too. Instead, Dev Group first imports the included file into the project's dependencies, then the development file into the dev group, then takes the included packages back out of it with uv remove --dev. Packages the development file lists itself stay in the dev group, so one click on requirements-dev.txt migrates both files.
Your requirements files are read, never changed; unsaved changes to the open one are saved first, so uv imports what you see. uv init --bare needs uv 0.5.29 or newer. uv sets requires-python from the Python it finds, and the Python version quick fix changes it.
From the command line
The same conversion is on npm as a standalone CLI, for projects you don't open in VS Code or for scripts:
npx @wizhut_tech/practical-uv convert requirements-dev.txt
It prints the same commands, asks once (--yes skips the question, --dry-run only prints), and runs uv in the current folder. See cli/README.md.
⚡ Quick Fix: Upgrade to Latest
Click the lightbulb (or press Cmd+. / Ctrl+.) on an outdated dependency to instantly upgrade it to the latest version. The same menu offers a per-dependency security check — see Security Advisories.
📋 Version Selection
Choose from all available versions on PyPI via a quick pick menu.
📦 Project Version Bumping (pyproject.toml only)
Place your cursor on the version = "x.y.z" line under [project] and bump the major, minor, or build version:
- Bump build —
0.1.0 → 0.1.1
- Bump minor —
0.1.0 → 0.2.0
- Bump major —
0.1.0 → 1.0.0

🐍 Python Version Selection (pyproject.toml only)
Place your cursor on the requires-python line to quickly switch Python versions. Quick-fix actions show the latest patch release of each major version from 3.10 onwards (e.g., 3.14.3, 3.13.12, …), fetched dynamically from the endoflife.date API. Choose "More Python versions…" to browse all versions from 3.1 onwards.
Hover over a package name in a dependency section to see its latest PyPI version with a link to the project page.
📊 Dependency Dashboard
Run UV: Show Dependencies from the command palette to open an interactive webview panel that lists all your dependencies with:
- Package name and current version
- Latest version from PyPI
- Security — the worst severity affecting the package plus each CVE and its fixing version, or ✅ when clean (shown when
uv.security.enabled is on)
- Status indicator — ✅ if up-to-date, or an Upgrade button to update outdated packages
🖥️ UV Commands
Run common uv commands directly from the command palette (Cmd+Shift+P):
| Command |
Description |
UV: Sync |
Run uv sync |
UV: Add |
Add a package via uv add |
UV: Run |
Run a command via uv run |
UV: Show Dependencies |
Open the dependency dashboard |
UV: Check Dependencies for Security Advisories |
Run a one-off OSV check on the active file, regardless of uv.security.enabled |
UV: Convert requirements.txt to uv project |
Run uv init --bare (if needed) and uv add -r <file>, or uv add --dev -r <file> for development requirements — only shown when a requirements file is active |
Settings
| Setting |
Default |
Description |
uv.security.enabled |
false |
Check declared dependencies against the OSV advisory database and report known vulnerabilities as diagnostics. Sends dependency names and versions to api.osv.dev. |
uv.security.includeRangeFindings |
false |
Also report advisories that a dependency's declared range permits but that its resolved version may not have. Requires uv.security.enabled. |
Supported Sources
In pyproject.toml, dependencies are parsed using a real TOML parser (@iarna/toml) — both inline (dependencies = ['x==1.0', ...]) and multi-line array styles, with single or double quotes, are handled identically. Recognized sections:
[project] → dependencies = [...]
[project.optional-dependencies] → dev = [...], etc.
[dependency-groups] → dev = [...], etc.
In requirements.txt (and the variants listed above), each line is parsed as a PEP 508 requirement.
Requirements
- VS Code
^1.125.0
- Internet access for PyPI lookups, and for
api.osv.dev if security checking is enabled
Development
# Install dependencies
npm install
# Compile
npm run compile
# Watch for changes
npm run watch
# Run unit tests (parser, requirements.txt, security audit, uv conversion)
npm test
# Build .vsix for both registries (output in dist/)
npm run package # vscode + openvsx
npm run package:vscode # VS Code Marketplace only
npm run package:openvsx # Open VSX only
The two registries require different (name, publisher) pairs. Edit build/targets.json to change them. The script overrides package.json in place during each build and restores it afterwards.
Press F5 to launch the Extension Development Host for testing.
Tests use the built-in node:test runner and live in src/test/.
License
MIT