From 73829f3bf4fa1bfced8b9efb6645dbe0e93d9a19 Mon Sep 17 00:00:00 2001 From: Ben Beasley Date: Mon, 2 Jun 2025 03:57:03 -0400 Subject: [PATCH] Conditionalize more tests that require PyPI (#13699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Use the existing `pypi` feature to conditionalize a number of tests that attempt to access https://pypi.org and/or https://files.pythonhosted.org. See https://github.com/astral-sh/uv/issues/8970#issuecomment-2466794088. There is no reason to believe that these are *all* of the tests that need to be conditionalized on the `pypi` feature, but this should be a solid step in the right direction. ## Test Plan This allows me to build and run the integration tests in [Fedora’s `uv` package](https://src.fedoraproject.org/rpms/uv) without having to manually skip tests that try to access PyPI. I confirmed that this appears to accomplish that goal. Otherwise, this should be tested by building and running the tests as usual. As mentioned in https://github.com/astral-sh/uv/issues/8970#issuecomment-2516181501, a more complete solution would include CI tests that confirm these features are working as intended. I’m not in a position to offer that. --- crates/uv/tests/it/branching_urls.rs | 10 ++++++++-- crates/uv/tests/it/build_backend.rs | 3 +++ crates/uv/tests/it/main.rs | 1 + crates/uv/tests/it/pip_list.rs | 10 ++++++++++ crates/uv/tests/it/pip_show.rs | 10 ++++++++++ crates/uv/tests/it/pip_tree.rs | 19 +++++++++++++++++++ crates/uv/tests/it/pip_uninstall.rs | 6 ++++++ crates/uv/tests/it/venv.rs | 2 ++ crates/uv/tests/it/version.rs | 2 ++ crates/uv/tests/it/workspace.rs | 14 ++++++++++++++ 10 files changed, 75 insertions(+), 2 deletions(-) diff --git a/crates/uv/tests/it/branching_urls.rs b/crates/uv/tests/it/branching_urls.rs index 09c77ef59..a02ec0de3 100644 --- a/crates/uv/tests/it/branching_urls.rs +++ b/crates/uv/tests/it/branching_urls.rs @@ -14,6 +14,7 @@ use crate::common::{TestContext, make_project, uv_snapshot}; /// ] /// ``` #[test] +#[cfg(feature = "pypi")] fn branching_urls_disjoint() -> Result<()> { let context = TestContext::new("3.12"); @@ -47,6 +48,7 @@ fn branching_urls_disjoint() -> Result<()> { /// ] /// ``` #[test] +#[cfg(feature = "pypi")] fn branching_urls_overlapping() -> Result<()> { let context = TestContext::new("3.12"); @@ -83,6 +85,7 @@ fn branching_urls_overlapping() -> Result<()> { /// a -> b -> b2 -> https://../iniconfig-2.0.0-py3-none-any.whl /// ``` #[test] +#[cfg(feature = "pypi")] fn root_package_splits_but_transitive_conflict() -> Result<()> { let context = TestContext::new("3.12"); @@ -151,6 +154,7 @@ fn root_package_splits_but_transitive_conflict() -> Result<()> { /// a -> b -> b2 ; python_version >= '3.12' -> https://../iniconfig-2.0.0-py3-none-any.whl /// ``` #[test] +#[cfg(feature = "pypi")] fn root_package_splits_transitive_too() -> Result<()> { let context = TestContext::new("3.12"); @@ -356,6 +360,7 @@ fn root_package_splits_transitive_too() -> Result<()> { /// a -> b2 ; python_version >= '3.12' -> iniconfig==2.0.0 /// ``` #[test] +#[cfg(feature = "pypi")] fn root_package_splits_other_dependencies_too() -> Result<()> { let context = TestContext::new("3.12"); @@ -539,6 +544,7 @@ fn root_package_splits_other_dependencies_too() -> Result<()> { /// ] /// ``` #[test] +#[cfg(feature = "pypi")] fn branching_between_registry_and_direct_url() -> Result<()> { let context = TestContext::new("3.12"); @@ -624,7 +630,7 @@ fn branching_between_registry_and_direct_url() -> Result<()> { /// ] /// ``` #[test] -#[cfg(feature = "git")] +#[cfg(all(feature = "git", feature = "pypi"))] fn branching_urls_of_different_sources_disjoint() -> Result<()> { let context = TestContext::new("3.12"); @@ -708,7 +714,7 @@ fn branching_urls_of_different_sources_disjoint() -> Result<()> { /// ] /// ``` #[test] -#[cfg(feature = "git")] +#[cfg(all(feature = "git", feature = "pypi"))] fn branching_urls_of_different_sources_conflict() -> Result<()> { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/build_backend.rs b/crates/uv/tests/it/build_backend.rs index ee4cde32b..ad3caedce 100644 --- a/crates/uv/tests/it/build_backend.rs +++ b/crates/uv/tests/it/build_backend.rs @@ -24,6 +24,7 @@ const BUILT_BY_UV_TEST_SCRIPT: &str = indoc! {r#" /// /// We can't test end-to-end here including the PEP 517 bridge code since we don't have a uv wheel. #[test] +#[cfg(feature = "pypi")] fn built_by_uv_direct_wheel() -> Result<()> { let context = TestContext::new("3.12"); let built_by_uv = Path::new("../../scripts/packages/built-by-uv"); @@ -83,6 +84,7 @@ fn built_by_uv_direct_wheel() -> Result<()> { /// We can't test end-to-end here including the PEP 517 bridge code since we don't have a uv wheel, /// so we call the build backend directly. #[test] +#[cfg(feature = "pypi")] fn built_by_uv_direct() -> Result<()> { let context = TestContext::new("3.12"); let built_by_uv = Path::new("../../scripts/packages/built-by-uv"); @@ -160,6 +162,7 @@ fn built_by_uv_direct() -> Result<()> { /// We can't test end-to-end here including the PEP 517 bridge code since we don't have a uv wheel, /// so we call the build backend directly. #[test] +#[cfg(feature = "pypi")] fn built_by_uv_editable() -> Result<()> { let context = TestContext::new("3.12"); let built_by_uv = Path::new("../../scripts/packages/built-by-uv"); diff --git a/crates/uv/tests/it/main.rs b/crates/uv/tests/it/main.rs index 926a3a790..5daa56a3a 100644 --- a/crates/uv/tests/it/main.rs +++ b/crates/uv/tests/it/main.rs @@ -41,6 +41,7 @@ mod lock_scenarios; mod version; +#[cfg(all(feature = "python", feature = "pypi"))] mod pip_check; #[cfg(all(feature = "python", feature = "pypi"))] diff --git a/crates/uv/tests/it/pip_list.rs b/crates/uv/tests/it/pip_list.rs index 5c26c03aa..ec1f288e6 100644 --- a/crates/uv/tests/it/pip_list.rs +++ b/crates/uv/tests/it/pip_list.rs @@ -56,6 +56,7 @@ fn list_empty_json() { } #[test] +#[cfg(feature = "pypi")] fn list_single_no_editable() -> Result<()> { let context = TestContext::new("3.12"); @@ -96,6 +97,7 @@ fn list_single_no_editable() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn list_outdated_columns() -> Result<()> { let context = TestContext::new("3.12"); @@ -136,6 +138,7 @@ fn list_outdated_columns() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn list_outdated_json() -> Result<()> { let context = TestContext::new("3.12"); @@ -232,6 +235,7 @@ fn list_outdated_git() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn list_outdated_index() -> Result<()> { let context = TestContext::new("3.12"); @@ -275,6 +279,7 @@ fn list_outdated_index() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn list_editable() { let context = TestContext::new("3.12"); @@ -320,6 +325,7 @@ fn list_editable() { } #[test] +#[cfg(feature = "pypi")] fn list_editable_only() { let context = TestContext::new("3.12"); @@ -394,6 +400,7 @@ fn list_editable_only() { } #[test] +#[cfg(feature = "pypi")] fn list_exclude() { let context = TestContext::new("3.12"); @@ -475,6 +482,7 @@ fn list_exclude() { } #[test] +#[cfg(feature = "pypi")] #[cfg(not(windows))] fn list_format_json() { let context = TestContext::new("3.12"); @@ -541,6 +549,7 @@ fn list_format_json() { } #[test] +#[cfg(feature = "pypi")] fn list_format_freeze() { let context = TestContext::new("3.12"); @@ -706,6 +715,7 @@ Version: 0.1-bulbasaur } #[test] +#[cfg(feature = "pypi")] fn list_ignores_quiet_flag_format_freeze() { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/pip_show.rs b/crates/uv/tests/it/pip_show.rs index 4371b089e..a097e128b 100644 --- a/crates/uv/tests/it/pip_show.rs +++ b/crates/uv/tests/it/pip_show.rs @@ -26,6 +26,7 @@ fn show_empty() { } #[test] +#[cfg(feature = "pypi")] fn show_requires_multiple() -> Result<()> { let context = TestContext::new("3.12"); @@ -75,6 +76,7 @@ fn show_requires_multiple() -> Result<()> { /// Asserts that the Python version marker in the metadata is correctly evaluated. /// `click` v8.1.7 requires `importlib-metadata`, but only when `python_version < "3.8"`. #[test] +#[cfg(feature = "pypi")] fn show_python_version_marker() -> Result<()> { let context = TestContext::new("3.12"); @@ -124,6 +126,7 @@ fn show_python_version_marker() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_found_single_package() -> Result<()> { let context = TestContext::new("3.12"); @@ -168,6 +171,7 @@ fn show_found_single_package() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_found_multiple_packages() -> Result<()> { let context = TestContext::new("3.12"); @@ -224,6 +228,7 @@ fn show_found_multiple_packages() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_found_one_out_of_three() -> Result<()> { let context = TestContext::new("3.12"); @@ -276,6 +281,7 @@ fn show_found_one_out_of_three() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_found_one_out_of_two_quiet() -> Result<()> { let context = TestContext::new("3.12"); @@ -323,6 +329,7 @@ fn show_found_one_out_of_two_quiet() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_empty_quiet() -> Result<()> { let context = TestContext::new("3.12"); @@ -369,6 +376,7 @@ fn show_empty_quiet() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_editable() -> Result<()> { let context = TestContext::new("3.12"); @@ -405,6 +413,7 @@ fn show_editable() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_required_by_multiple() -> Result<()> { let context = TestContext::new("3.12"); @@ -460,6 +469,7 @@ fn show_required_by_multiple() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn show_files() { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/pip_tree.rs b/crates/uv/tests/it/pip_tree.rs index 085d2e08d..5393c9823 100644 --- a/crates/uv/tests/it/pip_tree.rs +++ b/crates/uv/tests/it/pip_tree.rs @@ -26,6 +26,7 @@ fn no_package() { } #[test] +#[cfg(feature = "pypi")] fn prune_last_in_the_subgroup() { let context = TestContext::new("3.12"); @@ -69,6 +70,7 @@ fn prune_last_in_the_subgroup() { } #[test] +#[cfg(feature = "pypi")] fn single_package() { let context = TestContext::new("3.12"); @@ -114,6 +116,7 @@ fn single_package() { } #[test] +#[cfg(feature = "pypi")] fn nested_dependencies() { let context = TestContext::new("3.12"); @@ -163,6 +166,7 @@ fn nested_dependencies() { /// Identical test as `invert` since `--reverse` is simply an alias for `--invert`. #[test] +#[cfg(feature = "pypi")] fn reverse() { let context = TestContext::new("3.12"); @@ -214,6 +218,7 @@ fn reverse() { } #[test] +#[cfg(feature = "pypi")] fn invert() { let context = TestContext::new("3.12"); @@ -265,6 +270,7 @@ fn invert() { } #[test] +#[cfg(feature = "pypi")] fn depth() { let context = TestContext::new("3.12"); @@ -364,6 +370,7 @@ fn depth() { } #[test] +#[cfg(feature = "pypi")] fn prune() { let context = TestContext::new("3.12"); @@ -468,6 +475,7 @@ fn prune() { /// Ensure `pip tree` behaves correctly after a package has been removed. #[test] +#[cfg(feature = "pypi")] fn removed_dependency() { let context = TestContext::new("3.12"); @@ -523,6 +531,7 @@ fn removed_dependency() { } #[test] +#[cfg(feature = "pypi")] fn multiple_packages() { let context = TestContext::new("3.12"); @@ -577,6 +586,7 @@ fn multiple_packages() { /// Show the installed tree in the presence of a cycle. #[test] +#[cfg(feature = "pypi")] fn cycle() { let context = TestContext::new("3.12"); @@ -644,6 +654,7 @@ fn cycle() { /// Both `pendulum` and `boto3` depend on `python-dateutil`. #[test] +#[cfg(feature = "pypi")] fn multiple_packages_shared_descendant() { let context = TestContext::new("3.12"); @@ -697,6 +708,7 @@ fn multiple_packages_shared_descendant() { /// Test the interaction between `--no-dedupe` and `--invert`. #[test] +#[cfg(feature = "pypi")] fn no_dedupe_and_invert() { let context = TestContext::new("3.12"); @@ -749,6 +761,7 @@ fn no_dedupe_and_invert() { } #[test] +#[cfg(feature = "pypi")] fn no_dedupe() { let context = TestContext::new("3.12"); @@ -843,6 +856,7 @@ fn with_editable() { } #[test] +#[cfg(feature = "pypi")] fn package_flag() { let context = TestContext::new("3.12"); @@ -910,6 +924,7 @@ fn package_flag() { } #[test] +#[cfg(feature = "pypi")] fn show_version_specifiers_simple() { let context = TestContext::new("3.12"); @@ -953,6 +968,7 @@ fn show_version_specifiers_simple() { } #[test] +#[cfg(feature = "pypi")] fn show_version_specifiers_with_invert() { let context = TestContext::new("3.12"); @@ -1008,6 +1024,7 @@ fn show_version_specifiers_with_invert() { } #[test] +#[cfg(feature = "pypi")] fn show_version_specifiers_with_package() { let context = TestContext::new("3.12"); @@ -1055,6 +1072,7 @@ fn show_version_specifiers_with_package() { } #[test] +#[cfg(feature = "pypi")] fn print_output_even_with_quite_flag() { let context = TestContext::new("3.12"); @@ -1094,6 +1112,7 @@ fn print_output_even_with_quite_flag() { } #[test] +#[cfg(feature = "pypi")] fn outdated() { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/pip_uninstall.rs b/crates/uv/tests/it/pip_uninstall.rs index 5c820673d..3c1c0d717 100644 --- a/crates/uv/tests/it/pip_uninstall.rs +++ b/crates/uv/tests/it/pip_uninstall.rs @@ -100,6 +100,7 @@ fn invalid_requirements_txt_requirement() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn uninstall() -> Result<()> { let context = TestContext::new("3.12"); @@ -142,6 +143,7 @@ fn uninstall() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn missing_record() -> Result<()> { let context = TestContext::new("3.12"); @@ -180,6 +182,7 @@ fn missing_record() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn uninstall_editable_by_name() -> Result<()> { let context = TestContext::new("3.12"); @@ -228,6 +231,7 @@ fn uninstall_editable_by_name() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn uninstall_by_path() -> Result<()> { let context = TestContext::new("3.12"); @@ -276,6 +280,7 @@ fn uninstall_by_path() -> Result<()> { } #[test] +#[cfg(feature = "pypi")] fn uninstall_duplicate_by_path() -> Result<()> { let context = TestContext::new("3.12"); @@ -326,6 +331,7 @@ fn uninstall_duplicate_by_path() -> Result<()> { /// Uninstall a duplicate package in a virtual environment. #[test] +#[cfg(feature = "pypi")] fn uninstall_duplicate() -> Result<()> { use uv_fs::copy_dir_all; diff --git a/crates/uv/tests/it/venv.rs b/crates/uv/tests/it/venv.rs index 54c528d0e..1d9eb5721 100644 --- a/crates/uv/tests/it/venv.rs +++ b/crates/uv/tests/it/venv.rs @@ -579,6 +579,7 @@ fn create_venv_explicit_request_takes_priority_over_python_version_file() { } #[test] +#[cfg(feature = "pypi")] fn seed() { let context = TestContext::new_with_versions(&["3.12"]); uv_snapshot!(context.filters(), context.venv() @@ -602,6 +603,7 @@ fn seed() { } #[test] +#[cfg(feature = "pypi")] fn seed_older_python_version() { let context = TestContext::new_with_versions(&["3.11"]); uv_snapshot!(context.filters(), context.venv() diff --git a/crates/uv/tests/it/version.rs b/crates/uv/tests/it/version.rs index 6ecc38aa3..1fda42705 100644 --- a/crates/uv/tests/it/version.rs +++ b/crates/uv/tests/it/version.rs @@ -1368,6 +1368,7 @@ fn version_get_workspace() -> Result<()> { /// /// Also check that --locked/--frozen/--no-sync do what they say #[test] +#[cfg(feature = "pypi")] fn version_set_workspace() -> Result<()> { let context = TestContext::new("3.12"); @@ -1709,6 +1710,7 @@ fn version_set_workspace() -> Result<()> { /// It would be nice to have a case where we still get a package dependency, but /// this still demonstrates the non-trivial "hazard" of a version change. #[test] +#[cfg(feature = "pypi")] fn version_set_evil_constraints() -> Result<()> { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/workspace.rs b/crates/uv/tests/it/workspace.rs index 1b375597c..c52c4a2f1 100644 --- a/crates/uv/tests/it/workspace.rs +++ b/crates/uv/tests/it/workspace.rs @@ -24,6 +24,7 @@ fn workspaces_dir() -> PathBuf { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_in_examples_bird_feeder() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -67,6 +68,7 @@ fn test_albatross_in_examples_bird_feeder() { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_in_examples() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -107,6 +109,7 @@ fn test_albatross_in_examples() { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_just_project() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -147,6 +150,7 @@ fn test_albatross_just_project() { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_project_in_excluded() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -222,6 +226,7 @@ fn test_albatross_project_in_excluded() { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_root_workspace() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -265,6 +270,7 @@ fn test_albatross_root_workspace() { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_root_workspace_bird_feeder() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -310,6 +316,7 @@ fn test_albatross_root_workspace_bird_feeder() { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_root_workspace_albatross() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -355,6 +362,7 @@ fn test_albatross_root_workspace_albatross() { } #[test] +#[cfg(feature = "pypi")] fn test_albatross_virtual_workspace() { let context = TestContext::new("3.12"); let workspace = context.temp_dir.child("workspace"); @@ -402,6 +410,7 @@ fn test_albatross_virtual_workspace() { /// Check that `uv run --package` works in a virtual workspace. #[test] +#[cfg(feature = "pypi")] fn test_uv_run_with_package_virtual_workspace() -> Result<()> { let context = TestContext::new("3.12"); let work_dir = context.temp_dir.join("albatross-virtual-workspace"); @@ -471,6 +480,7 @@ fn test_uv_run_with_package_virtual_workspace() -> Result<()> { /// Check that `uv run` works from a virtual workspace root, which should sync all packages in the /// workspace. #[test] +#[cfg(feature = "pypi")] fn test_uv_run_virtual_workspace_root() -> Result<()> { let context = TestContext::new("3.12"); let work_dir = context.temp_dir.join("albatross-virtual-workspace"); @@ -511,6 +521,7 @@ fn test_uv_run_virtual_workspace_root() -> Result<()> { /// Check that `uv run --package` works in a root workspace. #[test] +#[cfg(feature = "pypi")] fn test_uv_run_with_package_root_workspace() -> Result<()> { let context = TestContext::new("3.12"); let work_dir = context.temp_dir.join("albatross-root-workspace"); @@ -573,6 +584,7 @@ fn test_uv_run_with_package_root_workspace() -> Result<()> { /// Check that `uv run --isolated` creates isolated virtual environments. #[test] +#[cfg(feature = "pypi")] fn test_uv_run_isolate() -> Result<()> { let context = TestContext::new("3.12"); let work_dir = context.temp_dir.join("albatross-root-workspace"); @@ -694,6 +706,7 @@ fn workspace_lock_idempotence(workspace: &str, subdirectories: &[&str]) -> Resul /// Check that the resolution is the same no matter where in the workspace we are. #[test] +#[cfg(feature = "pypi")] fn workspace_lock_idempotence_root_workspace() -> Result<()> { workspace_lock_idempotence( "albatross-root-workspace", @@ -705,6 +718,7 @@ fn workspace_lock_idempotence_root_workspace() -> Result<()> { /// Check that the resolution is the same no matter where in the workspace we are, and that locking /// works even if there is no root project. #[test] +#[cfg(feature = "pypi")] fn workspace_lock_idempotence_virtual_workspace() -> Result<()> { workspace_lock_idempotence( "albatross-virtual-workspace",