astral-sh / uv

An extremely fast Python package and project manager, written in Rust.
https://docs.astral.sh/uv
Apache License 2.0
26.4k stars 767 forks source link

Challenging to get started with workspaces. #9062

Open chrisfougner opened 3 days ago

chrisfougner commented 3 days ago

This is probably a me thing, but I haven't had luck getting workspaces to work, and I've had a pretty detailed read through the documentation.

This is what I have

root/
├── pyproject.toml
├── lib/
│   ├── pyproject.toml
│   ├── __init__.py
│   └── xyz.py  
└── tests/
    ├── pyproject.toml
    └── test.py

The files look like this:

root/pyproject.toml

[project]
...

[tool.uv.workspace]
members = ["lib", "tests"]

root/lib/pyproject.toml

[project]
name = "lib"
...

root/tests/pyproject.toml

[project]
...
dependencies = ["lib"]

[tool.uv.sources]
lib = {workspace = true}

root/tests/test.py

from lib import xyz 
...

And this is what I get:

$ uv run tests/test.py 
Traceback (most recent call last):
  File ".../root/tests/test.py", line 1, in <module>
    from lib import xyz
ImportError: cannot import name 'xyz' from 'lib' (unknown location)
bluss commented 3 days ago

The lib project there has a layout where __init__.py and pyproject.toml are on the same level. While any layout could work, that's definitely not a recommended or regular setup for a package project. uv init --lib can create a template that demonstrates an 'expected' layout. In this workspace it would look like either root/lib/lib/__init__.py or root/lib/src/lib/__init__.py together with root/lib/pyproject.toml for the lib part.

Maybe there's more to say but I thought it might help to bring up at least this lib thing in some detail, and that could get you going in the right direction. (Summary: before lib will work for you in the workspace, it needs to work as a standalone project.)

(If you see that and feel you don't want that layout - then maybe workspace is not what you want? Maybe root is just one project with lib and tests, doesn't need to be a workspace?)

dylwil3 commented 3 days ago

I agree this is confusing!

I think you actually need both lib and tests to be packaged? At least, I wasn't able to get it to work without that. If that's true, probably this line of the documentation on workspaces should specify "packaged" application:

Every directory included by the members globs (and not excluded by the exclude globs) must contain a pyproject.toml file. However, workspace members can be either applications or libraries; both are supported in the workspace context.

Ideally the error message would help point the way a bit better here. In fact, the messages get more confusing if you make lib packaged but not tests - then I was getting a message telling me lib needed to be added as a workspace source... but it was!

Speaking of which, the line:

[tool.uv.sources]
lib = {workspace = true}

should probably go in root/pyproject.toml.

chrisfougner commented 3 days ago

Thanks for taking a look so quickly @bluss! I agree the structure isn't really ideal. Unfortunately I'm in the situation where there is an existing codebase I'm working with and want to keep refactors to a minimum.

I tried getting it to work with the path specifier as well: lib = {path = "../lib", editable = true}, but am getting the same error.

@dyllwil3: My understanding was that [tool.uv.sources] needs to be specified in each individual package. Is that not the case? Or is it only for workspace packages that they need to be specified at the root?

bluss commented 3 days ago

@chrisfougner is the lib project already working and building a wheel for itself correctly, in isolation? I want to underline this as a way to work with it.