@@ -1201,6 +1201,221 @@ fn extra_unconditional_non_conflicting() -> Result<()> {
1201
1201
Ok ( ( ) )
1202
1202
}
1203
1203
1204
+ #[ test]
1205
+ fn extra_unconditional_in_optional ( ) -> Result < ( ) > {
1206
+ let context = TestContext :: new ( "3.12" ) ;
1207
+
1208
+ let root_pyproject_toml = context. temp_dir . child ( "pyproject.toml" ) ;
1209
+ root_pyproject_toml. write_str (
1210
+ r#"
1211
+ [project]
1212
+ name = "foo"
1213
+ version = "0.1.0"
1214
+ description = "Add your description here"
1215
+ readme = "README.md"
1216
+ requires-python = ">=3.10.0"
1217
+ dependencies = []
1218
+
1219
+ [tool.uv.workspace]
1220
+ members = ["proxy1"]
1221
+
1222
+ [tool.uv.sources]
1223
+ proxy1 = { workspace = true }
1224
+
1225
+ [project.optional-dependencies]
1226
+ x1 = ["proxy1[nested-x1]"]
1227
+ x2 = ["proxy1[nested-x2]"]
1228
+ "# ,
1229
+ ) ?;
1230
+
1231
+ let proxy1_pyproject_toml = context. temp_dir . child ( "proxy1" ) . child ( "pyproject.toml" ) ;
1232
+ proxy1_pyproject_toml. write_str (
1233
+ r#"
1234
+ [project]
1235
+ name = "proxy1"
1236
+ version = "0.1.0"
1237
+ requires-python = ">=3.10.0"
1238
+ dependencies = []
1239
+
1240
+ [project.optional-dependencies]
1241
+ nested-x1 = ["sortedcontainers==2.3.0"]
1242
+ nested-x2 = ["sortedcontainers==2.4.0"]
1243
+
1244
+ [tool.uv]
1245
+ conflicts = [
1246
+ [
1247
+ { extra = "nested-x1" },
1248
+ { extra = "nested-x2" },
1249
+ ],
1250
+ ]
1251
+ "# ,
1252
+ ) ?;
1253
+
1254
+ uv_snapshot ! ( context. filters( ) , context. lock( ) , @r###"
1255
+ success: true
1256
+ exit_code: 0
1257
+ ----- stdout -----
1258
+
1259
+ ----- stderr -----
1260
+ Resolved 4 packages in [TIME]
1261
+ "### ) ;
1262
+
1263
+ // This shouldn't install anything.
1264
+ uv_snapshot ! ( context. filters( ) , context. sync( ) . arg( "--frozen" ) , @r###"
1265
+ success: true
1266
+ exit_code: 0
1267
+ ----- stdout -----
1268
+
1269
+ ----- stderr -----
1270
+ Audited in [TIME]
1271
+ "### ) ;
1272
+
1273
+ // This shoudld install `sortedcontainers==2.3.0`.
1274
+ uv_snapshot ! ( context. filters( ) , context. sync( ) . arg( "--frozen" ) . arg( "--extra=x1" ) , @r###"
1275
+ success: true
1276
+ exit_code: 0
1277
+ ----- stdout -----
1278
+
1279
+ ----- stderr -----
1280
+ Prepared 1 package in [TIME]
1281
+ Installed 1 package in [TIME]
1282
+ + sortedcontainers==2.3.0
1283
+ "### ) ;
1284
+
1285
+ // This shoudld install `sortedcontainers==2.4.0`.
1286
+ uv_snapshot ! ( context. filters( ) , context. sync( ) . arg( "--frozen" ) . arg( "--extra=x2" ) , @r###"
1287
+ success: true
1288
+ exit_code: 0
1289
+ ----- stdout -----
1290
+
1291
+ ----- stderr -----
1292
+ Prepared 1 package in [TIME]
1293
+ Uninstalled 1 package in [TIME]
1294
+ Installed 1 package in [TIME]
1295
+ - sortedcontainers==2.3.0
1296
+ + sortedcontainers==2.4.0
1297
+ "### ) ;
1298
+
1299
+ // This should error!
1300
+ uv_snapshot ! (
1301
+ context. filters( ) ,
1302
+ context. sync( ) . arg( "--frozen" ) . arg( "--extra=x1" ) . arg( "--extra=x2" ) ,
1303
+ @r###"
1304
+ success: false
1305
+ exit_code: 2
1306
+ ----- stdout -----
1307
+
1308
+ ----- stderr -----
1309
+ error: Found conflicting extras `proxy1[nested-x1]` and `proxy1[nested-x2]` enabled simultaneously
1310
+ "### ) ;
1311
+
1312
+ Ok ( ( ) )
1313
+ }
1314
+
1315
+ #[ test]
1316
+ fn extra_unconditional_non_local_conflict ( ) -> Result < ( ) > {
1317
+ let context = TestContext :: new ( "3.12" ) ;
1318
+
1319
+ let root_pyproject_toml = context. temp_dir . child ( "pyproject.toml" ) ;
1320
+ root_pyproject_toml. write_str (
1321
+ r#"
1322
+ [project]
1323
+ name = "foo"
1324
+ version = "0.1.0"
1325
+ description = "Add your description here"
1326
+ readme = "README.md"
1327
+ requires-python = ">=3.10.0"
1328
+ dependencies = ["a", "b"]
1329
+
1330
+ [tool.uv.workspace]
1331
+ members = ["a", "b", "c"]
1332
+
1333
+ [tool.uv.sources]
1334
+ a = { workspace = true }
1335
+ b = { workspace = true }
1336
+ c = { workspace = true }
1337
+ "# ,
1338
+ ) ?;
1339
+
1340
+ let a_pyproject_toml = context. temp_dir . child ( "a" ) . child ( "pyproject.toml" ) ;
1341
+ a_pyproject_toml. write_str (
1342
+ r#"
1343
+ [project]
1344
+ name = "a"
1345
+ version = "0.1.0"
1346
+ requires-python = ">=3.10.0"
1347
+ dependencies = ["c[x1]"]
1348
+
1349
+ [tool.uv.sources]
1350
+ c = { workspace = true }
1351
+ "# ,
1352
+ ) ?;
1353
+
1354
+ let b_pyproject_toml = context. temp_dir . child ( "b" ) . child ( "pyproject.toml" ) ;
1355
+ b_pyproject_toml. write_str (
1356
+ r#"
1357
+ [project]
1358
+ name = "b"
1359
+ version = "0.1.0"
1360
+ requires-python = ">=3.10.0"
1361
+ dependencies = ["c[x2]"]
1362
+
1363
+ [tool.uv.sources]
1364
+ c = { workspace = true }
1365
+ "# ,
1366
+ ) ?;
1367
+
1368
+ let c_pyproject_toml = context. temp_dir . child ( "c" ) . child ( "pyproject.toml" ) ;
1369
+ c_pyproject_toml. write_str (
1370
+ r#"
1371
+ [project]
1372
+ name = "c"
1373
+ version = "0.1.0"
1374
+ requires-python = ">=3.10.0"
1375
+ dependencies = []
1376
+
1377
+ [project.optional-dependencies]
1378
+ x1 = ["sortedcontainers==2.3.0"]
1379
+ x2 = ["sortedcontainers==2.4.0"]
1380
+
1381
+ [tool.uv]
1382
+ conflicts = [
1383
+ [
1384
+ { extra = "x1" },
1385
+ { extra = "x2" },
1386
+ ],
1387
+ ]
1388
+ "# ,
1389
+ ) ?;
1390
+
1391
+ // Regretably, this produces a lock file, and it is one
1392
+ // that can never be installed! Namely, because two different
1393
+ // conflicting extras are enabled unconditionally in all
1394
+ // configurations.
1395
+ uv_snapshot ! ( context. filters( ) , context. lock( ) , @r###"
1396
+ success: true
1397
+ exit_code: 0
1398
+ ----- stdout -----
1399
+
1400
+ ----- stderr -----
1401
+ Resolved 6 packages in [TIME]
1402
+ "### ) ;
1403
+
1404
+ // This should fail. If it doesn't and we generated a lock
1405
+ // file above, then this will likely result in the installation
1406
+ // of two different versions of the same package.
1407
+ uv_snapshot ! ( context. filters( ) , context. sync( ) . arg( "--frozen" ) , @r###"
1408
+ success: false
1409
+ exit_code: 2
1410
+ ----- stdout -----
1411
+
1412
+ ----- stderr -----
1413
+ error: Found conflicting extras `c[x1]` and `c[x2]` enabled simultaneously
1414
+ "### ) ;
1415
+
1416
+ Ok ( ( ) )
1417
+ }
1418
+
1204
1419
/// This tests how we deal with mutually conflicting extras that span multiple
1205
1420
/// packages in a workspace.
1206
1421
#[ test]
0 commit comments