Home | Blag Index


From: wayne+blog@waynewerner.com
To: github.com/centaurialpha
Cc: everyone.everywhere.all.at.once
Date: Sat, 09 Aug 2025 14:43:48 -0500
Subject: Editable dev Dependencies With uv

I had an issue with uv and was asked for a writeup on my workaround, so here we are.

The tl;dr just copy and paste this:

export UV_OFFLINE=1
export ROOT=/tmp/asdf
rm -rf $ROOT
mkdir -p $ROOT/together
cd $ROOT
uv init --package cool_library
uv init --package app_one
cd $ROOT/cool_library
cat <<EOF>src/cool_library/__main__.py
import cool_library
cool_library.main()
EOF
cat <<EOF>src/cool_library/__init__.py
import importlib.metadata

def main():
    print('Hello from cool-library - ' + importlib.metadata.version('cool_library'))
EOF
uv run -m cool_library
uv build
cd $ROOT/app_one
cat <<EOF>src/app_one/__main__.py
import app_one
app_one.main()
EOF
echo "    cool_library.main()" >> src/app_one/__init__.py
sed -i '1s/^/import cool_library\n/' src/app_one/__init__.py
uv add --dev --editable ../cool_library/
uv add cool-library==0.1.0
uv run -m app_one
uv build
cd ../cool_library
uv version --bump minor
uv build
cd ../app_one
uv run -m app_one
cd ../together
uv venv
source .venv/bin/activate
uv pip install --find-links ../app_one/dist --find-links ../cool_library/dist app_one
uv run -m app_one
deactivate
cd ../app_one
echo "Current: $PWD"
uv run -m app_one
cd ../together
echo "Current: $PWD"
uv run -m app_one

A lot of this is mostly noisy bits that have to do with setting up this example. In fact, what makes this work is hidden within the pyproject.toml. And requires a bit of a workaround. Of course I haven't even introduced what in the world is going on here and the problem is that we're trying to solve.

Say you're building an app that has a library that you're also developing, in tandem but not, strictly speaking, part of the same thing. Like maybe you have an API that you're building, and you're building a UI on top of that API. Well, your API might be built as one library that really anyone could use. There's no absolute requirement that you use your UI. So you release the API as one package, and then your UI with a dependency on the API. But if you're building functionality you're not going to want to have to cut a pre-release of your API with every change you make. That's rough.

With a normal dependency, you can tell uv that you want to install something as a dev dependency. Then it will only install it in a dev environment. So let's say that you want to run your tests with pytest but you're not ever going to run your tests in production so you have something like this:

+-- src
|   `-- my_api
|
`-- tests

Well, uv add --dev pytest will add pytest as a dev dependency. When you deploy your software, it won't be installed with pytest. You could do something similar with uv add --dev /some/path/to/utils. Which works great if you only want the dep in dev. But what if you're in our circumstance and you want an editable install in dev, but a regular dependency (pinned or not) in production?

Well, the above example will kind of get it done. It comes with some problems. Your uv.lock won't lock with the right version, and if you use uv sync then it will pick up the dev/editable install.

But as you can see, if you take care to ensure that your uv add version is pinned, and you install into a virtual env with your wheel instead of from the repos... you can work around it for now.

But you can follow https://github.com/astral-sh/uv/issues/7945 to keep track of when the functionality gets proper support within uv.

~wayne
^C


Home | Blag Index

This site is Copyleft Wayne Werner - BY-NC-SA 4.0