Skip to content

Commit 5e25583

Browse files
authored
Construct PythonInstallation early instead of passing around source / interpreter separately (#18564)
1 parent 6d628da commit 5e25583

File tree

2 files changed

+58
-58
lines changed

2 files changed

+58
-58
lines changed

crates/uv-python/src/discovery.rs

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -738,16 +738,16 @@ fn find_all_minor(
738738
/// the interpreter. The caller is responsible for ensuring it is applied otherwise.
739739
///
740740
/// See [`python_executables`] for more information on discovery.
741-
fn python_interpreters<'a>(
741+
fn python_installations<'a>(
742742
version: &'a VersionRequest,
743743
implementation: Option<&'a ImplementationName>,
744744
platform: PlatformRequest,
745745
environments: EnvironmentPreference,
746746
preference: PythonPreference,
747747
cache: &'a Cache,
748748
preview: Preview,
749-
) -> impl Iterator<Item = Result<(PythonSource, Interpreter), Error>> + 'a {
750-
let interpreters = python_interpreters_from_executables(
749+
) -> impl Iterator<Item = Result<PythonInstallation, Error>> + 'a {
750+
let installations = python_installations_from_executables(
751751
// Perform filtering on the discovered executables based on their source. This avoids
752752
// unnecessary interpreter queries, which are generally expensive. We'll filter again
753753
// with `interpreter_satisfies_environment_preference` after querying.
@@ -764,52 +764,59 @@ fn python_interpreters<'a>(
764764
}),
765765
cache,
766766
)
767-
.filter_ok(move |(source, interpreter)| {
768-
interpreter_satisfies_environment_preference(*source, interpreter, environments)
767+
.filter_ok(move |installation| {
768+
interpreter_satisfies_environment_preference(
769+
installation.source,
770+
&installation.interpreter,
771+
environments,
772+
)
769773
})
770-
.filter_ok(move |(source, interpreter)| {
771-
let request = version.clone().into_request_for_source(*source);
772-
if request.matches_interpreter(interpreter) {
774+
.filter_ok(move |installation| {
775+
let request = version.clone().into_request_for_source(installation.source);
776+
if request.matches_interpreter(&installation.interpreter) {
773777
true
774778
} else {
775779
debug!(
776-
"Skipping interpreter at `{}` from {source}: does not satisfy request `{request}`",
777-
interpreter.sys_executable().user_display()
780+
"Skipping interpreter at `{}` from {}: does not satisfy request `{request}`",
781+
installation.interpreter.sys_executable().user_display(),
782+
installation.source,
778783
);
779784
false
780785
}
781786
})
782-
.filter_ok(move |(source, interpreter)| {
783-
satisfies_python_preference(*source, interpreter, preference)
787+
.filter_ok(move |installation| {
788+
satisfies_python_preference(installation.source, &installation.interpreter, preference)
784789
});
785790

786791
if std::env::var(uv_static::EnvVars::UV_INTERNAL__TEST_PYTHON_MANAGED).is_ok() {
787-
Either::Left(interpreters.map_ok(|(source, interpreter)| {
792+
Either::Left(installations.map_ok(|mut installation| {
788793
// In test mode, change the source to `Managed` if a version was marked as such via
789794
// `TestContext::with_versions_as_managed`.
790-
if interpreter.is_managed() {
791-
(PythonSource::Managed, interpreter)
792-
} else {
793-
(source, interpreter)
795+
if installation.interpreter.is_managed() {
796+
installation.source = PythonSource::Managed;
794797
}
798+
installation
795799
}))
796800
} else {
797-
Either::Right(interpreters)
801+
Either::Right(installations)
798802
}
799803
}
800804

801-
/// Lazily convert Python executables into interpreters.
802-
fn python_interpreters_from_executables<'a>(
805+
/// Lazily convert Python executables into installations.
806+
fn python_installations_from_executables<'a>(
803807
executables: impl Iterator<Item = Result<(PythonSource, PathBuf), Error>> + 'a,
804808
cache: &'a Cache,
805-
) -> impl Iterator<Item = Result<(PythonSource, Interpreter), Error>> + 'a {
809+
) -> impl Iterator<Item = Result<PythonInstallation, Error>> + 'a {
806810
executables.map(|result| match result {
807811
Ok((source, path)) => Interpreter::query(&path, cache)
808-
.map(|interpreter| (source, interpreter))
809-
.inspect(|(source, interpreter)| {
812+
.map(|interpreter| PythonInstallation {
813+
source,
814+
interpreter,
815+
})
816+
.inspect(|installation| {
810817
debug!(
811818
"Found `{}` at `{}` ({source})",
812-
interpreter.key(),
819+
installation.key(),
813820
path.display()
814821
);
815822
})
@@ -1097,12 +1104,12 @@ fn python_installation_from_directory(
10971104
python_installation_from_executable(&executable, cache)
10981105
}
10991106

1100-
/// Lazily iterate over all Python interpreters on the path with the given executable name.
1101-
fn python_interpreters_with_executable_name<'a>(
1107+
/// Lazily iterate over all Python installations on the path with the given executable name.
1108+
fn python_installations_with_executable_name<'a>(
11021109
name: &'a str,
11031110
cache: &'a Cache,
1104-
) -> impl Iterator<Item = Result<(PythonSource, Interpreter), Error>> + 'a {
1105-
python_interpreters_from_executables(
1111+
) -> impl Iterator<Item = Result<PythonInstallation, Error>> + 'a {
1112+
python_installations_from_executables(
11061113
which_all(name)
11071114
.into_iter()
11081115
.flat_map(|inner| inner.map(|path| Ok((PythonSource::SearchPath, path)))),
@@ -1181,15 +1188,15 @@ pub fn find_python_installations<'a>(
11811188
if preference.allows(PythonSource::SearchPath) {
11821189
debug!("Searching for Python interpreter with {request}");
11831190
Box::new(
1184-
python_interpreters_with_executable_name(name, cache)
1185-
.filter_ok(move |(source, interpreter)| {
1191+
python_installations_with_executable_name(name, cache)
1192+
.filter_ok(move |installation| {
11861193
interpreter_satisfies_environment_preference(
1187-
*source,
1188-
interpreter,
1194+
installation.source,
1195+
&installation.interpreter,
11891196
environments,
11901197
)
11911198
})
1192-
.map_ok(|tuple| Ok(PythonInstallation::from_tuple(tuple))),
1199+
.map_ok(Ok),
11931200
)
11941201
} else {
11951202
Box::new(iter::once(Err(Error::SourceNotAllowed(
@@ -1201,7 +1208,7 @@ pub fn find_python_installations<'a>(
12011208
}
12021209
PythonRequest::Any => Box::new({
12031210
debug!("Searching for any Python interpreter in {sources}");
1204-
python_interpreters(
1211+
python_installations(
12051212
&VersionRequest::Any,
12061213
None,
12071214
PlatformRequest::default(),
@@ -1210,11 +1217,11 @@ pub fn find_python_installations<'a>(
12101217
cache,
12111218
preview,
12121219
)
1213-
.map_ok(|tuple| Ok(PythonInstallation::from_tuple(tuple)))
1220+
.map_ok(Ok)
12141221
}),
12151222
PythonRequest::Default => Box::new({
12161223
debug!("Searching for default Python interpreter in {sources}");
1217-
python_interpreters(
1224+
python_installations(
12181225
&VersionRequest::Default,
12191226
None,
12201227
PlatformRequest::default(),
@@ -1223,15 +1230,15 @@ pub fn find_python_installations<'a>(
12231230
cache,
12241231
preview,
12251232
)
1226-
.map_ok(|tuple| Ok(PythonInstallation::from_tuple(tuple)))
1233+
.map_ok(Ok)
12271234
}),
12281235
PythonRequest::Version(version) => {
12291236
if let Err(err) = version.check_supported() {
12301237
return Box::new(iter::once(Err(Error::InvalidVersionRequest(err))));
12311238
}
12321239
Box::new({
12331240
debug!("Searching for {request} in {sources}");
1234-
python_interpreters(
1241+
python_installations(
12351242
version,
12361243
None,
12371244
PlatformRequest::default(),
@@ -1240,12 +1247,12 @@ pub fn find_python_installations<'a>(
12401247
cache,
12411248
preview,
12421249
)
1243-
.map_ok(|tuple| Ok(PythonInstallation::from_tuple(tuple)))
1250+
.map_ok(Ok)
12441251
})
12451252
}
12461253
PythonRequest::Implementation(implementation) => Box::new({
12471254
debug!("Searching for a {request} interpreter in {sources}");
1248-
python_interpreters(
1255+
python_installations(
12491256
&VersionRequest::Default,
12501257
Some(implementation),
12511258
PlatformRequest::default(),
@@ -1254,16 +1261,16 @@ pub fn find_python_installations<'a>(
12541261
cache,
12551262
preview,
12561263
)
1257-
.filter_ok(|(_source, interpreter)| implementation.matches_interpreter(interpreter))
1258-
.map_ok(|tuple| Ok(PythonInstallation::from_tuple(tuple)))
1264+
.filter_ok(|installation| implementation.matches_interpreter(&installation.interpreter))
1265+
.map_ok(Ok)
12591266
}),
12601267
PythonRequest::ImplementationVersion(implementation, version) => {
12611268
if let Err(err) = version.check_supported() {
12621269
return Box::new(iter::once(Err(Error::InvalidVersionRequest(err))));
12631270
}
12641271
Box::new({
12651272
debug!("Searching for {request} in {sources}");
1266-
python_interpreters(
1273+
python_installations(
12671274
version,
12681275
Some(implementation),
12691276
PlatformRequest::default(),
@@ -1272,8 +1279,10 @@ pub fn find_python_installations<'a>(
12721279
cache,
12731280
preview,
12741281
)
1275-
.filter_ok(|(_source, interpreter)| implementation.matches_interpreter(interpreter))
1276-
.map_ok(|tuple| Ok(PythonInstallation::from_tuple(tuple)))
1282+
.filter_ok(|installation| {
1283+
implementation.matches_interpreter(&installation.interpreter)
1284+
})
1285+
.map_ok(Ok)
12771286
})
12781287
}
12791288
PythonRequest::Key(request) => {
@@ -1285,7 +1294,7 @@ pub fn find_python_installations<'a>(
12851294

12861295
Box::new({
12871296
debug!("Searching for {request} in {sources}");
1288-
python_interpreters(
1297+
python_installations(
12891298
request.version().unwrap_or(&VersionRequest::Default),
12901299
request.implementation(),
12911300
request.platform(),
@@ -1294,10 +1303,10 @@ pub fn find_python_installations<'a>(
12941303
cache,
12951304
preview,
12961305
)
1297-
.filter_ok(move |(_source, interpreter)| {
1298-
request.satisfied_by_interpreter(interpreter)
1306+
.filter_ok(move |installation| {
1307+
request.satisfied_by_interpreter(&installation.interpreter)
12991308
})
1300-
.map_ok(|tuple| Ok(PythonInstallation::from_tuple(tuple)))
1309+
.map_ok(Ok)
13011310
})
13021311
}
13031312
}

crates/uv-python/src/installation.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,6 @@ pub struct PythonInstallation {
3838
}
3939

4040
impl PythonInstallation {
41-
/// Create a new [`PythonInstallation`] from a source, interpreter tuple.
42-
pub(crate) fn from_tuple(tuple: (PythonSource, Interpreter)) -> Self {
43-
let (source, interpreter) = tuple;
44-
Self {
45-
source,
46-
interpreter,
47-
}
48-
}
49-
5041
/// Find an installed [`PythonInstallation`].
5142
///
5243
/// This is the standard interface for discovering a Python installation for creating

0 commit comments

Comments
 (0)