Skip to content

Commit dd760ee

Browse files
Normalize platform_system to sys_platform (#9949)
## Summary A revival of an old idea (#9344) that I have slightly more confidence in now. I abandoned this idea because (1) it couldn't capture that, e.g., `platform_system == 'Windows' and sys_platform == 'foo'` (or some other unknown value) are disjoint, and (2) I thought that Android returned `"android"` for one of `sys_platform` or `platform_system`, which would've made this logic incorrect. However, it looks like Android... doesn't do that? And the values here are almost always in a small, known set. So in the end, the tradeoffs here actually seem pretty good. Vis-a-vis our current solution, this can (e.g.) _simplify out_ expressions like `sys_platform == 'win32' or platform_system == 'Windows'`.
1 parent eb6bf8b commit dd760ee

16 files changed

+246
-271
lines changed

crates/uv-pep508/src/marker/algebra.rs

+101-117
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,49 @@ impl InternerGuard<'_> {
271271
key,
272272
operator,
273273
value,
274-
} => (
275-
Variable::String(key.into()),
276-
Edges::from_string(operator, value),
277-
),
274+
} => {
275+
// Normalize `platform_system` markers to `sys_platform` nodes.
276+
//
277+
// The `platform` module is "primarily intended for diagnostic information to be
278+
// read by humans."
279+
//
280+
// We only normalize when we can confidently guarantee that the values are
281+
// exactly equivalent. For example, we normalize `platform_system == 'Windows'`
282+
// to `sys_platform == 'win32'`, but we do not normalize `platform_system == 'FreeBSD'`
283+
// to `sys_platform == 'freebsd'`, since FreeBSD typically includes a major version
284+
// in its `sys.platform` output.
285+
//
286+
// For cases that aren't normalized, we do our best to encode known-incompatible
287+
// values in `exclusions`.
288+
//
289+
// See: https://discuss.python.org/t/clarify-usage-of-platform-system/70900
290+
let (key, value) = match (key, value.as_str()) {
291+
(MarkerValueString::PlatformSystem, "Windows") => {
292+
(CanonicalMarkerValueString::SysPlatform, "win32".to_string())
293+
}
294+
(MarkerValueString::PlatformSystem, "Darwin") => (
295+
CanonicalMarkerValueString::SysPlatform,
296+
"darwin".to_string(),
297+
),
298+
(MarkerValueString::PlatformSystem, "Linux") => {
299+
(CanonicalMarkerValueString::SysPlatform, "linux".to_string())
300+
}
301+
(MarkerValueString::PlatformSystem, "AIX") => {
302+
(CanonicalMarkerValueString::SysPlatform, "aix".to_string())
303+
}
304+
(MarkerValueString::PlatformSystem, "Emscripten") => (
305+
CanonicalMarkerValueString::SysPlatform,
306+
"emscripten".to_string(),
307+
),
308+
// See: https://peps.python.org/pep-0738/#sys
309+
(MarkerValueString::PlatformSystem, "Android") => (
310+
CanonicalMarkerValueString::SysPlatform,
311+
"android".to_string(),
312+
),
313+
_ => (key.into(), value),
314+
};
315+
(Variable::String(key), Edges::from_string(operator, value))
316+
}
278317
// A variable representing the existence or absence of a particular extra.
279318
MarkerExpression::Extra {
280319
name: MarkerValueExtra::Extra(extra),
@@ -821,86 +860,23 @@ impl InternerGuard<'_> {
821860
return exclusions;
822861
}
823862
let mut tree = NodeId::FALSE;
824-
for (a, b) in [
825-
// sys_platform == 'darwin' and platform_system == 'Windows'
826-
(
827-
MarkerExpression::String {
828-
key: MarkerValueString::SysPlatform,
829-
operator: MarkerOperator::Equal,
830-
value: "darwin".to_string(),
831-
},
832-
MarkerExpression::String {
833-
key: MarkerValueString::PlatformSystem,
834-
operator: MarkerOperator::Equal,
835-
value: "Windows".to_string(),
836-
},
837-
),
838-
// sys_platform == 'darwin' and platform_system == 'Linux'
839-
(
840-
MarkerExpression::String {
841-
key: MarkerValueString::SysPlatform,
842-
operator: MarkerOperator::Equal,
843-
value: "darwin".to_string(),
844-
},
845-
MarkerExpression::String {
846-
key: MarkerValueString::PlatformSystem,
847-
operator: MarkerOperator::Equal,
848-
value: "Linux".to_string(),
849-
},
850-
),
851-
// sys_platform == 'win32' and platform_system == 'Darwin'
852-
(
853-
MarkerExpression::String {
854-
key: MarkerValueString::SysPlatform,
855-
operator: MarkerOperator::Equal,
856-
value: "win32".to_string(),
857-
},
858-
MarkerExpression::String {
859-
key: MarkerValueString::PlatformSystem,
860-
operator: MarkerOperator::Equal,
861-
value: "Darwin".to_string(),
862-
},
863-
),
864-
// sys_platform == 'win32' and platform_system == 'Linux'
865-
(
866-
MarkerExpression::String {
867-
key: MarkerValueString::SysPlatform,
868-
operator: MarkerOperator::Equal,
869-
value: "win32".to_string(),
870-
},
871-
MarkerExpression::String {
872-
key: MarkerValueString::PlatformSystem,
873-
operator: MarkerOperator::Equal,
874-
value: "Linux".to_string(),
875-
},
876-
),
877-
// sys_platform == 'linux' and platform_system == 'Darwin'
863+
864+
// Pairs of `os_name` and `sys_platform` that are known to be incompatible.
865+
//
866+
// For example: `os_name == 'nt' and sys_platform == 'darwin'`
867+
let mut pairs = vec![
878868
(
879869
MarkerExpression::String {
880-
key: MarkerValueString::SysPlatform,
881-
operator: MarkerOperator::Equal,
882-
value: "linux".to_string(),
883-
},
884-
MarkerExpression::String {
885-
key: MarkerValueString::PlatformSystem,
870+
key: MarkerValueString::OsName,
886871
operator: MarkerOperator::Equal,
887-
value: "Darwin".to_string(),
872+
value: "nt".to_string(),
888873
},
889-
),
890-
// sys_platform == 'linux' and platform_system == 'Windows'
891-
(
892874
MarkerExpression::String {
893875
key: MarkerValueString::SysPlatform,
894876
operator: MarkerOperator::Equal,
895877
value: "linux".to_string(),
896878
},
897-
MarkerExpression::String {
898-
key: MarkerValueString::PlatformSystem,
899-
operator: MarkerOperator::Equal,
900-
value: "Windows".to_string(),
901-
},
902879
),
903-
// os_name == 'nt' and sys_platform == 'darwin'
904880
(
905881
MarkerExpression::String {
906882
key: MarkerValueString::OsName,
@@ -913,7 +889,6 @@ impl InternerGuard<'_> {
913889
value: "darwin".to_string(),
914890
},
915891
),
916-
// os_name == 'nt' and sys_platform == 'linux'
917892
(
918893
MarkerExpression::String {
919894
key: MarkerValueString::OsName,
@@ -923,10 +898,9 @@ impl InternerGuard<'_> {
923898
MarkerExpression::String {
924899
key: MarkerValueString::SysPlatform,
925900
operator: MarkerOperator::Equal,
926-
value: "linux".to_string(),
901+
value: "ios".to_string(),
927902
},
928903
),
929-
// os_name == 'posix' and sys_platform == 'win32'
930904
(
931905
MarkerExpression::String {
932906
key: MarkerValueString::OsName,
@@ -939,51 +913,61 @@ impl InternerGuard<'_> {
939913
value: "win32".to_string(),
940914
},
941915
),
942-
// os_name == 'nt' and platform_system == 'Darwin'
943-
(
944-
MarkerExpression::String {
945-
key: MarkerValueString::OsName,
946-
operator: MarkerOperator::Equal,
947-
value: "nt".to_string(),
948-
},
949-
MarkerExpression::String {
950-
key: MarkerValueString::PlatformSystem,
951-
operator: MarkerOperator::Equal,
952-
value: "Darwin".to_string(),
953-
},
954-
),
955-
// os_name == 'nt' and platform_system == 'Linux'
956-
(
957-
MarkerExpression::String {
958-
key: MarkerValueString::OsName,
959-
operator: MarkerOperator::Equal,
960-
value: "nt".to_string(),
961-
},
962-
MarkerExpression::String {
963-
key: MarkerValueString::PlatformSystem,
964-
operator: MarkerOperator::Equal,
965-
value: "Linux".to_string(),
966-
},
967-
),
968-
// os_name == 'posix' and platform_system == 'Windows'
969-
(
970-
MarkerExpression::String {
971-
key: MarkerValueString::OsName,
972-
operator: MarkerOperator::Equal,
973-
value: "posix".to_string(),
974-
},
975-
MarkerExpression::String {
976-
key: MarkerValueString::PlatformSystem,
977-
operator: MarkerOperator::Equal,
978-
value: "Windows".to_string(),
979-
},
980-
),
981-
] {
916+
];
917+
918+
// Pairs of `platform_system` and `sys_platform` that are known to be incompatible.
919+
//
920+
// For example: `platform_system == 'FreeBSD' and sys_platform == 'darwin'`
921+
//
922+
// Any `platform_system` values that we normalize away (like `Windows` to `win32`) are
923+
// omitted, since we never expect them to be present in the tree.
924+
//
925+
// Unfortunately, we can't include Cygwin here, since Cygwin appears to use a
926+
// `platform_system` value with versions encoded (e.g., `CYGWIN_NT-10.0-22631).
927+
//
928+
for platform_system in ["FreeBSD", "NetBSD", "OpenBSD", "SunOS", "iOS", "iPadOS"] {
929+
// An enumeration of known values, excluding FreeBSD, SunOS, and other Unix systems,
930+
// which use the lowercased `uname -s`, which typically includes a version (e.g.,
931+
// `freebsd8`).
932+
//
933+
// See: https://docs.python.org/3/library/sys.html#sys.platform
934+
for sys_platform in [
935+
"aix",
936+
"android",
937+
"emscripten",
938+
"ios",
939+
"linux",
940+
"darwin",
941+
"win32",
942+
"cygwin",
943+
"wasi",
944+
] {
945+
// Some of the above pairs are actually compatible.
946+
if matches!((platform_system, sys_platform), ("iOS" | "iPadOS", "ios")) {
947+
continue;
948+
}
949+
pairs.push((
950+
MarkerExpression::String {
951+
key: MarkerValueString::PlatformSystem,
952+
operator: MarkerOperator::Equal,
953+
value: platform_system.to_string(),
954+
},
955+
MarkerExpression::String {
956+
key: MarkerValueString::SysPlatform,
957+
operator: MarkerOperator::Equal,
958+
value: sys_platform.to_string(),
959+
},
960+
));
961+
}
962+
}
963+
964+
for (a, b) in pairs {
982965
let a = self.expression(a);
983966
let b = self.expression(b);
984967
let a_and_b = conjunction(self, a, b);
985968
tree = disjunction(self, tree, a_and_b);
986969
}
970+
987971
self.state.exclusions = Some(tree);
988972
tree
989973
}

crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__line-endings-poetry-with-hashes.txt.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ RequirementsTxt {
8585
),
8686
),
8787
),
88-
marker: python_full_version >= '3.8' and python_full_version < '4.0' and platform_system == 'Windows',
88+
marker: python_full_version >= '3.8' and python_full_version < '4.0' and sys_platform == 'win32',
8989
origin: Some(
9090
File(
9191
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt",

crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-poetry-with-hashes.txt.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ RequirementsTxt {
8585
),
8686
),
8787
),
88-
marker: python_full_version >= '3.8' and python_full_version < '4.0' and platform_system == 'Windows',
88+
marker: python_full_version >= '3.8' and python_full_version < '4.0' and sys_platform == 'win32',
8989
origin: Some(
9090
File(
9191
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt",

crates/uv-resolver/src/lock/mod.rs

+3-12
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,15 @@ mod tree;
6060
pub const VERSION: u32 = 1;
6161

6262
static LINUX_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
63-
let pep508 = MarkerTree::from_str(
64-
"platform_system == 'Linux' and os_name == 'posix' and sys_platform == 'linux'",
65-
)
66-
.unwrap();
63+
let pep508 = MarkerTree::from_str("os_name == 'posix' and sys_platform == 'linux'").unwrap();
6764
UniversalMarker::new(pep508, ConflictMarker::TRUE)
6865
});
6966
static WINDOWS_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
70-
let pep508 = MarkerTree::from_str(
71-
"platform_system == 'Windows' and os_name == 'nt' and sys_platform == 'win32'",
72-
)
73-
.unwrap();
67+
let pep508 = MarkerTree::from_str("os_name == 'nt' and sys_platform == 'win32'").unwrap();
7468
UniversalMarker::new(pep508, ConflictMarker::TRUE)
7569
});
7670
static MAC_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
77-
let pep508 = MarkerTree::from_str(
78-
"platform_system == 'Darwin' and os_name == 'posix' and sys_platform == 'darwin'",
79-
)
80-
.unwrap();
71+
let pep508 = MarkerTree::from_str("os_name == 'posix' and sys_platform == 'darwin'").unwrap();
8172
UniversalMarker::new(pep508, ConflictMarker::TRUE)
8273
});
8374

crates/uv/tests/it/export.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ fn dependency_extra() -> Result<()> {
128128
click==8.1.7 \
129129
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
130130
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
131-
colorama==0.4.6 ; platform_system == 'Windows' \
131+
colorama==0.4.6 ; sys_platform == 'win32' \
132132
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
133133
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
134134
flask==3.0.2 \

0 commit comments

Comments
 (0)