In Python UV workspaces, there are three key concepts that got me confused at first:
- Members (
[tool.uv.workspace].members): local packages in the workspace (this means they share the lockfile). This is what adds a project to the workspace. - Dependencies (
[project].dependencies): package A declares it depends on package B (by name). - Sources (
[tool.uv.sources]): control where those names resolve from. UseB = { workspace = true }so A uses the local B (member), not PyPI.
Recommended flow
- Add each package to
workspace.members(root). - In package A, list B in
project.dependencies. - In the root (or in A), map
B = { workspace = true }.
Gotcha
- Without
sources, if B exists on PyPI, it will be installed from PyPI; if it does not, resolution fails.
Root as container
- Keep
dependencies = []if the root does not use anything itself.