Skip to content

Commit a79cdce

Browse files
fix: ensure we only create pypi prefix once (#4416)
Co-authored-by: Tim de Jager <[email protected]>
1 parent d84a545 commit a79cdce

File tree

3 files changed

+38
-24
lines changed

3 files changed

+38
-24
lines changed

crates/pixi_core/src/lock_file/update.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use pypi_modifiers::pypi_marker_env::determine_marker_environment;
4444
use rattler::package_cache::PackageCache;
4545
use rattler_conda_types::{Arch, GenericVirtualPackage, PackageName, Platform};
4646
use rattler_lock::{LockFile, LockedPackageRef, ParseCondaLockError};
47+
use std::collections::hash_map::Entry;
4748
use std::{
4849
cmp::PartialEq,
4950
collections::{HashMap, HashSet},
@@ -1345,6 +1346,7 @@ impl<'p> UpdateContext<'p> {
13451346

13461347
// Spawn tasks to update the pypi packages.
13471348
let uv_context = once_cell::sync::OnceCell::new();
1349+
let mut pypi_conda_prefix_updaters = HashMap::new();
13481350
for (environment, platform) in
13491351
self.outdated_envs
13501352
.pypi
@@ -1388,19 +1390,26 @@ impl<'p> UpdateContext<'p> {
13881390
.get_latest_group_repodata_records(&group, environment.best_platform())
13891391
.ok_or_else(|| make_unsupported_pypi_platform_error(environment, false));
13901392

1391-
// Creates an object to initiate an update at a later point
1392-
let prefix_platform = environment.best_platform();
1393-
let conda_prefix_updater = CondaPrefixUpdater::builder(
1394-
group.clone(),
1395-
prefix_platform,
1396-
environment
1397-
.virtual_packages(prefix_platform)
1398-
.into_iter()
1399-
.map(GenericVirtualPackage::from)
1400-
.collect(),
1401-
self.command_dispatcher.clone(),
1402-
)
1403-
.finish()?;
1393+
// Creates an object to initiate an update at a later point. Make sure to only create a single entry if we are solving for multiple platforms.
1394+
let conda_prefix_updater =
1395+
match pypi_conda_prefix_updaters.entry(environment.name().clone()) {
1396+
Entry::Vacant(entry) => {
1397+
let prefix_platform = environment.best_platform();
1398+
let conda_prefix_updater = CondaPrefixUpdater::builder(
1399+
group.clone(),
1400+
prefix_platform,
1401+
environment
1402+
.virtual_packages(prefix_platform)
1403+
.into_iter()
1404+
.map(GenericVirtualPackage::from)
1405+
.collect(),
1406+
self.command_dispatcher.clone(),
1407+
)
1408+
.finish()?;
1409+
entry.insert(conda_prefix_updater).clone()
1410+
}
1411+
Entry::Occupied(entry) => entry.get().clone(),
1412+
};
14041413

14051414
let uv_context = uv_context
14061415
.get_or_try_init(|| UvResolutionContext::from_workspace(project))?

crates/pixi_utils/src/reqwest.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,15 @@ mod tests {
212212
Url::parse("https://pypi.org/simple/").unwrap(),
213213
vec![Url::parse("https://my-mirror.example.com/simple/").unwrap()],
214214
);
215-
215+
216216
let middlewares = uv_middlewares(&config);
217-
217+
218218
// Should have: mirror + OCI + auth middleware
219-
assert!(middlewares.len() >= 3,
220-
"Expected at least 3 middlewares (mirror, OCI, auth) when mirrors configured, got {}",
221-
middlewares.len());
219+
assert!(
220+
middlewares.len() >= 3,
221+
"Expected at least 3 middlewares (mirror, OCI, auth) when mirrors configured, got {}",
222+
middlewares.len()
223+
);
222224
}
223225

224226
#[test]
@@ -227,10 +229,13 @@ mod tests {
227229
// This ensures existing non-mirror auth scenarios continue to work
228230
let config = Config::default();
229231
let middlewares = uv_middlewares(&config);
230-
232+
231233
// Should have: auth middleware only
232-
assert_eq!(middlewares.len(), 1,
233-
"Expected exactly 1 middleware (auth) when no mirrors configured, got {}",
234-
middlewares.len());
234+
assert_eq!(
235+
middlewares.len(),
236+
1,
237+
"Expected exactly 1 middleware (auth) when no mirrors configured, got {}",
238+
middlewares.len()
239+
);
235240
}
236241
}

tests/integration_rust/pypi_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ async fn test_pinned_help_message() {
460460
461461
[dependencies]
462462
python = "3.12.*"
463-
pandas = "*"
463+
pandas = "2.3.2"
464464
465465
[pypi-dependencies]
466466
databricks-sql-connector = ">=4.0.0"
@@ -472,6 +472,6 @@ async fn test_pinned_help_message() {
472472
// Second, it should contain a help message
473473
assert_eq!(
474474
format!("{}", err.help().unwrap()),
475-
"The following PyPI packages have been pinned by the conda solve, and this version may be causing a conflict:\npandas==2.3.1"
475+
"The following PyPI packages have been pinned by the conda solve, and this version may be causing a conflict:\npandas==2.3.2"
476476
);
477477
}

0 commit comments

Comments
 (0)