-
Notifications
You must be signed in to change notification settings - Fork 624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow multiple source entries for each package in tool.uv.sources
#7745
base: main
Are you sure you want to change the base?
Conversation
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BurntSushi -- I'd love your eyes on this file in particular. Should I be enforcing these at deserialization time? I could easily enforce them when we actually use the lowered requirement. I'm not certain what's best.
@@ -427,6 +513,7 @@ pub enum Source { | |||
rev: Option<String>, | |||
tag: Option<String>, | |||
branch: Option<String>, | |||
marker: Option<MarkerTreeContents>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ibraheemdev -- Is it correct to use Option<MarkerTreeContents>
for this? It's a field that users can provide in TOML.
return Err(LoweringError::UndeclaredWorkspacePackage); | ||
return Either::Left(std::iter::once(Err( | ||
LoweringError::UndeclaredWorkspacePackage, | ||
))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this slightly awkward: we return an iterator, but if the "overall" requirement fails, we use once with an error. Perhaps the return type should more truthfully be: Result<impl Iterator<Item = Result<LoweredRequirement, LoweringError>>, LoweringError>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We lower only for workspace packages, there are few items and the iterator looks too complex for this use case, should we collect into a Result<Vec<LoweredRequirement>, LoweringError>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose that's true -- this does only apply to workspace packages. I'd like @BurntSushi opinion on it too.
marker, | ||
source, | ||
origin: requirement.origin.clone(), | ||
})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is mostly just the code being indented and put under an iterator. Very minimal changes.
8a8b588
to
312a2eb
Compare
.ok_or_else(|| de::Error::custom("expected at least one marker expression"))?; | ||
Ok(marker) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\cc @ibraheemdev -- Does this make sense for a user-provided marker field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I'm not sure if this (and Option<MarkerTreeContents>
) works. If the user wrote x or not x
, we simplify to MarkerTree::TRUE
, so this deserialize would fail? I don't think serde falls back to None
in that case without serde(default).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you suggest? Just use String
and parse these as needed?
"items": { | ||
"$ref": "#/definitions/Source" | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is wrong (it thinks it has to be a list).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks correct to and check-jsonschema does only complain about "tree" below:
[tool.uv.sources]
tqdm = { git = "https:/github.com/tqdm/tqdm" }
httpx = [
{ git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" },
{ git = "https://github.com/encode/httpx", tag = "0.24.1", marker = "sys_platform == 'linux'" },
]
foo = "tree"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I think I fixed it between the time I wrote this comment and your testing. Thanks so much for testing it.)
320be30
to
73703fc
Compare
httpx = [ | ||
{ git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" }, | ||
{ git = "https://github.com/encode/httpx", tag = "0.24.1", marker = "sys_platform == 'linux'" }, | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In these expressions, do we accept extras and support the following (assuming index api has landed)?
[project.optional-dependencies]
cu118 = []
cu121 = []
cu124 = []
[tool.uv.sources]
torch = [
{ index = "torch-cu118", marker = "extra == 'cu118'"},
{ index = "torch-cu124", marker = "extra == 'cu124'"},
# cu121 is on pypi
]
[[tool.uv.index]]
name = "torch-cu118"
url = "https://download.pytorch.org/whl/cu118"
[[tool.uv.index]]
name = "torch-cu124"
url = "https://download.pytorch.org/whl/cu124"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We definitely can't support the above since we don't support disjoint extras, and those markers are overlapping. I talk about this at length here: https://www.notion.so/astral-sh/PyTorch-10a48797e1ca803ea593c456e9bf23f8?pvs=4#10a48797e1ca80f4ab5af90ebcd77000.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to see if we already propagate extras here though. I.e., this should probably work, right?
[project.optional-dependencies]
cu118 = []
[tool.uv.sources]
torch = [
{ index = "torch-cu118", marker = "extra == 'cu118'"},
]
[[tool.uv.index]]
name = "torch-cu118"
url = "https://download.pytorch.org/whl/cu118"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think we need to support it once we support disjoint extras. It makes the mixed CPU/GPU stuff so much better.
"items": { | ||
"$ref": "#/definitions/Source" | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks correct to and check-jsonschema does only complain about "tree" below:
[tool.uv.sources]
tqdm = { git = "https:/github.com/tqdm/tqdm" }
httpx = [
{ git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" },
{ git = "https://github.com/encode/httpx", tag = "0.24.1", marker = "sys_platform == 'linux'" },
]
foo = "tree"
.map(move |requirement| match requirement { | ||
Ok(requirement) => Ok(requirement.into_inner()), | ||
Err(err) => Err(err), | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
}) | |
.map_ok(move |requirement| requirement.into_inner()) |
| ^ | ||
Source markers must be disjoint, but the following markers overlap: `python_full_version == '3.12.*' and sys_platform == 'win32'` and `sys_platform == 'win32'`. | ||
|
||
hint: replace `sys_platform == 'win32'` with `python_full_version != '3.12.*' and sys_platform == 'win32'`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
powerful
return Err(LoweringError::UndeclaredWorkspacePackage); | ||
return Either::Left(std::iter::once(Err( | ||
LoweringError::UndeclaredWorkspacePackage, | ||
))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We lower only for workspace packages, there are few items and the iterator looks too complex for this use case, should we collect into a Result<Vec<LoweredRequirement>, LoweringError>
?
73703fc
to
6026428
Compare
[package.optional-dependencies] | ||
cpu = [ | ||
{ name = "iniconfig" }, | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is wrong (it doesn't include iniconfig
outside of the optional dependencies, but it should). I think it's because the negation of extra == 'cpu'
is extra != 'cpu'
, but when we resolve, we assume all extras are enabled, so that's false? It's like I want the negation of extra == 'cpu'
to be, like, just omitting that marker. \cc @konstin
6026428
to
4b3f1e6
Compare
4b3f1e6
to
5488719
Compare
Summary
This PR enables users to provide multiple source entries in
tool.uv.sources
, e.g.:The implementation is relatively straightforward: when we lower the requirement, we now return an iterator rather than a single requirement. In other words, the above is transformed into two requirements:
We verify (at deserialization time) that the markers are non-overlapping.
Closes #3397.