diff --git a/crates/uv/src/commands/pip/tree.rs b/crates/uv/src/commands/pip/tree.rs index a1d5e8146..a36370d39 100644 --- a/crates/uv/src/commands/pip/tree.rs +++ b/crates/uv/src/commands/pip/tree.rs @@ -166,6 +166,7 @@ impl DisplayDependencyGraph { } } } + Self { packages, depth, diff --git a/crates/uv/tests/it/pip_tree.rs b/crates/uv/tests/it/pip_tree.rs index 038fa22e8..3ca3d2b4d 100644 --- a/crates/uv/tests/it/pip_tree.rs +++ b/crates/uv/tests/it/pip_tree.rs @@ -1,3 +1,5 @@ +#![cfg(not(windows))] + use std::process::Command; use assert_fs::fixture::FileWriteStr; @@ -95,6 +97,7 @@ fn single_package() { ); context.assert_command("import requests").success(); + uv_snapshot!(context.filters(), context.pip_tree(), @r###" success: true exit_code: 0 @@ -109,62 +112,13 @@ fn single_package() { "### ); } -// `pandas` requires `numpy` with markers on Python version. -#[test] -#[cfg(not(windows))] -fn python_version_marker() { - let context = TestContext::new("3.12"); - - let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt.write_str("pandas==2.2.1").unwrap(); - - uv_snapshot!(context - .pip_install() - .arg("-r") - .arg("requirements.txt") - .arg("--strict"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - - ----- stderr ----- - Resolved 6 packages in [TIME] - Prepared 6 packages in [TIME] - Installed 6 packages in [TIME] - + numpy==1.26.4 - + pandas==2.2.1 - + python-dateutil==2.9.0.post0 - + pytz==2024.1 - + six==1.16.0 - + tzdata==2024.1 - - "### - ); - - uv_snapshot!(context.filters(), context.pip_tree(), @r###" - success: true - exit_code: 0 - ----- stdout ----- - pandas v2.2.1 - ├── numpy v1.26.4 - ├── python-dateutil v2.9.0.post0 - │ └── six v1.16.0 - ├── pytz v2024.1 - └── tzdata v2024.1 - - ----- stderr ----- - "### - ); -} #[test] fn nested_dependencies() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context .pip_install() @@ -176,14 +130,16 @@ fn nested_dependencies() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -191,27 +147,27 @@ fn nested_dependencies() { success: true exit_code: 0 ----- stdout ----- - scikit-learn v1.4.1.post1 - ├── numpy v1.26.4 - ├── scipy v1.12.0 - │ └── numpy v1.26.4 - ├── joblib v1.3.2 - └── threadpoolctl v3.4.0 + flask v3.0.2 + ├── werkzeug v3.0.1 + │ └── markupsafe v2.1.5 + ├── jinja2 v3.1.3 + │ └── markupsafe v2.1.5 + ├── itsdangerous v2.1.2 + ├── click v8.1.7 + └── blinker v1.7.0 ----- stderr ----- "### ); } -// Identical test as `invert` since `--reverse` is simply an alias for `--invert`. +/// Identical test as `invert` since `--reverse` is simply an alias for `--invert`. #[test] fn reverse() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context .pip_install() @@ -223,14 +179,16 @@ fn reverse() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -238,14 +196,17 @@ fn reverse() { success: true exit_code: 0 ----- stdout ----- - joblib v1.3.2 - └── scikit-learn v1.4.1.post1 - numpy v1.26.4 - ├── scikit-learn v1.4.1.post1 - └── scipy v1.12.0 - └── scikit-learn v1.4.1.post1 - threadpoolctl v3.4.0 - └── scikit-learn v1.4.1.post1 + markupsafe v2.1.5 + ├── jinja2 v3.1.3 + │ └── flask v3.0.2 + └── werkzeug v3.0.1 + └── flask v3.0.2 + blinker v1.7.0 + └── flask v3.0.2 + click v8.1.7 + └── flask v3.0.2 + itsdangerous v2.1.2 + └── flask v3.0.2 ----- stderr ----- "### @@ -257,9 +218,7 @@ fn invert() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context .pip_install() @@ -271,14 +230,16 @@ fn invert() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -286,14 +247,17 @@ fn invert() { success: true exit_code: 0 ----- stdout ----- - joblib v1.3.2 - └── scikit-learn v1.4.1.post1 - numpy v1.26.4 - ├── scikit-learn v1.4.1.post1 - └── scipy v1.12.0 - └── scikit-learn v1.4.1.post1 - threadpoolctl v3.4.0 - └── scikit-learn v1.4.1.post1 + markupsafe v2.1.5 + ├── jinja2 v3.1.3 + │ └── flask v3.0.2 + └── werkzeug v3.0.1 + └── flask v3.0.2 + blinker v1.7.0 + └── flask v3.0.2 + click v8.1.7 + └── flask v3.0.2 + itsdangerous v2.1.2 + └── flask v3.0.2 ----- stderr ----- "### @@ -305,9 +269,7 @@ fn depth() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context.pip_install() .arg("-r") @@ -318,14 +280,16 @@ fn depth() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -342,10 +306,9 @@ fn depth() { success: true exit_code: 0 ----- stdout ----- - scikit-learn v1.4.1.post1 + flask v3.0.2 ----- stderr ----- - "### ); @@ -362,14 +325,14 @@ fn depth() { success: true exit_code: 0 ----- stdout ----- - scikit-learn v1.4.1.post1 - ├── numpy v1.26.4 - ├── scipy v1.12.0 - ├── joblib v1.3.2 - └── threadpoolctl v3.4.0 + flask v3.0.2 + ├── werkzeug v3.0.1 + ├── jinja2 v3.1.3 + ├── itsdangerous v2.1.2 + ├── click v8.1.7 + └── blinker v1.7.0 ----- stderr ----- - "### ); @@ -386,12 +349,14 @@ fn depth() { success: true exit_code: 0 ----- stdout ----- - scikit-learn v1.4.1.post1 - ├── numpy v1.26.4 - ├── scipy v1.12.0 - │ └── numpy v1.26.4 - ├── joblib v1.3.2 - └── threadpoolctl v3.4.0 + flask v3.0.2 + ├── werkzeug v3.0.1 + │ └── markupsafe v2.1.5 + ├── jinja2 v3.1.3 + │ └── markupsafe v2.1.5 + ├── itsdangerous v2.1.2 + ├── click v8.1.7 + └── blinker v1.7.0 ----- stderr ----- "### @@ -403,9 +368,7 @@ fn prune() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context.pip_install() .arg("-r") @@ -416,14 +379,16 @@ fn prune() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -433,17 +398,19 @@ fn prune() { .arg("--cache-dir") .arg(context.cache_dir.path()) .arg("--prune") - .arg("numpy") + .arg("werkzeug") .env(EnvVars::VIRTUAL_ENV, context.venv.as_os_str()) .env(EnvVars::UV_NO_WRAP, "1") .current_dir(&context.temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- - scikit-learn v1.4.1.post1 - ├── scipy v1.12.0 - ├── joblib v1.3.2 - └── threadpoolctl v3.4.0 + flask v3.0.2 + ├── jinja2 v3.1.3 + │ └── markupsafe v2.1.5 + ├── itsdangerous v2.1.2 + ├── click v8.1.7 + └── blinker v1.7.0 ----- stderr ----- "### @@ -455,18 +422,19 @@ fn prune() { .arg("--cache-dir") .arg(context.cache_dir.path()) .arg("--prune") - .arg("numpy") + .arg("werkzeug") .arg("--prune") - .arg("joblib") + .arg("jinja2") .env(EnvVars::VIRTUAL_ENV, context.venv.as_os_str()) .env(EnvVars::UV_NO_WRAP, "1") .current_dir(&context.temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- - scikit-learn v1.4.1.post1 - ├── scipy v1.12.0 - └── threadpoolctl v3.4.0 + flask v3.0.2 + ├── itsdangerous v2.1.2 + ├── click v8.1.7 + └── blinker v1.7.0 ----- stderr ----- "### @@ -478,359 +446,32 @@ fn prune() { .arg("--cache-dir") .arg(context.cache_dir.path()) .arg("--prune") - .arg("scipy") + .arg("werkzeug") .env(EnvVars::VIRTUAL_ENV, context.venv.as_os_str()) .env(EnvVars::UV_NO_WRAP, "1") .current_dir(&context.temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- - scikit-learn v1.4.1.post1 - ├── numpy v1.26.4 - ├── joblib v1.3.2 - └── threadpoolctl v3.4.0 + flask v3.0.2 + ├── jinja2 v3.1.3 + │ └── markupsafe v2.1.5 + ├── itsdangerous v2.1.2 + ├── click v8.1.7 + └── blinker v1.7.0 ----- stderr ----- "### ); } -#[test] -#[cfg(target_os = "macos")] -fn complex_nested_dependencies_inverted() { - let context = TestContext::new("3.12"); - - let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt.write_str("packse").unwrap(); - - uv_snapshot!(context - .pip_install() - .arg("-r") - .arg("requirements.txt") - .arg("--strict"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - - ----- stderr ----- - Resolved 32 packages in [TIME] - Prepared 32 packages in [TIME] - Installed 32 packages in [TIME] - + certifi==2024.2.2 - + charset-normalizer==3.3.2 - + chevron-blue==0.2.1 - + docutils==0.20.1 - + hatchling==1.22.4 - + idna==3.6 - + importlib-metadata==7.1.0 - + jaraco-classes==3.3.1 - + jaraco-context==4.3.0 - + jaraco-functools==4.0.0 - + keyring==25.0.0 - + markdown-it-py==3.0.0 - + mdurl==0.1.2 - + more-itertools==10.2.0 - + msgspec==0.18.6 - + nh3==0.2.15 - + packaging==24.0 - + packse==0.3.12 - + pathspec==0.12.1 - + pkginfo==1.10.0 - + pluggy==1.4.0 - + pygments==2.17.2 - + readme-renderer==43.0 - + requests==2.31.0 - + requests-toolbelt==1.0.0 - + rfc3986==2.0.0 - + rich==13.7.1 - + setuptools==69.2.0 - + trove-classifiers==2024.3.3 - + twine==4.0.2 - + urllib3==2.2.1 - + zipp==3.18.1 - "### - ); - - uv_snapshot!(context.filters(), context.pip_tree().arg("--invert"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - certifi v2024.2.2 - └── requests v2.31.0 - ├── requests-toolbelt v1.0.0 - │ └── twine v4.0.2 - │ └── packse v0.3.12 - └── twine v4.0.2 (*) - charset-normalizer v3.3.2 - └── requests v2.31.0 (*) - chevron-blue v0.2.1 - └── packse v0.3.12 - docutils v0.20.1 - └── readme-renderer v43.0 - └── twine v4.0.2 (*) - idna v3.6 - └── requests v2.31.0 (*) - jaraco-context v4.3.0 - └── keyring v25.0.0 - └── twine v4.0.2 (*) - mdurl v0.1.2 - └── markdown-it-py v3.0.0 - └── rich v13.7.1 - └── twine v4.0.2 (*) - more-itertools v10.2.0 - ├── jaraco-classes v3.3.1 - │ └── keyring v25.0.0 (*) - └── jaraco-functools v4.0.0 - └── keyring v25.0.0 (*) - msgspec v0.18.6 - └── packse v0.3.12 - nh3 v0.2.15 - └── readme-renderer v43.0 (*) - packaging v24.0 - └── hatchling v1.22.4 - └── packse v0.3.12 - pathspec v0.12.1 - └── hatchling v1.22.4 (*) - pkginfo v1.10.0 - └── twine v4.0.2 (*) - pluggy v1.4.0 - └── hatchling v1.22.4 (*) - pygments v2.17.2 - ├── readme-renderer v43.0 (*) - └── rich v13.7.1 (*) - rfc3986 v2.0.0 - └── twine v4.0.2 (*) - setuptools v69.2.0 - └── packse v0.3.12 - trove-classifiers v2024.3.3 - └── hatchling v1.22.4 (*) - urllib3 v2.2.1 - ├── requests v2.31.0 (*) - └── twine v4.0.2 (*) - zipp v3.18.1 - └── importlib-metadata v7.1.0 - └── twine v4.0.2 (*) - (*) Package tree already displayed - - ----- stderr ----- - "### - ); -} - -#[test] -#[cfg(target_os = "macos")] -fn complex_nested_dependencies() { - let context = TestContext::new("3.12"); - - let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt.write_str("packse").unwrap(); - - uv_snapshot!(context - .pip_install() - .arg("-r") - .arg("requirements.txt") - .arg("--strict"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - - ----- stderr ----- - Resolved 32 packages in [TIME] - Prepared 32 packages in [TIME] - Installed 32 packages in [TIME] - + certifi==2024.2.2 - + charset-normalizer==3.3.2 - + chevron-blue==0.2.1 - + docutils==0.20.1 - + hatchling==1.22.4 - + idna==3.6 - + importlib-metadata==7.1.0 - + jaraco-classes==3.3.1 - + jaraco-context==4.3.0 - + jaraco-functools==4.0.0 - + keyring==25.0.0 - + markdown-it-py==3.0.0 - + mdurl==0.1.2 - + more-itertools==10.2.0 - + msgspec==0.18.6 - + nh3==0.2.15 - + packaging==24.0 - + packse==0.3.12 - + pathspec==0.12.1 - + pkginfo==1.10.0 - + pluggy==1.4.0 - + pygments==2.17.2 - + readme-renderer==43.0 - + requests==2.31.0 - + requests-toolbelt==1.0.0 - + rfc3986==2.0.0 - + rich==13.7.1 - + setuptools==69.2.0 - + trove-classifiers==2024.3.3 - + twine==4.0.2 - + urllib3==2.2.1 - + zipp==3.18.1 - "### - ); - - uv_snapshot!(context.filters(), context.pip_tree(), @r###" - success: true - exit_code: 0 - ----- stdout ----- - packse v0.3.12 - ├── chevron-blue v0.2.1 - ├── hatchling v1.22.4 - │ ├── packaging v24.0 - │ ├── pathspec v0.12.1 - │ ├── pluggy v1.4.0 - │ └── trove-classifiers v2024.3.3 - ├── msgspec v0.18.6 - ├── setuptools v69.2.0 - └── twine v4.0.2 - ├── pkginfo v1.10.0 - ├── readme-renderer v43.0 - │ ├── nh3 v0.2.15 - │ ├── docutils v0.20.1 - │ └── pygments v2.17.2 - ├── requests v2.31.0 - │ ├── charset-normalizer v3.3.2 - │ ├── idna v3.6 - │ ├── urllib3 v2.2.1 - │ └── certifi v2024.2.2 - ├── requests-toolbelt v1.0.0 - │ └── requests v2.31.0 (*) - ├── urllib3 v2.2.1 - ├── importlib-metadata v7.1.0 - │ └── zipp v3.18.1 - ├── keyring v25.0.0 - │ ├── jaraco-classes v3.3.1 - │ │ └── more-itertools v10.2.0 - │ ├── jaraco-functools v4.0.0 - │ │ └── more-itertools v10.2.0 - │ └── jaraco-context v4.3.0 - ├── rfc3986 v2.0.0 - └── rich v13.7.1 - ├── markdown-it-py v3.0.0 - │ └── mdurl v0.1.2 - └── pygments v2.17.2 - (*) Package tree already displayed - - ----- stderr ----- - "### - ); -} - -#[test] -#[cfg(target_os = "macos")] -fn prune_large_tree() { - let context = TestContext::new("3.12"); - - let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt.write_str("packse").unwrap(); - - uv_snapshot!(context.pip_install() - .arg("-r") - .arg("requirements.txt") - .arg("--strict"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - - ----- stderr ----- - Resolved 32 packages in [TIME] - Prepared 32 packages in [TIME] - Installed 32 packages in [TIME] - + certifi==2024.2.2 - + charset-normalizer==3.3.2 - + chevron-blue==0.2.1 - + docutils==0.20.1 - + hatchling==1.22.4 - + idna==3.6 - + importlib-metadata==7.1.0 - + jaraco-classes==3.3.1 - + jaraco-context==4.3.0 - + jaraco-functools==4.0.0 - + keyring==25.0.0 - + markdown-it-py==3.0.0 - + mdurl==0.1.2 - + more-itertools==10.2.0 - + msgspec==0.18.6 - + nh3==0.2.15 - + packaging==24.0 - + packse==0.3.12 - + pathspec==0.12.1 - + pkginfo==1.10.0 - + pluggy==1.4.0 - + pygments==2.17.2 - + readme-renderer==43.0 - + requests==2.31.0 - + requests-toolbelt==1.0.0 - + rfc3986==2.0.0 - + rich==13.7.1 - + setuptools==69.2.0 - + trove-classifiers==2024.3.3 - + twine==4.0.2 - + urllib3==2.2.1 - + zipp==3.18.1 - "### - ); - - uv_snapshot!(context.filters(), Command::new(get_bin()) - .arg("pip") - .arg("tree") - .arg("--cache-dir") - .arg(context.cache_dir.path()) - .arg("--prune") - .arg("hatchling") - .env(EnvVars::VIRTUAL_ENV, context.venv.as_os_str()) - .env(EnvVars::UV_NO_WRAP, "1") - .current_dir(&context.temp_dir), @r###" - success: true - exit_code: 0 - ----- stdout ----- - packse v0.3.12 - ├── chevron-blue v0.2.1 - ├── msgspec v0.18.6 - ├── setuptools v69.2.0 - └── twine v4.0.2 - ├── pkginfo v1.10.0 - ├── readme-renderer v43.0 - │ ├── nh3 v0.2.15 - │ ├── docutils v0.20.1 - │ └── pygments v2.17.2 - ├── requests v2.31.0 - │ ├── charset-normalizer v3.3.2 - │ ├── idna v3.6 - │ ├── urllib3 v2.2.1 - │ └── certifi v2024.2.2 - ├── requests-toolbelt v1.0.0 - │ └── requests v2.31.0 (*) - ├── urllib3 v2.2.1 - ├── importlib-metadata v7.1.0 - │ └── zipp v3.18.1 - ├── keyring v25.0.0 - │ ├── jaraco-classes v3.3.1 - │ │ └── more-itertools v10.2.0 - │ ├── jaraco-functools v4.0.0 - │ │ └── more-itertools v10.2.0 - │ └── jaraco-context v4.3.0 - ├── rfc3986 v2.0.0 - └── rich v13.7.1 - ├── markdown-it-py v3.0.0 - │ └── mdurl v0.1.2 - └── pygments v2.17.2 - (*) Package tree already displayed - - ----- stderr ----- - "### - ); -} - -// Ensure `pip tree` behaves correctly with a package that has a cyclic dependency. -// package `uv-cyclic-dependencies-a` and `uv-cyclic-dependencies-b` depend on each other, -// which creates a dependency cycle. -// Additionally, package `uv-cyclic-dependencies-c` is included (depends on `uv-cyclic-dependencies-a`) -// to make this test case more realistic and meaningful. +/// Ensure `pip tree` behaves correctly with a package that has a cyclic dependency. +/// +/// Package `uv-cyclic-dependencies-a` and `uv-cyclic-dependencies-b` depend on each other, +/// which creates a dependency cycle. +/// +/// Additionally, package `uv-cyclic-dependencies-c` is included (depends on `uv-cyclic-dependencies-a`) +/// to make this test case more realistic and meaningful. #[test] fn cyclic_dependency() { let context = TestContext::new("3.12"); @@ -878,7 +519,7 @@ fn cyclic_dependency() { ); } -// Ensure `pip tree` behaves correctly after a package has been removed. +/// Ensure `pip tree` behaves correctly after a package has been removed. #[test] fn removed_dependency() { let context = TestContext::new("3.12"); @@ -970,12 +611,8 @@ fn multiple_packages() { "### ); - let mut filters = context.filters(); - if cfg!(windows) { - filters.push(("└── colorama v0.4.6\n", "")); - } context.assert_command("import requests").success(); - uv_snapshot!(filters, context.pip_tree(), @r###" + uv_snapshot!(context.filters(), context.pip_tree(), @r###" success: true exit_code: 0 ----- stdout ----- @@ -991,18 +628,16 @@ fn multiple_packages() { ); } -// Both `pendulum` and `boto3` depend on `python-dateutil`. #[test] -#[cfg(not(windows))] -fn multiple_packages_shared_descendant() { +fn cycle() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); requirements_txt .write_str( r" - pendulum==3.0.0 - boto3==1.34.69 + testtools==2.3.0 + fixtures==3.0.0 ", ) .unwrap(); @@ -1020,17 +655,63 @@ fn multiple_packages_shared_descendant() { Resolved 10 packages in [TIME] Prepared 10 packages in [TIME] Installed 10 packages in [TIME] - + boto3==1.34.69 - + botocore==1.34.69 - + jmespath==1.0.1 - + pendulum==3.0.0 - + python-dateutil==2.9.0.post0 - + s3transfer==0.10.1 + + argparse==1.4.0 + + extras==1.0.0 + + fixtures==3.0.0 + + linecache2==1.0.0 + + pbr==6.0.0 + + python-mimeparse==1.6.0 + six==1.16.0 - + time-machine==2.14.1 - + tzdata==2024.1 - + urllib3==2.2.1 - + + testtools==2.3.0 + + traceback2==1.4.0 + + unittest2==1.1.0 + "### + ); + + uv_snapshot!(context.filters(), context.pip_tree(), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + + ----- stderr ----- + "### + ); +} + +/// Both `pendulum` and `boto3` depend on `python-dateutil`. +#[test] +fn multiple_packages_shared_descendant() { + let context = TestContext::new("3.12"); + + let requirements_txt = context.temp_dir.child("requirements.txt"); + requirements_txt + .write_str( + r" + pendulum + time-machine + ", + ) + .unwrap(); + + uv_snapshot!(context + .pip_install() + .arg("-r") + .arg("requirements.txt") + .arg("--strict"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 5 packages in [TIME] + Prepared 5 packages in [TIME] + Installed 5 packages in [TIME] + + pendulum==3.0.0 + + python-dateutil==2.9.0.post0 + + six==1.16.0 + + time-machine==2.14.1 + + tzdata==2024.1 "### ); @@ -1038,17 +719,9 @@ fn multiple_packages_shared_descendant() { success: true exit_code: 0 ----- stdout ----- - boto3 v1.34.69 - ├── botocore v1.34.69 - │ ├── jmespath v1.0.1 - │ ├── python-dateutil v2.9.0.post0 - │ │ └── six v1.16.0 - │ └── urllib3 v2.2.1 - ├── jmespath v1.0.1 - └── s3transfer v0.10.1 - └── botocore v1.34.69 (*) pendulum v3.0.0 - ├── python-dateutil v2.9.0.post0 (*) + ├── python-dateutil v2.9.0.post0 + │ └── six v1.16.0 ├── tzdata v2024.1 └── time-machine v2.14.1 └── python-dateutil v2.9.0.post0 (*) @@ -1059,9 +732,8 @@ fn multiple_packages_shared_descendant() { ); } -// Test the interaction between `--no-dedupe` and `--invert`. +/// Test the interaction between `--no-dedupe` and `--invert`. #[test] -#[cfg(not(windows))] fn no_dedupe_and_invert() { let context = TestContext::new("3.12"); @@ -1069,8 +741,8 @@ fn no_dedupe_and_invert() { requirements_txt .write_str( r" - pendulum==3.0.0 - boto3==1.34.69 + pendulum + time-machine ", ) .unwrap(); @@ -1085,20 +757,14 @@ fn no_dedupe_and_invert() { ----- stdout ----- ----- stderr ----- - Resolved 10 packages in [TIME] - Prepared 10 packages in [TIME] - Installed 10 packages in [TIME] - + boto3==1.34.69 - + botocore==1.34.69 - + jmespath==1.0.1 + Resolved 5 packages in [TIME] + Prepared 5 packages in [TIME] + Installed 5 packages in [TIME] + pendulum==3.0.0 + python-dateutil==2.9.0.post0 - + s3transfer==0.10.1 + six==1.16.0 + time-machine==2.14.1 + tzdata==2024.1 - + urllib3==2.2.1 - "### ); @@ -1106,38 +772,21 @@ fn no_dedupe_and_invert() { success: true exit_code: 0 ----- stdout ----- - jmespath v1.0.1 - ├── boto3 v1.34.69 - └── botocore v1.34.69 - ├── boto3 v1.34.69 - └── s3transfer v0.10.1 - └── boto3 v1.34.69 six v1.16.0 └── python-dateutil v2.9.0.post0 - ├── botocore v1.34.69 - │ ├── boto3 v1.34.69 - │ └── s3transfer v0.10.1 - │ └── boto3 v1.34.69 ├── pendulum v3.0.0 └── time-machine v2.14.1 └── pendulum v3.0.0 tzdata v2024.1 └── pendulum v3.0.0 - urllib3 v2.2.1 - └── botocore v1.34.69 - ├── boto3 v1.34.69 - └── s3transfer v0.10.1 - └── boto3 v1.34.69 ----- stderr ----- "### ); } -// Ensure that --no-dedupe behaves as expected -// in the presence of dependency cycles. +/// Ensure that --no-dedupe behaves as expected in the presence of dependency cycles. #[test] -#[cfg(not(windows))] fn no_dedupe_and_cycle() { let context = TestContext::new("3.12"); @@ -1145,8 +794,8 @@ fn no_dedupe_and_cycle() { requirements_txt .write_str( r" - pendulum==3.0.0 - boto3==1.34.69 + pendulum + time-machine ", ) .unwrap(); @@ -1161,20 +810,14 @@ fn no_dedupe_and_cycle() { ----- stdout ----- ----- stderr ----- - Resolved 10 packages in [TIME] - Prepared 10 packages in [TIME] - Installed 10 packages in [TIME] - + boto3==1.34.69 - + botocore==1.34.69 - + jmespath==1.0.1 + Resolved 5 packages in [TIME] + Prepared 5 packages in [TIME] + Installed 5 packages in [TIME] + pendulum==3.0.0 + python-dateutil==2.9.0.post0 - + s3transfer==0.10.1 + six==1.16.0 + time-machine==2.14.1 + tzdata==2024.1 - + urllib3==2.2.1 - "### ); @@ -1205,19 +848,6 @@ fn no_dedupe_and_cycle() { success: true exit_code: 0 ----- stdout ----- - boto3 v1.34.69 - ├── botocore v1.34.69 - │ ├── jmespath v1.0.1 - │ ├── python-dateutil v2.9.0.post0 - │ │ └── six v1.16.0 - │ └── urllib3 v2.2.1 - ├── jmespath v1.0.1 - └── s3transfer v0.10.1 - └── botocore v1.34.69 - ├── jmespath v1.0.1 - ├── python-dateutil v2.9.0.post0 - │ └── six v1.16.0 - └── urllib3 v2.2.1 pendulum v3.0.0 ├── python-dateutil v2.9.0.post0 │ └── six v1.16.0 @@ -1237,7 +867,6 @@ fn no_dedupe_and_cycle() { } #[test] -#[cfg(not(windows))] fn no_dedupe() { let context = TestContext::new("3.12"); @@ -1245,8 +874,8 @@ fn no_dedupe() { requirements_txt .write_str( r" - pendulum==3.0.0 - boto3==1.34.69 + pendulum + time-machine ", ) .unwrap(); @@ -1261,20 +890,14 @@ fn no_dedupe() { ----- stdout ----- ----- stderr ----- - Resolved 10 packages in [TIME] - Prepared 10 packages in [TIME] - Installed 10 packages in [TIME] - + boto3==1.34.69 - + botocore==1.34.69 - + jmespath==1.0.1 + Resolved 5 packages in [TIME] + Prepared 5 packages in [TIME] + Installed 5 packages in [TIME] + pendulum==3.0.0 + python-dateutil==2.9.0.post0 - + s3transfer==0.10.1 + six==1.16.0 + time-machine==2.14.1 + tzdata==2024.1 - + urllib3==2.2.1 - "### ); @@ -1283,19 +906,6 @@ fn no_dedupe() { success: true exit_code: 0 ----- stdout ----- - boto3 v1.34.69 - ├── botocore v1.34.69 - │ ├── jmespath v1.0.1 - │ ├── python-dateutil v2.9.0.post0 - │ │ └── six v1.16.0 - │ └── urllib3 v2.2.1 - ├── jmespath v1.0.1 - └── s3transfer v0.10.1 - └── botocore v1.34.69 - ├── jmespath v1.0.1 - ├── python-dateutil v2.9.0.post0 - │ └── six v1.16.0 - └── urllib3 v2.2.1 pendulum v3.0.0 ├── python-dateutil v2.9.0.post0 │ └── six v1.16.0 @@ -1350,98 +960,12 @@ fn with_editable() { ); } -#[test] -#[cfg(target_os = "macos")] -fn package_flag_complex() { - let context = TestContext::new("3.12"); - - let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt.write_str("packse").unwrap(); - - uv_snapshot!(context - .pip_install() - .arg("-r") - .arg("requirements.txt") - .arg("--strict"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - - ----- stderr ----- - Resolved 32 packages in [TIME] - Prepared 32 packages in [TIME] - Installed 32 packages in [TIME] - + certifi==2024.2.2 - + charset-normalizer==3.3.2 - + chevron-blue==0.2.1 - + docutils==0.20.1 - + hatchling==1.22.4 - + idna==3.6 - + importlib-metadata==7.1.0 - + jaraco-classes==3.3.1 - + jaraco-context==4.3.0 - + jaraco-functools==4.0.0 - + keyring==25.0.0 - + markdown-it-py==3.0.0 - + mdurl==0.1.2 - + more-itertools==10.2.0 - + msgspec==0.18.6 - + nh3==0.2.15 - + packaging==24.0 - + packse==0.3.12 - + pathspec==0.12.1 - + pkginfo==1.10.0 - + pluggy==1.4.0 - + pygments==2.17.2 - + readme-renderer==43.0 - + requests==2.31.0 - + requests-toolbelt==1.0.0 - + rfc3986==2.0.0 - + rich==13.7.1 - + setuptools==69.2.0 - + trove-classifiers==2024.3.3 - + twine==4.0.2 - + urllib3==2.2.1 - + zipp==3.18.1 - "### - ); - - uv_snapshot!( - context.filters(), - context.pip_tree() - .arg("--package") - .arg("hatchling") - .arg("--package") - .arg("keyring"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - hatchling v1.22.4 - ├── packaging v24.0 - ├── pathspec v0.12.1 - ├── pluggy v1.4.0 - └── trove-classifiers v2024.3.3 - - keyring v25.0.0 - ├── jaraco-classes v3.3.1 - │ └── more-itertools v10.2.0 - ├── jaraco-functools v4.0.0 - │ └── more-itertools v10.2.0 - └── jaraco-context v4.3.0 - - ----- stderr ----- - "### - ); -} - #[test] fn package_flag() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context .pip_install() @@ -1453,14 +977,16 @@ fn package_flag() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -1468,12 +994,13 @@ fn package_flag() { context.filters(), context.pip_tree() .arg("--package") - .arg("numpy"), + .arg("werkzeug"), @r###" success: true exit_code: 0 ----- stdout ----- - numpy v1.26.4 + werkzeug v3.0.1 + └── markupsafe v2.1.5 ----- stderr ----- "### @@ -1483,17 +1010,18 @@ fn package_flag() { context.filters(), context.pip_tree() .arg("--package") - .arg("scipy") + .arg("werkzeug") .arg("--package") - .arg("joblib"), + .arg("jinja2"), @r###" success: true exit_code: 0 ----- stdout ----- - scipy v1.12.0 - └── numpy v1.26.4 + werkzeug v3.0.1 + └── markupsafe v2.1.5 - joblib v1.3.2 + jinja2 v3.1.3 + └── markupsafe v2.1.5 ----- stderr ----- "### @@ -1543,117 +1071,12 @@ fn show_version_specifiers_simple() { ); } -#[test] -#[cfg(target_os = "macos")] -fn show_version_specifiers_complex() { - let context = TestContext::new("3.12"); - - let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt.write_str("packse").unwrap(); - - uv_snapshot!(context - .pip_install() - .arg("-r") - .arg("requirements.txt") - .arg("--strict"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - - ----- stderr ----- - Resolved 32 packages in [TIME] - Prepared 32 packages in [TIME] - Installed 32 packages in [TIME] - + certifi==2024.2.2 - + charset-normalizer==3.3.2 - + chevron-blue==0.2.1 - + docutils==0.20.1 - + hatchling==1.22.4 - + idna==3.6 - + importlib-metadata==7.1.0 - + jaraco-classes==3.3.1 - + jaraco-context==4.3.0 - + jaraco-functools==4.0.0 - + keyring==25.0.0 - + markdown-it-py==3.0.0 - + mdurl==0.1.2 - + more-itertools==10.2.0 - + msgspec==0.18.6 - + nh3==0.2.15 - + packaging==24.0 - + packse==0.3.12 - + pathspec==0.12.1 - + pkginfo==1.10.0 - + pluggy==1.4.0 - + pygments==2.17.2 - + readme-renderer==43.0 - + requests==2.31.0 - + requests-toolbelt==1.0.0 - + rfc3986==2.0.0 - + rich==13.7.1 - + setuptools==69.2.0 - + trove-classifiers==2024.3.3 - + twine==4.0.2 - + urllib3==2.2.1 - + zipp==3.18.1 - "### - ); - - uv_snapshot!(context.filters(), context.pip_tree().arg("--show-version-specifiers"), @r###" - success: true - exit_code: 0 - ----- stdout ----- - packse v0.3.12 - ├── chevron-blue v0.2.1 [required: >=0.2.1, <0.3.0] - ├── hatchling v1.22.4 [required: >=1.20.0, <2.0.0] - │ ├── packaging v24.0 [required: >=21.3] - │ ├── pathspec v0.12.1 [required: >=0.10.1] - │ ├── pluggy v1.4.0 [required: >=1.0.0] - │ └── trove-classifiers v2024.3.3 [required: *] - ├── msgspec v0.18.6 [required: >=0.18.4, <0.19.0] - ├── setuptools v69.2.0 [required: >=69.1.1, <70.0.0] - └── twine v4.0.2 [required: >=4.0.2, <5.0.0] - ├── pkginfo v1.10.0 [required: >=1.8.1] - ├── readme-renderer v43.0 [required: >=35.0] - │ ├── nh3 v0.2.15 [required: >=0.2.14] - │ ├── docutils v0.20.1 [required: >=0.13.1] - │ └── pygments v2.17.2 [required: >=2.5.1] - ├── requests v2.31.0 [required: >=2.20] - │ ├── charset-normalizer v3.3.2 [required: >=2, <4] - │ ├── idna v3.6 [required: >=2.5, <4] - │ ├── urllib3 v2.2.1 [required: >=1.21.1, <3] - │ └── certifi v2024.2.2 [required: >=2017.4.17] - ├── requests-toolbelt v1.0.0 [required: >=0.8.0, !=0.9.0] - │ └── requests v2.31.0 [required: >=2.0.1, <3.0.0] (*) - ├── urllib3 v2.2.1 [required: >=1.26.0] - ├── importlib-metadata v7.1.0 [required: >=3.6] - │ └── zipp v3.18.1 [required: >=0.5] - ├── keyring v25.0.0 [required: >=15.1] - │ ├── jaraco-classes v3.3.1 [required: *] - │ │ └── more-itertools v10.2.0 [required: *] - │ ├── jaraco-functools v4.0.0 [required: *] - │ │ └── more-itertools v10.2.0 [required: *] - │ └── jaraco-context v4.3.0 [required: *] - ├── rfc3986 v2.0.0 [required: >=1.4.0] - └── rich v13.7.1 [required: >=12.0.0] - ├── markdown-it-py v3.0.0 [required: >=2.2.0] - │ └── mdurl v0.1.2 [required: ~=0.1] - └── pygments v2.17.2 [required: >=2.13.0, <3.0.0] - (*) Package tree already displayed - - ----- stderr ----- - "### - ); -} - #[test] fn show_version_specifiers_with_invert() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context .pip_install() @@ -1665,14 +1088,16 @@ fn show_version_specifiers_with_invert() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -1684,14 +1109,17 @@ fn show_version_specifiers_with_invert() { success: true exit_code: 0 ----- stdout ----- - joblib v1.3.2 - └── scikit-learn v1.4.1.post1 [requires: joblib >=1.2.0] - numpy v1.26.4 - ├── scikit-learn v1.4.1.post1 [requires: numpy >=1.19.5, <2.0] - └── scipy v1.12.0 [requires: numpy >=1.22.4, <1.29.0] - └── scikit-learn v1.4.1.post1 [requires: scipy >=1.6.0] - threadpoolctl v3.4.0 - └── scikit-learn v1.4.1.post1 [requires: threadpoolctl >=2.0.0] + markupsafe v2.1.5 + ├── jinja2 v3.1.3 [requires: markupsafe >=2.0] + │ └── flask v3.0.2 [requires: jinja2 >=3.1.2] + └── werkzeug v3.0.1 [requires: markupsafe >=2.1.1] + └── flask v3.0.2 [requires: werkzeug >=3.0.0] + blinker v1.7.0 + └── flask v3.0.2 [requires: blinker >=1.6.2] + click v8.1.7 + └── flask v3.0.2 [requires: click >=8.1.3] + itsdangerous v2.1.2 + └── flask v3.0.2 [requires: itsdangerous >=2.1.2] ----- stderr ----- "### @@ -1703,9 +1131,7 @@ fn show_version_specifiers_with_package() { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); - requirements_txt - .write_str("scikit-learn==1.4.1.post1") - .unwrap(); + requirements_txt.write_str("flask").unwrap(); uv_snapshot!(context .pip_install() @@ -1717,14 +1143,16 @@ fn show_version_specifiers_with_package() { ----- stdout ----- ----- stderr ----- - Resolved 5 packages in [TIME] - Prepared 5 packages in [TIME] - Installed 5 packages in [TIME] - + joblib==1.3.2 - + numpy==1.26.4 - + scikit-learn==1.4.1.post1 - + scipy==1.12.0 - + threadpoolctl==3.4.0 + Resolved 7 packages in [TIME] + Prepared 7 packages in [TIME] + Installed 7 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.2 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 "### ); @@ -1733,12 +1161,12 @@ fn show_version_specifiers_with_package() { context.pip_tree() .arg("--show-version-specifiers") .arg("--package") - .arg("scipy"), @r###" + .arg("werkzeug"), @r###" success: true exit_code: 0 ----- stdout ----- - scipy v1.12.0 - └── numpy v1.26.4 [required: >=1.22.4, <1.29.0] + werkzeug v3.0.1 + └── markupsafe v2.1.5 [required: >=2.1.1] ----- stderr ----- "###