#![cfg(all(feature = "python", feature = "pypi"))] use std::iter; use std::path::Path; use std::process::Command; use anyhow::{Context, Result}; use assert_cmd::prelude::*; use assert_fs::prelude::*; use insta_cmd::_macro_support::insta; use insta_cmd::{assert_cmd_snapshot, get_cargo_bin}; use common::{create_venv_py312, BIN_NAME, INSTA_FILTERS}; mod common; fn check_command(venv: &Path, command: &str, temp_dir: &Path) { Command::new(venv.join("bin").join("python")) // https://github.com/python/cpython/issues/75953 .arg("-B") .arg("-c") .arg(command) .current_dir(temp_dir) .assert() .success(); } #[test] fn missing_requirements_txt() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let requirements_txt = temp_dir.child("requirements.txt"); assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .current_dir(&temp_dir), @r###" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- error: failed to open file `requirements.txt` Caused by: No such file or directory (os error 2) "###); requirements_txt.assert(predicates::path::missing()); Ok(()) } #[test] fn missing_venv() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = temp_dir.child(".venv"); assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- error: failed to open file `requirements.txt` Caused by: No such file or directory (os error 2) "###); venv.assert(predicates::path::missing()); Ok(()) } /// Install a package into a virtual environment using the default link semantics. (On macOS, /// this using `clone` semantics.) #[test] fn install() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + markupsafe==2.1.3 "###); }); check_command(&venv, "import markupsafe", &temp_dir); Ok(()) } /// Install a package into a virtual environment using copy semantics. #[test] fn install_copy() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--link-mode") .arg("copy") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + markupsafe==2.1.3 "###); }); check_command(&venv, "import markupsafe", &temp_dir); Ok(()) } /// Install a package into a virtual environment using hardlink semantics. #[test] fn install_hardlink() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--link-mode") .arg("hardlink") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + markupsafe==2.1.3 "###); }); check_command(&venv, "import markupsafe", &temp_dir); Ok(()) } /// Install multiple packages into a virtual environment. #[test] fn install_many() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] Downloaded 2 packages in [TIME] Installed 2 packages in [TIME] + markupsafe==2.1.3 + tomli==2.0.1 "###); }); check_command(&venv, "import markupsafe; import tomli", &cache_dir); Ok(()) } /// Attempt to install an already-installed package into a virtual environment. #[test] fn noop() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir) .assert() .success(); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Audited 1 package in [TIME] "###); }); check_command(&venv, "import markupsafe", &temp_dir); Ok(()) } /// Install a package into a virtual environment, then install the same package into a different /// virtual environment. #[test] fn link() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv1 = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv1.as_os_str()) .current_dir(&temp_dir) .assert() .success(); let venv2 = temp_dir.child(".venv2"); Command::new(get_cargo_bin(BIN_NAME)) .arg("venv") .arg(venv2.as_os_str()) .arg("--cache-dir") .arg(cache_dir.path()) .arg("--python") .arg("python3.12") .current_dir(&temp_dir) .assert() .success(); venv2.assert(predicates::path::is_dir()); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv2.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Installed 1 package in [TIME] + markupsafe==2.1.3 "###); }); check_command(&venv2, "import markupsafe", &temp_dir); Ok(()) } /// Install a package into a virtual environment, then sync the virtual environment with a /// different requirements file. #[test] fn add_remove() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir) .assert() .success(); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("tomli==2.0.1")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - markupsafe==2.1.3 + tomli==2.0.1 "###); }); check_command(&venv, "import tomli", &temp_dir); Command::new(venv.join("bin").join("python")) .arg("-c") .arg("import markupsafe") .current_dir(&temp_dir) .assert() .failure(); Ok(()) } /// Install a package into a virtual environment, then install a second package into the same /// virtual environment. #[test] fn install_sequential() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir) .assert() .success(); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tomli==2.0.1 "###); }); check_command(&venv, "import markupsafe; import tomli", &cache_dir); Ok(()) } /// Install a package into a virtual environment, then install a second package into the same /// virtual environment. #[test] fn upgrade() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("tomli==2.0.0")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir) .assert() .success(); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("tomli==2.0.1")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - tomli==2.0.0 + tomli==2.0.1 "###); }); check_command(&venv, "import tomli", &temp_dir); Ok(()) } /// Install a package into a virtual environment from a URL. #[test] fn install_url() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==2.0.0 (from https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl) "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Install a package into a virtual environment from a Git repository. #[test] #[cfg(feature = "git")] fn install_git_commit() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74) "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Install a package into a virtual environment from a Git repository. #[test] #[cfg(feature = "git")] fn install_git_tag() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ git+https://github.com/pallets/werkzeug.git@2.0.0")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@2.0.0) "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Install two packages from the same Git repository. #[test] #[cfg(feature = "git")] fn install_git_subdirectories() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("example-pkg-a @ git+https://github.com/pypa/sample-namespace-packages.git@df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45#subdirectory=pkg_resources/pkg_a\nexample-pkg-b @ git+https://github.com/pypa/sample-namespace-packages.git@df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45#subdirectory=pkg_resources/pkg_b")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] Downloaded 2 packages in [TIME] Installed 2 packages in [TIME] + example-pkg-a==1 (from git+https://github.com/pypa/sample-namespace-packages.git@df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45#subdirectory=pkg_resources/pkg_a) + example-pkg-b==1 (from git+https://github.com/pypa/sample-namespace-packages.git@df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45#subdirectory=pkg_resources/pkg_b) "###); }); check_command(&venv, "import example_pkg", &temp_dir); check_command(&venv, "import example_pkg.a", &temp_dir); check_command(&venv, "import example_pkg.b", &temp_dir); Ok(()) } /// Install a source distribution into a virtual environment. #[test] fn install_sdist() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("Werkzeug==0.9.6")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==0.9.6 "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Install a source distribution into a virtual environment. #[test] fn install_sdist_url() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("Werkzeug @ https://files.pythonhosted.org/packages/63/69/5702e5eb897d1a144001e21d676676bcb87b88c0862f947509ea95ea54fc/Werkzeug-0.9.6.tar.gz")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==0.9.6 (from https://files.pythonhosted.org/packages/63/69/5702e5eb897d1a144001e21d676676bcb87b88c0862f947509ea95ea54fc/Werkzeug-0.9.6.tar.gz) "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Attempt to re-install a package into a virtual environment from a URL. The second install /// should be a no-op. #[test] fn install_url_then_install_url() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir) .assert() .success(); insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Audited 1 package in [TIME] "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Install a package via a URL, then via a registry version. The second install _should_ remove the /// URL-based version, but doesn't right now. #[test] fn install_url_then_install_version() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir) .assert() .success(); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug==2.0.0")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Audited 1 package in [TIME] "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Install a package via a registry version, then via a direct URL version. The second install /// should remove the registry-based version. #[test] fn install_version_then_install_url() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug==2.0.0")?; Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir) .assert() .success(); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?; insta::with_settings!({ filters => vec![ (r"(\d|\.)+(ms|s)", "[TIME]"), ] }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - werkzeug==2.0.0 + werkzeug==2.0.0 (from https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl) "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Test that we select the last 3.8 compatible numpy version instead of trying to compile an /// incompatible sdist #[test] fn install_numpy_py38() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = temp_dir.child(".venv"); Command::new(get_cargo_bin(BIN_NAME)) .arg("venv") .arg(venv.as_os_str()) .arg("--python") // TODO(konstin): Mock the venv in the installer test so we don't need this anymore .arg(which::which("python3.8").context("python3.8 must be installed")?) .arg("--cache-dir") .arg(cache_dir.path()) .current_dir(&temp_dir) .assert() .success(); venv.assert(predicates::path::is_dir()); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("numpy")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + numpy==1.24.4 "###); }); check_command(&venv, "import numpy", &temp_dir); Ok(()) } #[test] fn warn_on_yanked_version() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_in = temp_dir.child("requirements.txt"); requirements_in.touch()?; // This version is yanked. requirements_in.write_str("colorama==0.4.2")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] warning: colorama==0.4.2 is yanked (reason: "Bad build, missing files, will not install"). Refresh your lockfile to pin an un-yanked version. Downloaded 1 package in [TIME] Installed 1 package in [TIME] + colorama==0.4.2 "###); }); Ok(()) } /// Resolve a local wheel. #[test] fn install_local_wheel() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); // Download a wheel. let response = reqwest::blocking::get("https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl")?; let archive = temp_dir.child("tomli-3.0.1-py3-none-any.whl"); let mut archive_file = std::fs::File::create(&archive)?; std::io::copy(&mut response.bytes()?.as_ref(), &mut archive_file)?; let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(&format!("tomli @ file://{}", archive.path().display()))?; // In addition to the standard filters, remove the temporary directory from the snapshot. let filters: Vec<_> = iter::once((r"file://.*/", "file://[TEMP_DIR]/")) .chain(INSTA_FILTERS.to_vec()) .collect(); insta::with_settings!({ filters => filters }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tomli==3.0.1 (from file://[TEMP_DIR]/tomli-3.0.1-py3-none-any.whl) "###); }); check_command(&venv, "import tomli", &temp_dir); Ok(()) } /// Install a local source distribution. #[test] fn install_local_source_distribution() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); // Download a source distribution. let response = reqwest::blocking::get("https://files.pythonhosted.org/packages/b0/b4/bc2baae3970c282fae6c2cb8e0f179923dceb7eaffb0e76170628f9af97b/wheel-0.42.0.tar.gz")?; let archive = temp_dir.child("wheel-0.42.0.tar.gz"); let mut archive_file = std::fs::File::create(&archive)?; std::io::copy(&mut response.bytes()?.as_ref(), &mut archive_file)?; let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(&format!("wheel @ file://{}", archive.path().display()))?; // In addition to the standard filters, remove the temporary directory from the snapshot. let filters: Vec<_> = iter::once((r"file://.*/", "file://[TEMP_DIR]/")) .chain(INSTA_FILTERS.to_vec()) .collect(); insta::with_settings!({ filters => filters }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + wheel==0.42.0 (from file://[TEMP_DIR]/wheel-0.42.0.tar.gz) "###); }); check_command(&venv, "import wheel", &temp_dir); Ok(()) } /// The `ujson` package includes a `[build-system]`, but no `build-backend`. It lists some explicit /// build requirements, but _also_ depends on `wheel` and `setuptools`: /// ```toml /// [build-system] /// requires = ["setuptools>=42", "setuptools_scm[toml]>=3.4"] /// ``` /// /// Like `pip` and `build`, we should use PEP 517 here and respect the `requires`, but use the /// default build backend. #[test] fn install_ujson() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("ujson @ https://files.pythonhosted.org/packages/43/1a/b0a027144aa5c8f4ea654f4afdd634578b450807bb70b9f8bad00d6f6d3c/ujson-5.7.0.tar.gz")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + ujson==5.7.0 (from https://files.pythonhosted.org/packages/43/1a/b0a027144aa5c8f4ea654f4afdd634578b450807bb70b9f8bad00d6f6d3c/ujson-5.7.0.tar.gz) "###); }); check_command(&venv, "import ujson", &temp_dir); Ok(()) } /// The `DTLSSocket` package includes a `[build-system]`, but no `build-backend`. It lists some /// explicit build requirements that are necessary to build the distribution: /// ```toml /// [build-system] /// requires = ["Cython<3", "setuptools", "wheel"] /// ``` /// /// Like `pip` and `build`, we should use PEP 517 here and respect the `requires`, but use the /// default build backend. #[test] fn install_dtls_socket() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("DTLSSocket @ https://files.pythonhosted.org/packages/58/42/0a0442118096eb9fbc9dc70b45aee2957f7546b80545e2a05bd839380519/DTLSSocket-0.1.16.tar.gz")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + dtlssocket==0.1.16 (from https://files.pythonhosted.org/packages/58/42/0a0442118096eb9fbc9dc70b45aee2957f7546b80545e2a05bd839380519/DTLSSocket-0.1.16.tar.gz) warning: The package `dtlssocket` requires `cython <3`, but it's not installed. "###); }); check_command(&venv, "import DTLSSocket", &temp_dir); Ok(()) } /// Check that we show the right messages on cached, direct URL source distribution installs. #[test] fn install_url_source_dist_cached() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("tqdm @ https://files.pythonhosted.org/packages/62/06/d5604a70d160f6a6ca5fd2ba25597c24abd5c5ca5f437263d177ac242308/tqdm-4.66.1.tar.gz")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tqdm==4.66.1 (from https://files.pythonhosted.org/packages/62/06/d5604a70d160f6a6ca5fd2ba25597c24abd5c5ca5f437263d177ac242308/tqdm-4.66.1.tar.gz) "###); }); check_command(&venv, "import tqdm", &temp_dir); // Re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Installed 1 package in [TIME] + tqdm==4.66.1 (from https://files.pythonhosted.org/packages/62/06/d5604a70d160f6a6ca5fd2ba25597c24abd5c5ca5f437263d177ac242308/tqdm-4.66.1.tar.gz) "###); }); check_command(&venv, "import tqdm", &temp_dir); // Clear the cache, then re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("clean") .arg("tqdm") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Cleared 1 entry for package: tqdm "###); }); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tqdm==4.66.1 (from https://files.pythonhosted.org/packages/62/06/d5604a70d160f6a6ca5fd2ba25597c24abd5c5ca5f437263d177ac242308/tqdm-4.66.1.tar.gz) "###); }); check_command(&venv, "import tqdm", &temp_dir); Ok(()) } /// Check that we show the right messages on cached, Git source distribution installs. #[test] #[cfg(feature = "git")] fn install_git_source_dist_cached() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74) "###); }); check_command(&venv, "import werkzeug", &temp_dir); // Re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Installed 1 package in [TIME] + werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74) "###); }); check_command(&venv, "import werkzeug", &temp_dir); // Clear the cache, then re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("clean") .arg("werkzeug") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Cleared 1 entry for package: werkzeug "###); }); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74) "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } /// Check that we show the right messages on cached, registry source distribution installs. #[test] fn install_registry_source_dist_cached() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("future==0.18.3")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + future==0.18.3 "###); }); check_command(&venv, "import future", &temp_dir); // Re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Installed 1 package in [TIME] + future==0.18.3 "###); }); check_command(&venv, "import future", &temp_dir); // Clear the cache, then re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("clean") .arg("future") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Cleared 2 entries for package: future "###); }); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + future==0.18.3 "###); }); check_command(&venv, "import future", &temp_dir); Ok(()) } /// Check that we show the right messages on cached, local source distribution installs. #[test] fn install_path_source_dist_cached() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); // Download a source distribution. let response = reqwest::blocking::get("https://files.pythonhosted.org/packages/b0/b4/bc2baae3970c282fae6c2cb8e0f179923dceb7eaffb0e76170628f9af97b/wheel-0.42.0.tar.gz")?; let archive = temp_dir.child("wheel-0.42.0.tar.gz"); let mut archive_file = std::fs::File::create(&archive)?; std::io::copy(&mut response.bytes()?.as_ref(), &mut archive_file)?; let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(&format!("wheel @ file://{}", archive.path().display()))?; // In addition to the standard filters, remove the temporary directory from the snapshot. let filters: Vec<_> = iter::once((r"file://.*/", "file://[TEMP_DIR]/")) .chain(INSTA_FILTERS.to_vec()) .collect(); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + wheel==0.42.0 (from file://[TEMP_DIR]/wheel-0.42.0.tar.gz) "###); }); check_command(&venv, "import wheel", &temp_dir); // Re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Installed 1 package in [TIME] + wheel==0.42.0 (from file://[TEMP_DIR]/wheel-0.42.0.tar.gz) "###); }); check_command(&venv, "import wheel", &temp_dir); // Clear the cache, then re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("clean") .arg("wheel") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Cleared 1 entry for package: wheel "###); }); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + wheel==0.42.0 (from file://[TEMP_DIR]/wheel-0.42.0.tar.gz) "###); }); check_command(&venv, "import wheel", &temp_dir); Ok(()) } /// Check that we show the right messages on cached, local source distribution installs. #[test] fn install_path_built_dist_cached() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); // Download a wheel. let response = reqwest::blocking::get("https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl")?; let archive = temp_dir.child("tomli-3.0.1-py3-none-any.whl"); let mut archive_file = std::fs::File::create(&archive)?; std::io::copy(&mut response.bytes()?.as_ref(), &mut archive_file)?; let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(&format!("tomli @ file://{}", archive.path().display()))?; // In addition to the standard filters, remove the temporary directory from the snapshot. let filters: Vec<_> = iter::once((r"file://.*/", "file://[TEMP_DIR]/")) .chain(INSTA_FILTERS.to_vec()) .collect(); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tomli==3.0.1 (from file://[TEMP_DIR]/tomli-3.0.1-py3-none-any.whl) "###); }); check_command(&venv, "import tomli", &temp_dir); // Re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Installed 1 package in [TIME] + tomli==3.0.1 (from file://[TEMP_DIR]/tomli-3.0.1-py3-none-any.whl) "###); }); check_command(&venv, "import tomli", &parent); // Clear the cache, then re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("clean") .arg("tomli") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Cleared 1 entry for package: tomli "###); }); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tomli==3.0.1 (from file://[TEMP_DIR]/tomli-3.0.1-py3-none-any.whl) "###); }); check_command(&venv, "import tomli", &temp_dir); Ok(()) } /// Check that we show the right messages on cached, direct URL built distribution installs. #[test] fn install_url_built_dist_cached() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("tqdm @ https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tqdm==4.66.1 (from https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl) "###); }); check_command(&venv, "import tqdm", &temp_dir); // Re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Installed 1 package in [TIME] + tqdm==4.66.1 (from https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl) "###); }); check_command(&venv, "import tqdm", &temp_dir); // Clear the cache, then re-run the installation in a new virtual environment. let parent = assert_fs::TempDir::new()?; let venv = create_venv_py312(&parent, &cache_dir); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("clean") .arg("tqdm") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Cleared 1 entry for package: tqdm "###); }); insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + tqdm==4.66.1 (from https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl) "###); }); check_command(&venv, "import tqdm", &temp_dir); Ok(()) } /// Verify that fail with an appropriate error when a package is repeated. #[test] fn duplicate_package_overlap() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3\nMarkupSafe==2.1.2")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- error: Failed to determine installation plan Caused by: Detected duplicate package in requirements: markupsafe "###); }); Ok(()) } /// Verify that allow duplicate packages when they are disjoint. #[test] fn duplicate_package_disjoint() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3\nMarkupSafe==2.1.2 ; python_version < '3.6'")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + markupsafe==2.1.3 "###); }); Ok(()) } /// Verify that we can force reinstall of packages. #[test] fn reinstall() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] Downloaded 2 packages in [TIME] Installed 2 packages in [TIME] + markupsafe==2.1.3 + tomli==2.0.1 "###); }); check_command(&venv, "import markupsafe", &temp_dir); check_command(&venv, "import tomli", &temp_dir); // Re-run the installation with `--reinstall`. insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--reinstall") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] Downloaded 2 packages in [TIME] Uninstalled 2 packages in [TIME] Installed 2 packages in [TIME] - markupsafe==2.1.3 + markupsafe==2.1.3 - tomli==2.0.1 + tomli==2.0.1 "###); }); check_command(&venv, "import markupsafe", &temp_dir); check_command(&venv, "import tomli", &temp_dir); Ok(()) } /// Verify that we can force reinstall of selective packages. #[test] fn reinstall_package() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] Downloaded 2 packages in [TIME] Installed 2 packages in [TIME] + markupsafe==2.1.3 + tomli==2.0.1 "###); }); check_command(&venv, "import markupsafe", &temp_dir); check_command(&venv, "import tomli", &temp_dir); // Re-run the installation with `--reinstall`. insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--reinstall-package") .arg("tomli") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - tomli==2.0.1 + tomli==2.0.1 "###); }); check_command(&venv, "import markupsafe", &temp_dir); check_command(&venv, "import tomli", &temp_dir); Ok(()) } /// Verify that we can force reinstall of Git dependencies. #[test] #[cfg(feature = "git")] fn reinstall_git() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.touch()?; requirements_txt.write_str("werkzeug @ git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74")?; insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74) "###); }); check_command(&venv, "import werkzeug", &temp_dir); // Re-run the installation with `--reinstall`. insta::with_settings!({ filters => INSTA_FILTERS.to_vec() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--reinstall-package") .arg("WerkZeug") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74) + werkzeug==2.0.0 (from git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74) "###); }); check_command(&venv, "import werkzeug", &temp_dir); Ok(()) } #[test] #[cfg(feature = "maturin")] fn sync_editable() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let current_dir = std::env::current_dir()?; let workspace_dir = current_dir.join("..").join("..").canonicalize()?; let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(&indoc::formatdoc! {r" boltons==23.1.1 -e ../../scripts/editable-installs/maturin_editable numpy==1.26.2 # via poetry-editable -e file://{current_dir}/../../scripts/editable-installs/poetry_editable ", current_dir = current_dir.display(), })?; let filter_path = requirements_txt.display().to_string(); let filters = INSTA_FILTERS .iter() .chain(&[ (filter_path.as_str(), "requirements.txt"), ( r"file://.*/../../scripts/editable-installs/poetry_editable", "file://[TEMP_DIR]/../../scripts/editable-installs/poetry_editable", ), (workspace_dir.to_str().unwrap(), "[WORKSPACE_DIR]"), ]) .copied() .collect::>(); // Install the editable packages. insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg(requirements_txt.path()) .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .env("CARGO_TARGET_DIR", "../../../target/target_install_editable"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Built 2 editables in [TIME] Resolved 2 packages in [TIME] Downloaded 2 packages in [TIME] Installed 4 packages in [TIME] + boltons==23.1.1 + maturin-editable==0.1.0 (from file://[WORKSPACE_DIR]/scripts/editable-installs/maturin_editable/) + numpy==1.26.2 + poetry-editable==0.1.0 (from file://[WORKSPACE_DIR]/scripts/editable-installs/poetry_editable) "###); }); // Reinstall the editable packages. insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg(requirements_txt.path()) .arg("--reinstall-package") .arg("poetry-editable") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .env("CARGO_TARGET_DIR", "../../../target/target_install_editable"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Built 1 editable in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - poetry-editable==0.1.0 (from file://[WORKSPACE_DIR]/scripts/editable-installs/poetry_editable) + poetry-editable==0.1.0 (from file://[WORKSPACE_DIR]/scripts/editable-installs/poetry_editable) "###); }); // Make sure we have the right base case. let python_source_file = "../../scripts/editable-installs/maturin_editable/python/maturin_editable/__init__.py"; let python_version_1 = indoc::indoc! {r" from .maturin_editable import * version = 1 "}; fs_err::write(python_source_file, python_version_1)?; let command = indoc::indoc! {r#" from maturin_editable import sum_as_string, version assert version == 1, version assert sum_as_string(1, 2) == "3", sum_as_string(1, 2) "#}; check_command(&venv, command, &temp_dir); // Edit the sources. let python_version_2 = indoc::indoc! {r" from .maturin_editable import * version = 2 "}; fs_err::write(python_source_file, python_version_2)?; let command = indoc::indoc! {r#" from maturin_editable import sum_as_string, version from pathlib import Path assert version == 2, version assert sum_as_string(1, 2) == "3", sum_as_string(1, 2) "#}; check_command(&venv, command, &temp_dir); // Don't create a git diff. fs_err::write(python_source_file, python_version_1)?; insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg(requirements_txt.path()) .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .env("CARGO_TARGET_DIR", "../../../target/target_install_editable"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Audited 4 packages in [TIME] "###); }); Ok(()) } #[test] fn sync_editable_and_registry() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let current_dir = std::env::current_dir()?; let workspace_dir = current_dir.join("..").join("..").canonicalize()?; // Install the registry-based version of Black. let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(indoc::indoc! {r" black " })?; let filter_path = requirements_txt.display().to_string(); let filters = INSTA_FILTERS .iter() .chain(&[ (filter_path.as_str(), "requirements.txt"), (workspace_dir.to_str().unwrap(), "[WORKSPACE_DIR]"), ]) .copied() .collect::>(); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg(requirements_txt.path()) .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .env("CARGO_TARGET_DIR", "../../../target/target_install_editable"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Installed 1 package in [TIME] + black==24.1a1 warning: The package `black` requires `click >=8.0.0`, but it's not installed. warning: The package `black` requires `mypy-extensions >=0.4.3`, but it's not installed. warning: The package `black` requires `packaging >=22.0`, but it's not installed. warning: The package `black` requires `pathspec >=0.9.0`, but it's not installed. warning: The package `black` requires `platformdirs >=2`, but it's not installed. warning: The package `black` requires `aiohttp >=3.7.4 ; sys_platform != 'win32' or (implementation_name != 'pypy' and extra == 'd')`, but it's not installed. "###); }); // Install the editable version of Black. This should remove the registry-based version. let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(indoc::indoc! {r" -e ../../scripts/editable-installs/black_editable " })?; let filter_path = requirements_txt.display().to_string(); let filters = INSTA_FILTERS .iter() .chain(&[ (filter_path.as_str(), "requirements.txt"), (workspace_dir.to_str().unwrap(), "[WORKSPACE_DIR]"), ]) .copied() .collect::>(); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg(requirements_txt.path()) .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .env("CARGO_TARGET_DIR", "../../../target/target_install_editable"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Built 1 editable in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - black==24.1a1 + black==0.1.0 (from file://[WORKSPACE_DIR]/scripts/editable-installs/black_editable/) "###); }); // Re-install the registry-based version of Black. This should be a no-op, since we have a // version of Black installed (the editable version) that satisfies the requirements. let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(indoc::indoc! {r" black " })?; let filter_path = requirements_txt.display().to_string(); let filters = INSTA_FILTERS .iter() .chain(&[ (filter_path.as_str(), "requirements.txt"), (workspace_dir.to_str().unwrap(), "[WORKSPACE_DIR]"), ]) .copied() .collect::>(); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg(requirements_txt.path()) .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .env("CARGO_TARGET_DIR", "../../../target/target_install_editable"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Audited 1 package in [TIME] "###); }); // Re-install Black at a specific version. This should replace the editable version. let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(indoc::indoc! {r" black==23.10.0 " })?; let filter_path = requirements_txt.display().to_string(); let filters = INSTA_FILTERS .iter() .chain(&[ (filter_path.as_str(), "requirements.txt"), (workspace_dir.to_str().unwrap(), "[WORKSPACE_DIR]"), ]) .copied() .collect::>(); insta::with_settings!({ filters => filters.clone() }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg(requirements_txt.path()) .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .env("CARGO_TARGET_DIR", "../../../target/target_install_editable"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] Downloaded 1 package in [TIME] Uninstalled 1 package in [TIME] Installed 1 package in [TIME] - black==0.1.0 (from file://[WORKSPACE_DIR]/scripts/editable-installs/black_editable/) + black==23.10.0 warning: The package `black` requires `click >=8.0.0`, but it's not installed. warning: The package `black` requires `mypy-extensions >=0.4.3`, but it's not installed. warning: The package `black` requires `packaging >=22.0`, but it's not installed. warning: The package `black` requires `pathspec >=0.9.0`, but it's not installed. warning: The package `black` requires `platformdirs >=2`, but it's not installed. "###); }); Ok(()) } #[test] fn incompatible_wheel() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; let wheel_dir = assert_fs::TempDir::new()?; let cache_dir = assert_fs::TempDir::new()?; let venv = create_venv_py312(&temp_dir, &cache_dir); let wheel = wheel_dir.child("foo-1.2.3-not-compatible-wheel.whl"); wheel.touch()?; let requirements_txt = temp_dir.child("requirements.txt"); requirements_txt.write_str(&format!("foo @ file://{}", wheel.path().display()))?; let wheel_dir = wheel_dir.path().canonicalize()?.display().to_string(); let filters: Vec<_> = iter::once((wheel_dir.as_str(), "[TEMP_DIR]")) .chain(INSTA_FILTERS.to_vec()) .collect(); insta::with_settings!({ filters => filters }, { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) .arg("pip-sync") .arg("requirements.txt") .arg("--strict") .arg("--cache-dir") .arg(cache_dir.path()) .env("VIRTUAL_ENV", venv.as_os_str()) .current_dir(&temp_dir), @r###" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- error: Failed to determine installation plan Caused by: A path dependency is incompatible with the current platform: [TEMP_DIR]/foo-1.2.3-not-compatible-wheel.whl "###); }); Ok(()) }