Repository navigation
Proposal: support uv as an optional backend for venv creation & installs #451
Description
Context
Relates to #423 (PEP 723 support).
uv has become the de-facto fast Python package/venv manager and overlaps heavily with what fades does. This issue does two things:
- Documents a feature-by-feature comparison of every fades command/feature against its
uvequivalent. - Proposes a concrete first step: use
uvas an optional backend (create the venv + install deps withuvinstead ofpip/venvwhenuvis available), keeping all the rest of fades' behaviour unchanged.
The comparison is meant to inform a future decision about fades' direction. For now the only proposed action is the optional-backend work below.
fades → uv feature comparison
Docs read: uv latest (scripts, run, CLI reference) and fades master README/CLI.
CLI options
| fades option | What it does | uv equivalent | Same? |
|---|---|---|---|
fades script.py |
Run script in managed venv | uv run script.py |
✅ |
#!/usr/bin/env fades |
Self-executing script | #!/usr/bin/env -S uv run --script |
✅ |
fades http://.../script.py |
Run script from pastebin/URL | uv run https://.../script.py |
✅ (fades also resolves pastebin/gist/linkode share pages) |
import x # fades |
Mark dep via import comment | ❌ none — uv uses PEP 723 or --with |
❌ fades-only |
| docstring deps | Deps in docstring after fades line |
❌ none | ❌ fades-only |
-d, --dependency |
Add dep on CLI (repeatable) | uv run --with PKG |
✅ |
-r, --requirement |
Install from requirements file(s) | uv run --with-requirements req.txt |
✅ |
-p, --python |
Pick interpreter | uv run --python 3.11 (also auto-downloads) |
✅ (uv superset) |
-i, --ipython |
Use IPython REPL | uv run --with ipython ipython |
|
-a, --autoimport |
Auto-import deps in REPL | ❌ none | ❌ fades-only |
| (no script) | Open REPL in the env | uv run python |
✅ |
--system-site-packages |
Venv sees system packages | uv venv --system-site-packages (create-time only) |
|
-x, --exec |
Run any installed executable in venv | uv run <exe> / uvx <exe> |
✅ |
-m, --module |
Run module | uv run -m module |
✅ |
--check-updates / -U |
Re-resolve to newest | uv run --refresh / --upgrade |
✅ |
--freeze FILE |
Dump pip freeze of env |
uv lock --script (.py.lock) / uv export |
|
--no-precheck-availability |
Skip PyPI existence check | n/a (uv resolves directly) | — |
--avoid-pip-upgrade |
Don't auto-upgrade pip | n/a (no pip) | — |
--pip-options |
Pass-through pip args | native flags only; no generic passthrough | |
--python-options |
Pass-through python args | uv run python <opts> |
✅ |
--virtualenv-options |
Pass-through virtualenv args | limited uv venv flags |
|
-v/--verbose, -q/--quiet |
Verbosity | uv -v / uv -q |
✅ |
-V, --version |
Version + system info | uv version |
✅ |
Repository / source support
| fades feature | uv equivalent | Same? |
|---|---|---|
pypi::pkg |
default PyPI | ✅ |
vcs::git+https://... |
--with "pkg @ git+https://..." |
✅ |
file:///local/project |
--with /local/path |
✅ |
| alternate index | uv run --index URL |
✅ |
Venv lifecycle / maintenance
| fades feature | uv equivalent | Same? |
|---|---|---|
--get-venv-dir / --where |
❌ envs live opaquely in uv cache | ❌ fades-only |
--rm UUID |
uv cache clean / prune (no per-UUID removal) |
|
--clean-unused-venvs=N |
uv cache prune (no day-based policy) |
|
| per-depset venv reuse | automatic (keyed on resolved depset) | ✅ |
Configuration
| fades feature | uv equivalent | Same? |
|---|---|---|
.ini at system/user/project, merged |
uv.toml / [tool.uv] + env vars, layered |
✅ (different format) |
| config-injected global deps into every env | ❌ none | ❌ fades-only |
Genuine fades-only features (uv can't replicate today)
# fadesimport-comment & docstring dependency marking (fades' signature feature).--autoimportinto the REPL.--where/--get-venv-dirand--rm UUID(per-venv management by UUID).--clean-unused-venvs=Nday-based GC.- Config-injected global dependencies.
How the comparison shifts once fades supports PEP 723 (#423)
Once #423 lands, fades will read # /// script ... /// blocks. This narrows the gap meaningfully:
- Interoperability: fades and uv (and pipx/pip-run) could run each other's scripts. The
# fadescomment convention stays as the fades-native way; PEP 723 becomes the portable way. - Dependency declaration moves from "fades-only" toward "✅ same standard" — the biggest semantic difference between the tools largely disappears.
- What remains distinctly fades: the
# fadescomment style,--autoimport, explicit per-UUID venv management (--where/--rm), day-based venv GC, and config-injected global deps.
So post-#423 the two tools converge on the input format but still differ on venv management philosophy (fades exposes/manages individual venvs by UUID; uv hides them in a cache).
Proposal: use uv as an optional backend
Add uv as an optional dependency. When uv is present on the system, fades uses it for the parts where it's strictly better; when it's absent, fades behaves exactly as today.
Concretely:
- Venv creation: use
uv venvinstead of thevenv/virtualenvpath. - Dependency installation: use
uv pip install(oruv add) instead ofpip. - Everything else stays fades: dependency parsing (
# fadescomments, docstring,-d/-r), venv indexing by UUID, reuse logic,--where/--rm/--clean-unused-venvs, config files, REPL/--autoimport, etc.
This gives fades users uv's speed and built-in Python provisioning without changing fades' UX or losing any of its unique features, and it's a low-risk, incremental step.
Open questions to resolve before implementing:
- Detection & opt-out: auto-detect
uvonPATH, with a config flag / env var to force on/off? - Does
uv's venv layout stay compatible with fades' UUID indexing and reuse-by-hash logic? - How to map
--pip-options/--virtualenv-optionsontouvinvocations. --freezesemantics when usinguv.
Scope of this issue
This issue is for documenting the comparison and discussing the optional-backend approach. No implementation is proposed here yet beyond the outline above — the broader question of fades' long-term direction vs. uv is intentionally left for a future decision.
Activity
facundobatista commentedon Jun 20, 2026
Great comparison and proposal, thanks!
I think we can totally have
uvas an optional backend. I just wouldn't switch touvby default if the binary is present.uvhas not the same behaviour thanpip, which will makefadesbehaviour to change (the final virtual environments content) only by the presence of an external process.I propose to have a envvar/option pair (
FADES_USE_UVand--use-uv) that enables the behaviour (and ifuvis not in the path is an error... we can have a--uv-pathto specify the location of an executable too).Taking that in consideration, some comments around the proposal and questions...
Yes, but only if
uvusage is explicitly indicated.Yes, but only if
uvusage is explicitly indicated. Note that in this case we should also skip the initial "package availability" step, which was created to fail early, anduvcovers that.Yes!
In my proposal it has to be explicitly indicated.
We wouldn't be using the "venvs directory management" from
uv, just create the venv where we say so (infadescurrent structure) and install packages there. We wouldn't even be using packages removal or updates.If
uvis indicated to use, and--pip-optionsor--virtualenv-optionsare indicated, it's an error. We should also add a--uv-optionsto customizeuvruns.Probably in this case we should produce
uv'slockfile, what do you think?gilgamezh commentedon Jun 20, 2026
I think you are right, it's also a nicer and a bit more conservative way to incorporate a new backend. If in 1 year we see this is always the default we change it. Also based on the news who knows what will happen with a project that was promised to be OSS forever.. so good to be conservative.
I'll make it optional
You mean never discover? or --uv-path should be optional?
Make the uv backend opt-in instead of the default
gilgamezh commentedon Jun 20, 2026
Updated #454 I left --uv-path optional, seems the simplest
facundobatista commentedon Jun 20, 2026
Yes,
--uv-pathis optional. If present, we use it, else we use"uv".gilgamezh commentedon Jun 21, 2026
Cool, this is all implemented in #454 now
Make the uv backend opt-in instead of the default
Make the uv backend opt-in instead of the default