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