Skip to content

Commit 320be30

Browse files
committed
Respect markers on them
1 parent 09cc286 commit 320be30

File tree

11 files changed

+515
-42
lines changed

11 files changed

+515
-42
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pep508-rs/src/marker/tree.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ use std::ops::{Bound, Deref};
55
use std::str::FromStr;
66

77
use itertools::Itertools;
8+
use pep440_rs::{Version, VersionParseError, VersionSpecifier};
89
use pubgrub::Range;
910
#[cfg(feature = "pyo3")]
1011
use pyo3::{basic::CompareOp, pyclass, pymethods};
1112
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
12-
13-
use pep440_rs::{Version, VersionParseError, VersionSpecifier};
1413
use uv_normalize::ExtraName;
1514

1615
use crate::cursor::Cursor;
@@ -1631,6 +1630,20 @@ impl Serialize for MarkerTreeContents {
16311630
}
16321631
}
16331632

1633+
impl<'de> serde::Deserialize<'de> for MarkerTreeContents {
1634+
fn deserialize<D>(deserializer: D) -> Result<MarkerTreeContents, D::Error>
1635+
where
1636+
D: Deserializer<'de>,
1637+
{
1638+
let s = String::deserialize(deserializer)?;
1639+
let marker = MarkerTree::from_str(&s).map_err(de::Error::custom)?;
1640+
let marker = marker
1641+
.contents()
1642+
.ok_or_else(|| de::Error::custom("expected at least one marker expression"))?;
1643+
Ok(marker)
1644+
}
1645+
}
1646+
16341647
impl Display for MarkerTreeContents {
16351648
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
16361649
// Normalize all `false` expressions to the same trivially false expression.
@@ -1667,6 +1680,28 @@ impl Display for MarkerTreeContents {
16671680
}
16681681
}
16691682

1683+
#[cfg(feature = "schemars")]
1684+
impl schemars::JsonSchema for MarkerTreeContents {
1685+
fn schema_name() -> String {
1686+
"MarkerTreeContents".to_string()
1687+
}
1688+
1689+
fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1690+
schemars::schema::SchemaObject {
1691+
instance_type: Some(schemars::schema::InstanceType::String.into()),
1692+
metadata: Some(Box::new(schemars::schema::Metadata {
1693+
description: Some(
1694+
"A PEP 508-compliant marker expression, e.g., `sys_platform == 'Darwin'`"
1695+
.to_string(),
1696+
),
1697+
..schemars::schema::Metadata::default()
1698+
})),
1699+
..schemars::schema::SchemaObject::default()
1700+
}
1701+
.into()
1702+
}
1703+
}
1704+
16701705
#[cfg(test)]
16711706
mod test {
16721707
use std::ops::Bound;

crates/uv-distribution/src/metadata/lowering.rs

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use url::Url;
77

88
use distribution_filename::DistExtension;
99
use pep440_rs::VersionSpecifiers;
10-
use pep508_rs::{VerbatimUrl, VersionOrUrl};
10+
use pep508_rs::{MarkerTree, VerbatimUrl, VersionOrUrl};
1111
use pypi_types::{ParsedUrlError, Requirement, RequirementSource, VerbatimParsedUrl};
1212
use uv_git::GitReference;
1313
use uv_normalize::PackageName;
@@ -48,8 +48,8 @@ impl LoweredRequirement {
4848
// We require that when you use a package that's part of the workspace, ...
4949
!workspace.packages().contains_key(&requirement.name)
5050
// ... it must be declared as a workspace dependency (`workspace = true`), ...
51-
|| source.as_ref().is_some_and(|source| source.inner().iter().all(|source| {
52-
matches!(source, Source::Workspace { workspace: true })
51+
|| source.as_ref().is_some_and(|source| source.iter().all(|source| {
52+
matches!(source, Source::Workspace { workspace: true, .. })
5353
}))
5454
// ... except for recursive self-inclusion (extras that activate other extras), e.g.
5555
// `framework[machine_learning]` depends on `framework[cuda]`.
@@ -75,41 +75,62 @@ impl LoweredRequirement {
7575
return Either::Left(std::iter::once(Ok(Self(Requirement::from(requirement)))));
7676
};
7777

78-
Either::Right(source.into_inner().into_iter().map(move |source| {
79-
let source = match source {
78+
Either::Right(source.into_iter().map(move |source| {
79+
let (source, mut marker) = match source {
8080
Source::Git {
8181
git,
8282
subdirectory,
8383
rev,
8484
tag,
8585
branch,
86+
marker,
8687
} => {
8788
if matches!(requirement.version_or_url, Some(VersionOrUrl::Url(_))) {
8889
return Err(LoweringError::ConflictingUrls);
8990
}
90-
git_source(&git, subdirectory.map(PathBuf::from), rev, tag, branch)?
91+
let source =
92+
git_source(&git, subdirectory.map(PathBuf::from), rev, tag, branch)?;
93+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
94+
(source, marker)
9195
}
92-
Source::Url { url, subdirectory } => {
96+
Source::Url {
97+
url,
98+
subdirectory,
99+
marker,
100+
} => {
93101
if matches!(requirement.version_or_url, Some(VersionOrUrl::Url(_))) {
94102
return Err(LoweringError::ConflictingUrls);
95103
}
96-
url_source(url, subdirectory.map(PathBuf::from))?
104+
let source = url_source(url, subdirectory.map(PathBuf::from))?;
105+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
106+
(source, marker)
97107
}
98-
Source::Path { path, editable } => {
108+
Source::Path {
109+
path,
110+
editable,
111+
marker,
112+
} => {
99113
if matches!(requirement.version_or_url, Some(VersionOrUrl::Url(_))) {
100114
return Err(LoweringError::ConflictingUrls);
101115
}
102-
path_source(
116+
let source = path_source(
103117
PathBuf::from(path),
104118
origin,
105119
project_dir,
106120
workspace.install_path(),
107121
editable.unwrap_or(false),
108-
)?
122+
)?;
123+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
124+
(source, marker)
125+
}
126+
Source::Registry { index, marker } => {
127+
let source = registry_source(&requirement, index)?;
128+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
129+
(source, marker)
109130
}
110-
Source::Registry { index } => registry_source(&requirement, index)?,
111131
Source::Workspace {
112132
workspace: is_workspace,
133+
marker,
113134
} => {
114135
if !is_workspace {
115136
return Err(LoweringError::WorkspaceFalse);
@@ -148,7 +169,7 @@ impl LoweredRequirement {
148169
))
149170
})?;
150171

151-
if member.pyproject_toml().is_package() {
172+
let source = if member.pyproject_toml().is_package() {
152173
RequirementSource::Directory {
153174
install_path,
154175
url,
@@ -162,17 +183,22 @@ impl LoweredRequirement {
162183
editable: false,
163184
r#virtual: true,
164185
}
165-
}
186+
};
187+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
188+
(source, marker)
166189
}
167190
Source::CatchAll { .. } => {
168191
// Emit a dedicated error message, which is an improvement over Serde's default error.
169192
return Err(LoweringError::InvalidEntry);
170193
}
171194
};
195+
196+
marker.and(requirement.marker.clone());
197+
172198
Ok(Self(Requirement {
173199
name: requirement.name.clone(),
174200
extras: requirement.extras.clone(),
175-
marker: requirement.marker.clone(),
201+
marker,
176202
source,
177203
origin: requirement.origin.clone(),
178204
}))
@@ -192,39 +218,59 @@ impl LoweredRequirement {
192218
return Either::Left(std::iter::once(Ok(Self(Requirement::from(requirement)))));
193219
};
194220

195-
Either::Right(source.into_inner().into_iter().map(move |source| {
196-
let source = match source {
221+
Either::Right(source.into_iter().map(move |source| {
222+
let (source, mut marker) = match source {
197223
Source::Git {
198224
git,
199225
subdirectory,
200226
rev,
201227
tag,
202228
branch,
229+
marker,
203230
} => {
204231
if matches!(requirement.version_or_url, Some(VersionOrUrl::Url(_))) {
205232
return Err(LoweringError::ConflictingUrls);
206233
}
207-
git_source(&git, subdirectory.map(PathBuf::from), rev, tag, branch)?
234+
let source =
235+
git_source(&git, subdirectory.map(PathBuf::from), rev, tag, branch)?;
236+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
237+
(source, marker)
208238
}
209-
Source::Url { url, subdirectory } => {
239+
Source::Url {
240+
url,
241+
subdirectory,
242+
marker,
243+
} => {
210244
if matches!(requirement.version_or_url, Some(VersionOrUrl::Url(_))) {
211245
return Err(LoweringError::ConflictingUrls);
212246
}
213-
url_source(url, subdirectory.map(PathBuf::from))?
247+
let source = url_source(url, subdirectory.map(PathBuf::from))?;
248+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
249+
(source, marker)
214250
}
215-
Source::Path { path, editable } => {
251+
Source::Path {
252+
path,
253+
editable,
254+
marker,
255+
} => {
216256
if matches!(requirement.version_or_url, Some(VersionOrUrl::Url(_))) {
217257
return Err(LoweringError::ConflictingUrls);
218258
}
219-
path_source(
259+
let source = path_source(
220260
PathBuf::from(path),
221261
Origin::Project,
222262
dir,
223263
dir,
224264
editable.unwrap_or(false),
225-
)?
265+
)?;
266+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
267+
(source, marker)
268+
}
269+
Source::Registry { index, marker } => {
270+
let source = registry_source(&requirement, index)?;
271+
let marker = marker.map(MarkerTree::from).unwrap_or_default();
272+
(source, marker)
226273
}
227-
Source::Registry { index } => registry_source(&requirement, index)?,
228274
Source::Workspace { .. } => {
229275
return Err(LoweringError::WorkspaceMember);
230276
}
@@ -235,10 +281,12 @@ impl LoweredRequirement {
235281
}
236282
};
237283

284+
marker.and(requirement.marker.clone());
285+
238286
Ok(Self(Requirement {
239287
name: requirement.name.clone(),
240288
extras: requirement.extras.clone(),
241-
marker: requirement.marker.clone(),
289+
marker,
242290
source,
243291
origin: requirement.origin.clone(),
244292
}))

crates/uv-workspace/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ uv-options-metadata = { workspace = true }
2626
either = { workspace = true }
2727
fs-err = { workspace = true }
2828
glob = { workspace = true }
29+
itertools = { workspace = true }
30+
owo-colors = { workspace = true }
2931
rustc-hash = { workspace = true }
3032
same-file = { workspace = true }
3133
schemars = { workspace = true, optional = true }
@@ -36,7 +38,6 @@ toml = { workspace = true }
3638
toml_edit = { workspace = true }
3739
tracing = { workspace = true }
3840
url = { workspace = true }
39-
itertools = { workspace = true }
4041

4142
[dev-dependencies]
4243
anyhow = { workspace = true }

0 commit comments

Comments
 (0)