uv/crates/puffin/tests/pip_install_scenarios.rs

3117 lines
102 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! DO NOT EDIT
//!
//! Generated with ./scripts/scenarios/update.py
//! Scenarios from <https://github.com/zanieb/packse/tree/a2c483f055f5cb01fbbbcf9189c238ee487a7a8e/scenarios>
//!
#![cfg(all(feature = "python", feature = "pypi"))]
use std::path::Path;
use std::process::Command;
use assert_cmd::assert::Assert;
use assert_cmd::prelude::*;
use common::{venv_to_interpreter, INSTA_FILTERS};
use crate::common::{get_bin, puffin_snapshot, TestContext};
mod common;
fn assert_command(venv: &Path, command: &str, temp_dir: &Path) -> Assert {
Command::new(venv_to_interpreter(venv))
.arg("-c")
.arg(command)
.current_dir(temp_dir)
.assert()
}
fn assert_installed(venv: &Path, package: &'static str, version: &'static str, temp_dir: &Path) {
assert_command(
venv,
format!("import {package} as package; print(package.__version__, end='')").as_str(),
temp_dir,
)
.success()
.stdout(version);
}
fn assert_not_installed(venv: &Path, package: &'static str, temp_dir: &Path) {
assert_command(venv, format!("import {package}").as_str(), temp_dir).failure();
}
/// Create a `pip install` command with options shared across all scenarios.
fn command(context: &TestContext) -> Command {
let mut command = Command::new(get_bin());
command
.arg("pip")
.arg("install")
.arg("--extra-index-url")
.arg("https://test.pypi.org/simple")
.arg("--cache-dir")
.arg(context.cache_dir.path())
.env("VIRTUAL_ENV", context.venv.as_os_str())
.env("PUFFIN_NO_WRAP", "1")
.current_dir(&context.temp_dir);
command
}
/// requires-package-does-not-exist
///
/// The user requires any version of package `a` which does not exist.
///
/// ```text
/// 5a1a4a35
/// ├── environment
/// │ └── python3.8
/// └── root
/// └── requires a
/// └── unsatisfied: no versions for package
/// ```
#[test]
fn requires_package_does_not_exist() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"-5a1a4a35", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-5a1a4a35")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because a was not found in the package registry and you require a, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_5a1a4a35", &context.temp_dir);
}
/// requires-exact-version-does-not-exist
///
/// The user requires an exact version of package `a` but only other versions exist
///
/// ```text
/// 7cff23d9
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a==2.0.0
/// │ └── unsatisfied: no matching version
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn requires_exact_version_does_not_exist() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-7cff23d9", "albatross"));
filters.push((r"-7cff23d9", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-7cff23d9==2.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because there is no version of albatross==2.0.0 and you require albatross==2.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_7cff23d9", &context.temp_dir);
}
/// requires-greater-version-does-not-exist
///
/// The user requires a version of `a` greater than `1.0.0` but only smaller or
/// equal versions exist
///
/// ```text
/// 63569c9e
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>1.0.0
/// │ └── unsatisfied: no matching version
/// └── a
/// ├── a-0.1.0
/// └── a-1.0.0
/// ```
#[test]
fn requires_greater_version_does_not_exist() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-63569c9e", "albatross"));
filters.push((r"-63569c9e", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-63569c9e>1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross<=1.0.0 is available and you require albatross>1.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_63569c9e", &context.temp_dir);
}
/// requires-less-version-does-not-exist
///
/// The user requires a version of `a` less than `1.0.0` but only larger versions
/// exist
///
/// ```text
/// 2af6fa02
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a<2.0.0
/// │ └── unsatisfied: no matching version
/// └── a
/// ├── a-2.0.0
/// ├── a-3.0.0
/// └── a-4.0.0
/// ```
#[test]
fn requires_less_version_does_not_exist() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-2af6fa02", "albatross"));
filters.push((r"-2af6fa02", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-2af6fa02<2.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross>=2.0.0 is available and you require albatross<2.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_2af6fa02", &context.temp_dir);
}
/// transitive-requires-package-does-not-exist
///
/// The user requires package `a` but `a` requires package `b` which does not exist
///
/// ```text
/// 64b04b2b
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// └── requires b
/// └── unsatisfied: no versions for package
/// ```
#[test]
fn transitive_requires_package_does_not_exist() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-64b04b2b", "albatross"));
filters.push((r"-64b04b2b", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-64b04b2b")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because b was not found in the package registry and albatross==1.0.0 depends on b, we can conclude that albatross==1.0.0 cannot be used.
And because only albatross==1.0.0 is available and you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_64b04b2b", &context.temp_dir);
}
/// excluded-only-version
///
/// Only one version of the requested package is available, but the user has banned
/// that version.
///
/// ```text
/// 72f0d052
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a!=1.0.0
/// │ └── unsatisfied: no matching version
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn excluded_only_version() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-72f0d052", "albatross"));
filters.push((r"-72f0d052", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-72f0d052!=1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross==1.0.0 is available and you require one of:
albatross<1.0.0
albatross>1.0.0
we can conclude that the requirements are unsatisfiable.
"###);
// Only `a==1.0.0` is available but the user excluded it.
assert_not_installed(&context.venv, "a_72f0d052", &context.temp_dir);
}
/// excluded-only-compatible-version
///
/// Only one version of the requested package `a` is compatible, but the user has
/// banned that version.
///
/// ```text
/// d6ce69da
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a!=2.0.0
/// │ │ ├── satisfied by a-1.0.0
/// │ │ └── satisfied by a-3.0.0
/// │ └── requires b<3.0.0,>=2.0.0
/// │ └── satisfied by b-2.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ │ └── requires b==1.0.0
/// │ │ └── satisfied by b-1.0.0
/// │ ├── a-2.0.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ └── a-3.0.0
/// │ └── requires b==3.0.0
/// │ └── satisfied by b-3.0.0
/// └── b
/// ├── b-1.0.0
/// ├── b-2.0.0
/// └── b-3.0.0
/// ```
#[test]
fn excluded_only_compatible_version() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-d6ce69da", "albatross"));
filters.push((r"b-d6ce69da", "bluebird"));
filters.push((r"-d6ce69da", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-d6ce69da!=2.0.0")
.arg("b-d6ce69da<3.0.0,>=2.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of albatross are available:
albatross==1.0.0
albatross==2.0.0
albatross==3.0.0
and albatross==1.0.0 depends on bluebird==1.0.0, we can conclude that albatross<2.0.0 depends on bluebird==1.0.0.
And because albatross==3.0.0 depends on bluebird==3.0.0, we can conclude that any of:
albatross<2.0.0
albatross>2.0.0
depends on one of:
bluebird<=1.0.0
bluebird>=3.0.0
And because you require bluebird>=2.0.0,<3.0.0 and you require one of:
albatross<2.0.0
albatross>2.0.0
we can conclude that the requirements are unsatisfiable.
"###);
// Only `a==1.2.0` is available since `a==1.0.0` and `a==3.0.0` require
// incompatible versions of `b`. The user has excluded that version of `a` so
// resolution fails.
assert_not_installed(&context.venv, "a_d6ce69da", &context.temp_dir);
assert_not_installed(&context.venv, "b_d6ce69da", &context.temp_dir);
}
/// dependency-excludes-range-of-compatible-versions
///
/// There is a range of compatible versions for the requested package `a`, but
/// another dependency `c` excludes that range.
///
/// ```text
/// 5824fb81
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ ├── satisfied by a-1.0.0
/// │ │ ├── satisfied by a-2.0.0
/// │ │ ├── satisfied by a-2.1.0
/// │ │ ├── satisfied by a-2.2.0
/// │ │ ├── satisfied by a-2.3.0
/// │ │ └── satisfied by a-3.0.0
/// │ ├── requires b<3.0.0,>=2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ └── requires c
/// │ ├── satisfied by c-1.0.0
/// │ └── satisfied by c-2.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ │ └── requires b==1.0.0
/// │ │ └── satisfied by b-1.0.0
/// │ ├── a-2.0.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ ├── a-2.1.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ ├── a-2.2.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ ├── a-2.3.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ └── a-3.0.0
/// │ └── requires b==3.0.0
/// │ └── satisfied by b-3.0.0
/// ├── b
/// │ ├── b-1.0.0
/// │ ├── b-2.0.0
/// │ └── b-3.0.0
/// └── c
/// ├── c-1.0.0
/// │ └── requires a<2.0.0
/// │ └── satisfied by a-1.0.0
/// └── c-2.0.0
/// └── requires a>=3.0.0
/// └── satisfied by a-3.0.0
/// ```
#[test]
fn dependency_excludes_range_of_compatible_versions() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-5824fb81", "albatross"));
filters.push((r"b-5824fb81", "bluebird"));
filters.push((r"c-5824fb81", "crow"));
filters.push((r"-5824fb81", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-5824fb81")
.arg("b-5824fb81<3.0.0,>=2.0.0")
.arg("c-5824fb81")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of albatross are available:
albatross==1.0.0
albatross>=2.0.0,<=3.0.0
and albatross==1.0.0 depends on bluebird==1.0.0, we can conclude that albatross<2.0.0 depends on bluebird==1.0.0. (1)
Because only the following versions of crow are available:
crow==1.0.0
crow==2.0.0
and crow==1.0.0 depends on albatross<2.0.0, we can conclude that crow<2.0.0 depends on albatross<2.0.0.
And because crow==2.0.0 depends on albatross>=3.0.0, we can conclude that all versions of crow depend on one of:
albatross<2.0.0
albatross>=3.0.0
And because we know from (1) that albatross<2.0.0 depends on bluebird==1.0.0, we can conclude that albatross!=3.0.0, all versions of crow, bluebird!=1.0.0 are incompatible.
And because albatross==3.0.0 depends on bluebird==3.0.0, we can conclude that all versions of crow depend on one of:
bluebird==1.0.0
bluebird==3.0.0
And because you require crow and you require bluebird>=2.0.0,<3.0.0, we can conclude that the requirements are unsatisfiable.
"###);
// Only the `2.x` versions of `a` are available since `a==1.0.0` and `a==3.0.0`
// require incompatible versions of `b`, but all available versions of `c` exclude
// that range of `a` so resolution fails.
assert_not_installed(&context.venv, "a_5824fb81", &context.temp_dir);
assert_not_installed(&context.venv, "b_5824fb81", &context.temp_dir);
assert_not_installed(&context.venv, "c_5824fb81", &context.temp_dir);
}
/// dependency-excludes-non-contiguous-range-of-compatible-versions
///
/// There is a non-contiguous range of compatible versions for the requested package
/// `a`, but another dependency `c` excludes the range. This is the same as
/// `dependency-excludes-range-of-compatible-versions` but some of the versions of
/// `a` are incompatible for another reason e.g. dependency on non-existant package
/// `d`.
///
/// ```text
/// 119f929b
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ ├── satisfied by a-1.0.0
/// │ │ ├── satisfied by a-2.0.0
/// │ │ ├── satisfied by a-2.1.0
/// │ │ ├── satisfied by a-2.2.0
/// │ │ ├── satisfied by a-2.3.0
/// │ │ ├── satisfied by a-2.4.0
/// │ │ └── satisfied by a-3.0.0
/// │ ├── requires b<3.0.0,>=2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ └── requires c
/// │ ├── satisfied by c-1.0.0
/// │ └── satisfied by c-2.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ │ └── requires b==1.0.0
/// │ │ └── satisfied by b-1.0.0
/// │ ├── a-2.0.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ ├── a-2.1.0
/// │ │ ├── requires b==2.0.0
/// │ │ │ └── satisfied by b-2.0.0
/// │ │ └── requires d
/// │ │ └── unsatisfied: no versions for package
/// │ ├── a-2.2.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ ├── a-2.3.0
/// │ │ ├── requires b==2.0.0
/// │ │ │ └── satisfied by b-2.0.0
/// │ │ └── requires d
/// │ │ └── unsatisfied: no versions for package
/// │ ├── a-2.4.0
/// │ │ └── requires b==2.0.0
/// │ │ └── satisfied by b-2.0.0
/// │ └── a-3.0.0
/// │ └── requires b==3.0.0
/// │ └── satisfied by b-3.0.0
/// ├── b
/// │ ├── b-1.0.0
/// │ ├── b-2.0.0
/// │ └── b-3.0.0
/// └── c
/// ├── c-1.0.0
/// │ └── requires a<2.0.0
/// │ └── satisfied by a-1.0.0
/// └── c-2.0.0
/// └── requires a>=3.0.0
/// └── satisfied by a-3.0.0
/// ```
#[test]
fn dependency_excludes_non_contiguous_range_of_compatible_versions() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-119f929b", "albatross"));
filters.push((r"b-119f929b", "bluebird"));
filters.push((r"c-119f929b", "crow"));
filters.push((r"-119f929b", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-119f929b")
.arg("b-119f929b<3.0.0,>=2.0.0")
.arg("c-119f929b")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of crow are available:
crow==1.0.0
crow==2.0.0
and crow==1.0.0 depends on albatross<2.0.0, we can conclude that crow<2.0.0 depends on albatross<2.0.0. (1)
Because only the following versions of albatross are available:
albatross==1.0.0
albatross>=2.0.0
and albatross==1.0.0 depends on bluebird==1.0.0, we can conclude that albatross<2.0.0 depends on bluebird==1.0.0.
And because we know from (1) that crow<2.0.0 depends on albatross<2.0.0, we can conclude that crow<2.0.0 depends on bluebird==1.0.0.
And because crow==2.0.0 depends on albatross>=3.0.0, we can conclude that albatross<3.0.0, all versions of crow, bluebird!=1.0.0 are incompatible. (2)
Because only albatross<=3.0.0 is available and albatross==3.0.0 depends on bluebird==3.0.0, we can conclude that albatross>=3.0.0 depends on bluebird==3.0.0.
And because we know from (2) that albatross<3.0.0, all versions of crow, bluebird!=1.0.0 are incompatible, we can conclude that all versions of crow depend on one of:
bluebird<=1.0.0
bluebird>=3.0.0
And because you require bluebird>=2.0.0,<3.0.0 and you require crow, we can conclude that the requirements are unsatisfiable.
"###);
// Only the `2.x` versions of `a` are available since `a==1.0.0` and `a==3.0.0`
// require incompatible versions of `b`, but all available versions of `c` exclude
// that range of `a` so resolution fails.
assert_not_installed(&context.venv, "a_119f929b", &context.temp_dir);
assert_not_installed(&context.venv, "b_119f929b", &context.temp_dir);
assert_not_installed(&context.venv, "c_119f929b", &context.temp_dir);
}
/// extra-required
///
/// Optional dependencies are requested for the package.
///
/// ```text
/// c1e0ed38
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a[extra]
/// │ ├── satisfied by a-1.0.0
/// │ └── satisfied by a-1.0.0[extra]
/// ├── a
/// │ ├── a-1.0.0
/// │ └── a-1.0.0[extra]
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// └── b
/// └── b-1.0.0
/// ```
#[test]
fn extra_required() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-c1e0ed38", "albatross"));
filters.push((r"b-c1e0ed38", "bluebird"));
filters.push((r"-c1e0ed38", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-c1e0ed38[extra]")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Downloaded 2 packages in [TIME]
Installed 2 packages in [TIME]
+ albatross==1.0.0
+ bluebird==1.0.0
"###);
assert_installed(&context.venv, "a_c1e0ed38", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "b_c1e0ed38", "1.0.0", &context.temp_dir);
}
/// missing-extra
///
/// Optional dependencies are requested for the package, but the extra does not
/// exist.
///
/// ```text
/// de25a6db
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a[extra]
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn missing_extra() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-de25a6db", "albatross"));
filters.push((r"-de25a6db", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-de25a6db[extra]")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
// Missing extras are ignored during resolution.
assert_installed(&context.venv, "a_de25a6db", "1.0.0", &context.temp_dir);
}
/// multiple-extras-required
///
/// Multiple optional dependencies are requested for the package.
///
/// ```text
/// 502cbb59
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a[extra_b,extra_c]
/// │ ├── satisfied by a-1.0.0
/// │ ├── satisfied by a-1.0.0[extra_b]
/// │ └── satisfied by a-1.0.0[extra_c]
/// ├── a
/// │ ├── a-1.0.0
/// │ ├── a-1.0.0[extra_b]
/// │ │ └── requires b
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-1.0.0[extra_c]
/// │ └── requires c
/// │ └── satisfied by c-1.0.0
/// ├── b
/// │ └── b-1.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn multiple_extras_required() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-502cbb59", "albatross"));
filters.push((r"b-502cbb59", "bluebird"));
filters.push((r"c-502cbb59", "crow"));
filters.push((r"-502cbb59", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-502cbb59[extra_b,extra_c]")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Downloaded 3 packages in [TIME]
Installed 3 packages in [TIME]
+ albatross==1.0.0
+ bluebird==1.0.0
+ crow==1.0.0
"###);
assert_installed(&context.venv, "a_502cbb59", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "b_502cbb59", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "c_502cbb59", "1.0.0", &context.temp_dir);
}
/// extra-incompatible-with-extra
///
/// Multiple optional dependencies are requested for the package, but they have
/// conflicting requirements with each other.
///
/// ```text
/// a5547b80
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a[extra_b,extra_c]
/// │ ├── satisfied by a-1.0.0
/// │ ├── satisfied by a-1.0.0[extra_b]
/// │ └── satisfied by a-1.0.0[extra_c]
/// ├── a
/// │ ├── a-1.0.0
/// │ ├── a-1.0.0[extra_b]
/// │ │ └── requires b==1.0.0
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-1.0.0[extra_c]
/// │ └── requires b==2.0.0
/// │ └── satisfied by b-2.0.0
/// └── b
/// ├── b-1.0.0
/// └── b-2.0.0
/// ```
#[test]
fn extra_incompatible_with_extra() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-a5547b80", "albatross"));
filters.push((r"b-a5547b80", "bluebird"));
filters.push((r"-a5547b80", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-a5547b80[extra_b,extra_c]")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross[extra-b]==1.0.0 is available and albatross[extra-b]==1.0.0 depends on bluebird==1.0.0, we can conclude that all versions of albatross[extra-b] depend on bluebird==1.0.0.
And because albatross[extra-c]==1.0.0 depends on bluebird==2.0.0 and only albatross[extra-c]==1.0.0 is available, we can conclude that all versions of albatross[extra-c] and all versions of albatross[extra-b] are incompatible.
And because you require albatross[extra-c] and you require albatross[extra-b], we can conclude that the requirements are unsatisfiable.
"###);
// Because both `extra_b` and `extra_c` are requested and they require incompatible
// versions of `b`, `a` cannot be installed.
assert_not_installed(&context.venv, "a_a5547b80", &context.temp_dir);
}
/// extra-incompatible-with-extra-not-requested
///
/// One of two incompatible optional dependencies are requested for the package.
///
/// ```text
/// 8bb31c23
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a[extra_c]
/// │ ├── satisfied by a-1.0.0
/// │ ├── satisfied by a-1.0.0[extra_b]
/// │ └── satisfied by a-1.0.0[extra_c]
/// ├── a
/// │ ├── a-1.0.0
/// │ ├── a-1.0.0[extra_b]
/// │ │ └── requires b==1.0.0
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-1.0.0[extra_c]
/// │ └── requires b==2.0.0
/// │ └── satisfied by b-2.0.0
/// └── b
/// ├── b-1.0.0
/// └── b-2.0.0
/// ```
#[test]
fn extra_incompatible_with_extra_not_requested() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-8bb31c23", "albatross"));
filters.push((r"b-8bb31c23", "bluebird"));
filters.push((r"-8bb31c23", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-8bb31c23[extra_c]")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Downloaded 2 packages in [TIME]
Installed 2 packages in [TIME]
+ albatross==1.0.0
+ bluebird==2.0.0
"###);
// Because the user does not request both extras, it is okay that one is
// incompatible with the other.
assert_installed(&context.venv, "a_8bb31c23", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "b_8bb31c23", "2.0.0", &context.temp_dir);
}
/// extra-incompatible-with-root
///
/// Optional dependencies are requested for the package, but the extra is not
/// compatible with other requested versions.
///
/// ```text
/// aca6971b
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a[extra]
/// │ │ ├── satisfied by a-1.0.0
/// │ │ └── satisfied by a-1.0.0[extra]
/// │ └── requires b==2.0.0
/// │ └── satisfied by b-2.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ └── a-1.0.0[extra]
/// │ └── requires b==1.0.0
/// │ └── satisfied by b-1.0.0
/// └── b
/// ├── b-1.0.0
/// └── b-2.0.0
/// ```
#[test]
fn extra_incompatible_with_root() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-aca6971b", "albatross"));
filters.push((r"b-aca6971b", "bluebird"));
filters.push((r"-aca6971b", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-aca6971b[extra]")
.arg("b-aca6971b==2.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross[extra]==1.0.0 is available and albatross[extra]==1.0.0 depends on bluebird==1.0.0, we can conclude that all versions of albatross[extra] depend on bluebird==1.0.0.
And because you require albatross[extra] and you require bluebird==2.0.0, we can conclude that the requirements are unsatisfiable.
"###);
// Because the user requested `b==2.0.0` but the requested extra requires
// `b==1.0.0`, the dependencies cannot be satisfied.
assert_not_installed(&context.venv, "a_aca6971b", &context.temp_dir);
assert_not_installed(&context.venv, "b_aca6971b", &context.temp_dir);
}
/// extra-does-not-exist-backtrack
///
/// Optional dependencies are requested for the package, the extra is only available
/// on an older version.
///
/// ```text
/// c4307e58
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a[extra]
/// │ ├── satisfied by a-1.0.0
/// │ ├── satisfied by a-1.0.0[extra]
/// │ ├── satisfied by a-2.0.0
/// │ └── satisfied by a-3.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ ├── a-1.0.0[extra]
/// │ │ └── requires b==1.0.0
/// │ │ └── satisfied by b-1.0.0
/// │ ├── a-2.0.0
/// │ └── a-3.0.0
/// └── b
/// └── b-1.0.0
/// ```
#[test]
fn extra_does_not_exist_backtrack() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-c4307e58", "albatross"));
filters.push((r"b-c4307e58", "bluebird"));
filters.push((r"-c4307e58", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-c4307e58[extra]")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==3.0.0
"###);
// The resolver should not backtrack to `a==1.0.0` because missing extras are
// allowed during resolution. `b` should not be installed.
assert_installed(&context.venv, "a_c4307e58", "3.0.0", &context.temp_dir);
}
/// direct-incompatible-versions
///
/// The user requires two incompatible, existing versions of package `a`
///
/// ```text
/// c0e7adfa
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires a==2.0.0
/// │ └── satisfied by a-2.0.0
/// └── a
/// ├── a-1.0.0
/// └── a-2.0.0
/// ```
#[test]
fn direct_incompatible_versions() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-c0e7adfa", "albatross"));
filters.push((r"-c0e7adfa", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-c0e7adfa==1.0.0")
.arg("a-c0e7adfa==2.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ your requirements cannot be used because there are conflicting versions for `albatross`: `albatross==1.0.0` does not intersect with `albatross==2.0.0`
"###);
assert_not_installed(&context.venv, "a_c0e7adfa", &context.temp_dir);
assert_not_installed(&context.venv, "a_c0e7adfa", &context.temp_dir);
}
/// transitive-incompatible-with-root-version
///
/// The user requires packages `a` and `b` but `a` requires a different version of
/// `b`
///
/// ```text
/// a13da883
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b==1.0.0
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires b==2.0.0
/// │ └── satisfied by b-2.0.0
/// └── b
/// ├── b-1.0.0
/// └── b-2.0.0
/// ```
#[test]
fn transitive_incompatible_with_root_version() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-a13da883", "albatross"));
filters.push((r"b-a13da883", "bluebird"));
filters.push((r"-a13da883", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-a13da883")
.arg("b-a13da883==1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross==1.0.0 is available and albatross==1.0.0 depends on bluebird==2.0.0, we can conclude that all versions of albatross depend on bluebird==2.0.0.
And because you require albatross and you require bluebird==1.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_a13da883", &context.temp_dir);
assert_not_installed(&context.venv, "b_a13da883", &context.temp_dir);
}
/// transitive-incompatible-with-transitive
///
/// The user requires package `a` and `b`; `a` and `b` require different versions of
/// `c`
///
/// ```text
/// ec82e315
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c==1.0.0
/// │ └── satisfied by c-1.0.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c==2.0.0
/// │ └── satisfied by c-2.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0
/// ```
#[test]
fn transitive_incompatible_with_transitive() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-ec82e315", "albatross"));
filters.push((r"b-ec82e315", "bluebird"));
filters.push((r"c-ec82e315", "crow"));
filters.push((r"-ec82e315", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-ec82e315")
.arg("b-ec82e315")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only bluebird==1.0.0 is available and bluebird==1.0.0 depends on crow==2.0.0, we can conclude that all versions of bluebird depend on crow==2.0.0.
And because albatross==1.0.0 depends on crow==1.0.0 and only albatross==1.0.0 is available, we can conclude that all versions of bluebird and all versions of albatross are incompatible.
And because you require bluebird and you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_ec82e315", &context.temp_dir);
assert_not_installed(&context.venv, "b_ec82e315", &context.temp_dir);
}
/// package-only-prereleases
///
/// The user requires any version of package `a` which only has prerelease versions
/// available.
///
/// ```text
/// 472fcc7e
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── unsatisfied: no matching version
/// └── a
/// └── a-1.0.0a1
/// ```
#[test]
fn package_only_prereleases() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-472fcc7e", "albatross"));
filters.push((r"-472fcc7e", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-472fcc7e")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0a1
"###);
// Since there are only prerelease versions of `a` available, it should be
// installed even though the user did not include a prerelease specifier.
assert_installed(&context.venv, "a_472fcc7e", "1.0.0a1", &context.temp_dir);
}
/// package-only-prereleases-in-range
///
/// The user requires a version of package `a` which only matches prerelease
/// versions but they did not include a prerelease specifier.
///
/// ```text
/// 1017748b
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>0.1.0
/// │ └── unsatisfied: no matching version
/// └── a
/// ├── a-0.1.0
/// └── a-1.0.0a1
/// ```
#[test]
fn package_only_prereleases_in_range() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-1017748b", "albatross"));
filters.push((r"-1017748b", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-1017748b>0.1.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross<=0.1.0 is available and you require albatross>0.1.0, we can conclude that the requirements are unsatisfiable.
hint: Pre-releases are available for albatross in the requested range (e.g., 1.0.0a1), but pre-releases weren't enabled (try: `--prerelease=allow`)
"###);
// Since there are stable versions of `a` available, prerelease versions should not
// be selected without explicit opt-in.
assert_not_installed(&context.venv, "a_1017748b", &context.temp_dir);
}
/// requires-package-only-prereleases-in-range-global-opt-in
///
/// The user requires a version of package `a` which only matches prerelease
/// versions. They did not include a prerelease specifier for the package, but they
/// opted into prereleases globally.
///
/// ```text
/// 95140069
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>0.1.0
/// │ └── unsatisfied: no matching version
/// └── a
/// ├── a-0.1.0
/// └── a-1.0.0a1
/// ```
#[test]
fn requires_package_only_prereleases_in_range_global_opt_in() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-95140069", "albatross"));
filters.push((r"-95140069", ""));
puffin_snapshot!(filters, command(&context)
.arg("--prerelease=allow")
.arg("a-95140069>0.1.0")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0a1
"###);
assert_installed(&context.venv, "a_95140069", "1.0.0a1", &context.temp_dir);
}
/// requires-package-prerelease-and-final-any
///
/// The user requires any version of package `a` has a prerelease version available
/// and an older non-prerelease version.
///
/// ```text
/// 909975d8
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-0.1.0
/// └── a
/// ├── a-0.1.0
/// └── a-1.0.0a1
/// ```
#[test]
fn requires_package_prerelease_and_final_any() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-909975d8", "albatross"));
filters.push((r"-909975d8", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-909975d8")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==0.1.0
"###);
// Since the user did not provide a prerelease specifier, the older stable version
// should be selected.
assert_installed(&context.venv, "a_909975d8", "0.1.0", &context.temp_dir);
}
/// package-prerelease-specified-only-final-available
///
/// The user requires a version of `a` with a prerelease specifier and only stable
/// releases are available.
///
/// ```text
/// 6f8bea9f
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>=0.1.0a1
/// │ ├── satisfied by a-0.1.0
/// │ ├── satisfied by a-0.2.0
/// │ └── satisfied by a-0.3.0
/// └── a
/// ├── a-0.1.0
/// ├── a-0.2.0
/// └── a-0.3.0
/// ```
#[test]
fn package_prerelease_specified_only_final_available() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-6f8bea9f", "albatross"));
filters.push((r"-6f8bea9f", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-6f8bea9f>=0.1.0a1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==0.3.0
"###);
// The latest stable version should be selected.
assert_installed(&context.venv, "a_6f8bea9f", "0.3.0", &context.temp_dir);
}
/// package-prerelease-specified-only-prerelease-available
///
/// The user requires a version of `a` with a prerelease specifier and only
/// prerelease releases are available.
///
/// ```text
/// 48d4bba0
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>=0.1.0a1
/// │ ├── satisfied by a-0.1.0a1
/// │ ├── satisfied by a-0.2.0a1
/// │ └── satisfied by a-0.3.0a1
/// └── a
/// ├── a-0.1.0a1
/// ├── a-0.2.0a1
/// └── a-0.3.0a1
/// ```
#[test]
fn package_prerelease_specified_only_prerelease_available() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-48d4bba0", "albatross"));
filters.push((r"-48d4bba0", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-48d4bba0>=0.1.0a1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==0.3.0a1
"###);
// The latest prerelease version should be selected.
assert_installed(&context.venv, "a_48d4bba0", "0.3.0a1", &context.temp_dir);
}
/// package-prerelease-specified-mixed-available
///
/// The user requires a version of `a` with a prerelease specifier and both
/// prerelease and stable releases are available.
///
/// ```text
/// 2b1193a7
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>=0.1.0a1
/// │ ├── satisfied by a-0.1.0
/// │ ├── satisfied by a-0.2.0a1
/// │ ├── satisfied by a-0.3.0
/// │ └── satisfied by a-1.0.0a1
/// └── a
/// ├── a-0.1.0
/// ├── a-0.2.0a1
/// ├── a-0.3.0
/// └── a-1.0.0a1
/// ```
#[test]
fn package_prerelease_specified_mixed_available() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-2b1193a7", "albatross"));
filters.push((r"-2b1193a7", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-2b1193a7>=0.1.0a1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0a1
"###);
// Since the user provided a prerelease specifier, the latest prerelease version
// should be selected.
assert_installed(&context.venv, "a_2b1193a7", "1.0.0a1", &context.temp_dir);
}
/// package-multiple-prereleases-kinds
///
/// The user requires `a` which has multiple prereleases available with different
/// labels.
///
/// ```text
/// 72919cf7
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>=1.0.0a1
/// │ ├── satisfied by a-1.0.0a1
/// │ ├── satisfied by a-1.0.0b1
/// │ └── satisfied by a-1.0.0rc1
/// └── a
/// ├── a-1.0.0a1
/// ├── a-1.0.0b1
/// └── a-1.0.0rc1
/// ```
#[test]
fn package_multiple_prereleases_kinds() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-72919cf7", "albatross"));
filters.push((r"-72919cf7", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-72919cf7>=1.0.0a1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0rc1
"###);
// Release candidates should be the highest precedence prerelease kind.
assert_installed(&context.venv, "a_72919cf7", "1.0.0rc1", &context.temp_dir);
}
/// package-multiple-prereleases-numbers
///
/// The user requires `a` which has multiple alphas available.
///
/// ```text
/// cecdb92d
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>=1.0.0a1
/// │ ├── satisfied by a-1.0.0a1
/// │ ├── satisfied by a-1.0.0a2
/// │ └── satisfied by a-1.0.0a3
/// └── a
/// ├── a-1.0.0a1
/// ├── a-1.0.0a2
/// └── a-1.0.0a3
/// ```
#[test]
fn package_multiple_prereleases_numbers() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-cecdb92d", "albatross"));
filters.push((r"-cecdb92d", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-cecdb92d>=1.0.0a1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0a3
"###);
// The latest alpha version should be selected.
assert_installed(&context.venv, "a_cecdb92d", "1.0.0a3", &context.temp_dir);
}
/// transitive-package-only-prereleases
///
/// The user requires any version of package `a` which requires `b` which only has
/// prerelease versions available.
///
/// ```text
/// e3c94488
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-0.1.0
/// ├── a
/// │ └── a-0.1.0
/// │ └── requires b
/// │ └── unsatisfied: no matching version
/// └── b
/// └── b-1.0.0a1
/// ```
#[test]
fn transitive_package_only_prereleases() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-e3c94488", "albatross"));
filters.push((r"b-e3c94488", "bluebird"));
filters.push((r"-e3c94488", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-e3c94488")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Downloaded 2 packages in [TIME]
Installed 2 packages in [TIME]
+ albatross==0.1.0
+ bluebird==1.0.0a1
"###);
// Since there are only prerelease versions of `b` available, it should be selected
// even though the user did not opt-in to prereleases.
assert_installed(&context.venv, "a_e3c94488", "0.1.0", &context.temp_dir);
assert_installed(&context.venv, "b_e3c94488", "1.0.0a1", &context.temp_dir);
}
/// transitive-package-only-prereleases-in-range
///
/// The user requires package `a` which has a dependency on a package which only
/// matches prerelease versions but they did not include a prerelease specifier.
///
/// ```text
/// 20238f1b
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-0.1.0
/// ├── a
/// │ └── a-0.1.0
/// │ └── requires b>0.1
/// │ └── unsatisfied: no matching version
/// └── b
/// ├── b-0.1.0
/// └── b-1.0.0a1
/// ```
#[test]
fn transitive_package_only_prereleases_in_range() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-20238f1b", "albatross"));
filters.push((r"b-20238f1b", "bluebird"));
filters.push((r"-20238f1b", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-20238f1b")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only bluebird<=0.1 is available and albatross==0.1.0 depends on bluebird>0.1, we can conclude that albatross==0.1.0 cannot be used.
And because only albatross==0.1.0 is available and you require albatross, we can conclude that the requirements are unsatisfiable.
hint: Pre-releases are available for bluebird in the requested range (e.g., 1.0.0a1), but pre-releases weren't enabled (try: `--prerelease=allow`)
"###);
// Since there are stable versions of `b` available, the prerelease version should
// not be selected without explicit opt-in. The available version is excluded by
// the range requested by the user.
assert_not_installed(&context.venv, "a_20238f1b", &context.temp_dir);
}
/// transitive-package-only-prereleases-in-range-opt-in
///
/// The user requires package `a` which has a dependency on a package which only
/// matches prerelease versions; the user has opted into allowing prereleases in `b`
/// explicitly.
///
/// ```text
/// d65d5fdf
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-0.1.0
/// │ └── requires b>0.0.0a1
/// │ └── satisfied by b-0.1.0
/// ├── a
/// │ └── a-0.1.0
/// │ └── requires b>0.1
/// │ └── unsatisfied: no matching version
/// └── b
/// ├── b-0.1.0
/// └── b-1.0.0a1
/// ```
#[test]
fn transitive_package_only_prereleases_in_range_opt_in() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-d65d5fdf", "albatross"));
filters.push((r"b-d65d5fdf", "bluebird"));
filters.push((r"-d65d5fdf", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-d65d5fdf")
.arg("b-d65d5fdf>0.0.0a1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Downloaded 2 packages in [TIME]
Installed 2 packages in [TIME]
+ albatross==0.1.0
+ bluebird==1.0.0a1
"###);
// Since the user included a dependency on `b` with a prerelease specifier, a
// prerelease version can be selected.
assert_installed(&context.venv, "a_d65d5fdf", "0.1.0", &context.temp_dir);
assert_installed(&context.venv, "b_d65d5fdf", "1.0.0a1", &context.temp_dir);
}
/// transitive-prerelease-and-stable-dependency
///
/// A transitive dependency has both a prerelease and a stable selector, but can
/// only be satisfied by a prerelease
///
/// ```text
/// d62255d0
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c==2.0.0b1
/// │ └── satisfied by c-2.0.0b1
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c<=3.0.0,>=1.0.0
/// │ └── satisfied by c-1.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0b1
/// ```
#[test]
fn transitive_prerelease_and_stable_dependency() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-d62255d0", "albatross"));
filters.push((r"b-d62255d0", "bluebird"));
filters.push((r"c-d62255d0", "crow"));
filters.push((r"-d62255d0", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-d62255d0")
.arg("b-d62255d0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because there is no version of crow==2.0.0b1 and albatross==1.0.0 depends on crow==2.0.0b1, we can conclude that albatross==1.0.0 cannot be used.
And because only albatross==1.0.0 is available and you require albatross, we can conclude that the requirements are unsatisfiable.
hint: crow was requested with a pre-release marker (e.g., crow==2.0.0b1), but pre-releases weren't enabled (try: `--prerelease=allow`)
"###);
// Since the user did not explicitly opt-in to a prerelease, it cannot be selected.
assert_not_installed(&context.venv, "a_d62255d0", &context.temp_dir);
assert_not_installed(&context.venv, "b_d62255d0", &context.temp_dir);
}
/// transitive-prerelease-and-stable-dependency-opt-in
///
/// A transitive dependency has both a prerelease and a stable selector, but can
/// only be satisfied by a prerelease. The user includes an opt-in to prereleases of
/// the transitive dependency.
///
/// ```text
/// 0778b0eb
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ ├── requires b
/// │ │ └── satisfied by b-1.0.0
/// │ └── requires c>=0.0.0a1
/// │ ├── satisfied by c-1.0.0
/// │ └── satisfied by c-2.0.0b1
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c==2.0.0b1
/// │ └── satisfied by c-2.0.0b1
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c<=3.0.0,>=1.0.0
/// │ └── satisfied by c-1.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0b1
/// ```
#[test]
fn transitive_prerelease_and_stable_dependency_opt_in() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-0778b0eb", "albatross"));
filters.push((r"b-0778b0eb", "bluebird"));
filters.push((r"c-0778b0eb", "crow"));
filters.push((r"-0778b0eb", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-0778b0eb")
.arg("b-0778b0eb")
.arg("c-0778b0eb>=0.0.0a1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Downloaded 3 packages in [TIME]
Installed 3 packages in [TIME]
+ albatross==1.0.0
+ bluebird==1.0.0
+ crow==2.0.0b1
"###);
// Since the user explicitly opted-in to a prerelease for `c`, it can be installed.
assert_installed(&context.venv, "a_0778b0eb", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "b_0778b0eb", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "c_0778b0eb", "2.0.0b1", &context.temp_dir);
}
/// transitive-prerelease-and-stable-dependency-many-versions
///
/// A transitive dependency has both a prerelease and a stable selector, but can
/// only be satisfied by a prerelease. There are many prerelease versions.
///
/// ```text
/// cc6a6eac
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c>=2.0.0b1
/// │ ├── satisfied by c-2.0.0b1
/// │ ├── satisfied by c-2.0.0b2
/// │ ├── satisfied by c-2.0.0b3
/// │ ├── satisfied by c-2.0.0b4
/// │ ├── satisfied by c-2.0.0b5
/// │ ├── satisfied by c-2.0.0b6
/// │ ├── satisfied by c-2.0.0b7
/// │ ├── satisfied by c-2.0.0b8
/// │ └── satisfied by c-2.0.0b9
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c<=3.0.0,>=1.0.0
/// │ └── satisfied by c-1.0.0
/// └── c
/// ├── c-1.0.0
/// ├── c-2.0.0a1
/// ├── c-2.0.0a2
/// ├── c-2.0.0a3
/// ├── c-2.0.0a4
/// ├── c-2.0.0a5
/// ├── c-2.0.0a6
/// ├── c-2.0.0a7
/// ├── c-2.0.0a8
/// ├── c-2.0.0a9
/// ├── c-2.0.0b1
/// ├── c-2.0.0b2
/// ├── c-2.0.0b3
/// ├── c-2.0.0b4
/// ├── c-2.0.0b5
/// ├── c-2.0.0b6
/// ├── c-2.0.0b7
/// ├── c-2.0.0b8
/// └── c-2.0.0b9
/// ```
#[test]
fn transitive_prerelease_and_stable_dependency_many_versions() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-cc6a6eac", "albatross"));
filters.push((r"b-cc6a6eac", "bluebird"));
filters.push((r"c-cc6a6eac", "crow"));
filters.push((r"-cc6a6eac", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-cc6a6eac")
.arg("b-cc6a6eac")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only bluebird==1.0.0 is available and bluebird==1.0.0 depends on crow, we can conclude that all versions of bluebird depend on crow.
And because only crow<2.0.0b1 is available, we can conclude that all versions of bluebird depend on crow<2.0.0b1.
And because albatross==1.0.0 depends on crow>=2.0.0b1 and only albatross==1.0.0 is available, we can conclude that all versions of bluebird and all versions of albatross are incompatible.
And because you require bluebird and you require albatross, we can conclude that the requirements are unsatisfiable.
hint: crow was requested with a pre-release marker (e.g., crow>=2.0.0b1), but pre-releases weren't enabled (try: `--prerelease=allow`)
"###);
// Since the user did not explicitly opt-in to a prerelease, it cannot be selected.
assert_not_installed(&context.venv, "a_cc6a6eac", &context.temp_dir);
assert_not_installed(&context.venv, "b_cc6a6eac", &context.temp_dir);
}
/// transitive-prerelease-and-stable-dependency-many-versions-holes
///
/// A transitive dependency has both a prerelease and a stable selector, but can
/// only be satisfied by a prerelease. There are many prerelease versions and some
/// are excluded.
///
/// ```text
/// 041e36bc
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c!=2.0.0a5,!=2.0.0a6,!=2.0.0a7,!=2.0.0b1,<2.0.0b5,>1.0.0
/// │ └── unsatisfied: no matching version
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c<=3.0.0,>=1.0.0
/// │ └── satisfied by c-1.0.0
/// └── c
/// ├── c-1.0.0
/// ├── c-2.0.0a1
/// ├── c-2.0.0a2
/// ├── c-2.0.0a3
/// ├── c-2.0.0a4
/// ├── c-2.0.0a5
/// ├── c-2.0.0a6
/// ├── c-2.0.0a7
/// ├── c-2.0.0a8
/// ├── c-2.0.0a9
/// ├── c-2.0.0b1
/// ├── c-2.0.0b2
/// ├── c-2.0.0b3
/// ├── c-2.0.0b4
/// ├── c-2.0.0b5
/// ├── c-2.0.0b6
/// ├── c-2.0.0b7
/// ├── c-2.0.0b8
/// └── c-2.0.0b9
/// ```
#[test]
fn transitive_prerelease_and_stable_dependency_many_versions_holes() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-041e36bc", "albatross"));
filters.push((r"b-041e36bc", "bluebird"));
filters.push((r"c-041e36bc", "crow"));
filters.push((r"-041e36bc", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-041e36bc")
.arg("b-041e36bc")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of crow are available:
crow<=1.0.0
crow>=2.0.0a5,<=2.0.0a7
crow==2.0.0b1
crow>=2.0.0b5
and albatross==1.0.0 depends on one of:
crow>1.0.0,<2.0.0a5
crow>2.0.0a7,<2.0.0b1
crow>2.0.0b1,<2.0.0b5
we can conclude that albatross==1.0.0 cannot be used.
And because only albatross==1.0.0 is available and you require albatross, we can conclude that the requirements are unsatisfiable.
hint: crow was requested with a pre-release marker (e.g., any of:
crow>1.0.0,<2.0.0a5
crow>2.0.0a7,<2.0.0b1
crow>2.0.0b1,<2.0.0b5
), but pre-releases weren't enabled (try: `--prerelease=allow`)
"###);
// Since the user did not explicitly opt-in to a prerelease, it cannot be selected.
assert_not_installed(&context.venv, "a_041e36bc", &context.temp_dir);
assert_not_installed(&context.venv, "b_041e36bc", &context.temp_dir);
}
/// requires-python-version-does-not-exist
///
/// The user requires a package which requires a Python version that does not exist
///
/// ```text
/// 4486c0e5
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// └── requires python>=4.0 (incompatible with environment)
/// ```
#[test]
fn requires_python_version_does_not_exist() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-4486c0e5", "albatross"));
filters.push((r"-4486c0e5", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-4486c0e5==1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because the current Python version (3.8.18) does not satisfy Python>=4.0 and albatross==1.0.0 depends on Python>=4.0, we can conclude that albatross==1.0.0 cannot be used.
And because you require albatross==1.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_4486c0e5", &context.temp_dir);
}
/// requires-python-version-less-than-current
///
/// The user requires a package which requires a Python version less than the
/// current version
///
/// ```text
/// d4ea58de
/// ├── environment
/// │ └── python3.9
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// └── requires python<=3.8 (incompatible with environment)
/// ```
#[test]
fn requires_python_version_less_than_current() {
let context = TestContext::new("3.9");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-d4ea58de", "albatross"));
filters.push((r"-d4ea58de", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-d4ea58de==1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because the current Python version (3.9.18) does not satisfy Python<=3.8 and albatross==1.0.0 depends on Python<=3.8, we can conclude that albatross==1.0.0 cannot be used.
And because you require albatross==1.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_d4ea58de", &context.temp_dir);
}
/// requires-python-version-greater-than-current
///
/// The user requires a package which requires a Python version greater than the
/// current version
///
/// ```text
/// 741c8854
/// ├── environment
/// │ └── python3.9
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// └── requires python>=3.10 (incompatible with environment)
/// ```
#[test]
fn requires_python_version_greater_than_current() {
let context = TestContext::new("3.9");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-741c8854", "albatross"));
filters.push((r"-741c8854", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-741c8854==1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because the current Python version (3.9.18) does not satisfy Python>=3.10 and albatross==1.0.0 depends on Python>=3.10, we can conclude that albatross==1.0.0 cannot be used.
And because you require albatross==1.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_741c8854", &context.temp_dir);
}
/// requires-python-version-greater-than-current-patch
///
/// The user requires a package which requires a Python version with a patch version
/// greater than the current patch version
///
/// ```text
/// 0044ac94
/// ├── environment
/// │ └── python3.8.12
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// └── requires python>=3.8.14 (incompatible with environment)
/// ```
#[test]
fn requires_python_version_greater_than_current_patch() {
let context = TestContext::new("3.8.12");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-0044ac94", "albatross"));
filters.push((r"-0044ac94", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-0044ac94==1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because the current Python version (3.8.12) does not satisfy Python>=3.8.14 and albatross==1.0.0 depends on Python>=3.8.14, we can conclude that albatross==1.0.0 cannot be used.
And because you require albatross==1.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_0044ac94", &context.temp_dir);
}
/// requires-python-version-greater-than-current-many
///
/// The user requires a package which has many versions which all require a Python
/// version greater than the current version
///
/// ```text
/// da5bd150
/// ├── environment
/// │ └── python3.9
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── unsatisfied: no matching version
/// └── a
/// ├── a-2.0.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-2.1.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-2.2.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-2.3.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-2.4.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-2.5.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-3.0.0
/// │ └── requires python>=3.11 (incompatible with environment)
/// ├── a-3.1.0
/// │ └── requires python>=3.11 (incompatible with environment)
/// ├── a-3.2.0
/// │ └── requires python>=3.11 (incompatible with environment)
/// ├── a-3.3.0
/// │ └── requires python>=3.11 (incompatible with environment)
/// ├── a-3.4.0
/// │ └── requires python>=3.11 (incompatible with environment)
/// └── a-3.5.0
/// └── requires python>=3.11 (incompatible with environment)
/// ```
#[test]
fn requires_python_version_greater_than_current_many() {
let context = TestContext::new("3.9");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-da5bd150", "albatross"));
filters.push((r"-da5bd150", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-da5bd150==1.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because there is no version of albatross==1.0.0 and you require albatross==1.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_da5bd150", &context.temp_dir);
}
/// requires-python-version-greater-than-current-backtrack
///
/// The user requires a package where recent versions require a Python version
/// greater than the current version, but an older version is compatible.
///
/// ```text
/// 3204bc0a
/// ├── environment
/// │ └── python3.9
/// ├── root
/// │ └── requires a
/// │ ├── satisfied by a-1.0.0
/// │ ├── satisfied by a-2.0.0
/// │ ├── satisfied by a-3.0.0
/// │ └── satisfied by a-4.0.0
/// └── a
/// ├── a-1.0.0
/// ├── a-2.0.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-3.0.0
/// │ └── requires python>=3.11 (incompatible with environment)
/// └── a-4.0.0
/// └── requires python>=3.12 (incompatible with environment)
/// ```
#[test]
fn requires_python_version_greater_than_current_backtrack() {
let context = TestContext::new("3.9");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-3204bc0a", "albatross"));
filters.push((r"-3204bc0a", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-3204bc0a")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
assert_installed(&context.venv, "a_3204bc0a", "1.0.0", &context.temp_dir);
}
/// requires-python-version-greater-than-current-excluded
///
/// The user requires a package where recent versions require a Python version
/// greater than the current version, but an excluded older version is compatible.
///
/// ```text
/// 874cae6d
/// ├── environment
/// │ └── python3.9
/// ├── root
/// │ └── requires a>=2.0.0
/// │ ├── satisfied by a-2.0.0
/// │ ├── satisfied by a-3.0.0
/// │ └── satisfied by a-4.0.0
/// └── a
/// ├── a-1.0.0
/// ├── a-2.0.0
/// │ └── requires python>=3.10 (incompatible with environment)
/// ├── a-3.0.0
/// │ └── requires python>=3.11 (incompatible with environment)
/// └── a-4.0.0
/// └── requires python>=3.12 (incompatible with environment)
/// ```
#[test]
fn requires_python_version_greater_than_current_excluded() {
let context = TestContext::new("3.9");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-874cae6d", "albatross"));
filters.push((r"-874cae6d", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-874cae6d>=2.0.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because the current Python version (3.9.18) does not satisfy Python>=3.10,<3.11 and the current Python version (3.9.18) does not satisfy Python>=3.12, we can conclude that any of:
Python>=3.10,<3.11
Python>=3.12
are incompatible.
And because the current Python version (3.9.18) does not satisfy Python>=3.11,<3.12, we can conclude that Python>=3.10 are incompatible.
And because albatross==2.0.0 depends on Python>=3.10 and only the following versions of albatross are available:
albatross<=2.0.0
albatross==3.0.0
albatross==4.0.0
we can conclude that albatross>=2.0.0,<3.0.0 cannot be used. (1)
Because the current Python version (3.9.18) does not satisfy Python>=3.11,<3.12 and the current Python version (3.9.18) does not satisfy Python>=3.12, we can conclude that Python>=3.11 are incompatible.
And because albatross==3.0.0 depends on Python>=3.11, we can conclude that albatross==3.0.0 cannot be used.
And because we know from (1) that albatross>=2.0.0,<3.0.0 cannot be used, we can conclude that albatross>=2.0.0,<4.0.0 cannot be used. (2)
Because the current Python version (3.9.18) does not satisfy Python>=3.12 and albatross==4.0.0 depends on Python>=3.12, we can conclude that albatross==4.0.0 cannot be used.
And because we know from (2) that albatross>=2.0.0,<4.0.0 cannot be used, we can conclude that albatross>=2.0.0 cannot be used.
And because you require albatross>=2.0.0, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_874cae6d", &context.temp_dir);
}
/// specific-tag-and-default
///
/// A wheel for a specific platform is available alongside the default.
///
/// ```text
/// 8f7a81f1
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn specific_tag_and_default() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-8f7a81f1", "albatross"));
filters.push((r"-8f7a81f1", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-8f7a81f1")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
}
/// only-wheels
///
/// No source distributions are available, only wheels.
///
/// ```text
/// a874f41e
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn only_wheels() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-a874f41e", "albatross"));
filters.push((r"-a874f41e", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-a874f41e")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
}
/// no-wheels
///
/// No wheels are available, only source distributions.
///
/// ```text
/// 0278f343
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn no_wheels() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-0278f343", "albatross"));
filters.push((r"-0278f343", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-0278f343")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
}
/// no-wheels-with-matching-platform
///
/// No wheels with matching platform tags are available, just source distributions.
///
/// ```text
/// f1a1f15c
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn no_wheels_with_matching_platform() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-f1a1f15c", "albatross"));
filters.push((r"-f1a1f15c", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-f1a1f15c")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
}
/// no-sdist-no-wheels-with-matching-platform
///
/// No wheels with matching platform tags are available, nor are any source
/// distributions available
///
/// ```text
/// af6bcec1
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn no_sdist_no_wheels_with_matching_platform() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-af6bcec1", "albatross"));
filters.push((r"-af6bcec1", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-af6bcec1")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because there are no versions of albatross and you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_af6bcec1", &context.temp_dir);
}
/// no-wheels-no-build
///
/// No wheels are available, only source distributions but the user has disabled
/// builds.
///
/// ```text
/// 662cbd94
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn no_wheels_no_build() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-662cbd94", "albatross"));
filters.push((r"-662cbd94", ""));
puffin_snapshot!(filters, command(&context)
.arg("--only-binary")
.arg("a-662cbd94")
.arg("a-662cbd94")
, @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to download and build: albatross==1.0.0
Caused by: Building source distributions is disabled
"###);
assert_not_installed(&context.venv, "a_662cbd94", &context.temp_dir);
}
/// only-wheels-no-binary
///
/// No source distributions are available, only wheels but the user has disabled
/// using pre-built binaries.
///
/// ```text
/// dd137625
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn only_wheels_no_binary() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-dd137625", "albatross"));
filters.push((r"-dd137625", ""));
puffin_snapshot!(filters, command(&context)
.arg("--no-binary")
.arg("a-dd137625")
.arg("a-dd137625")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because there are no versions of albatross and you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
assert_not_installed(&context.venv, "a_dd137625", &context.temp_dir);
}
/// no-build
///
/// Both wheels and source distributions are available, and the user has disabled
/// builds.
///
/// ```text
/// 9ff1e173
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn no_build() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-9ff1e173", "albatross"));
filters.push((r"-9ff1e173", ""));
puffin_snapshot!(filters, command(&context)
.arg("--only-binary")
.arg("a-9ff1e173")
.arg("a-9ff1e173")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
// The wheel should be used for install
}
/// no-binary
///
/// Both wheels and source distributions are available, and the user has disabled
/// binaries.
///
/// ```text
/// 10e961b8
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn no_binary() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-10e961b8", "albatross"));
filters.push((r"-10e961b8", ""));
puffin_snapshot!(filters, command(&context)
.arg("--no-binary")
.arg("a-10e961b8")
.arg("a-10e961b8")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==1.0.0
"###);
// The source distribution should be used for install
}
/// package-only-yanked
///
/// The user requires any version of package `a` which only has yanked versions
/// available.
///
/// ```text
/// e3de7eb4
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── unsatisfied: no matching version
/// └── a
/// └── a-1.0.0 (yanked)
/// ```
#[test]
fn package_only_yanked() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-e3de7eb4", "albatross"));
filters.push((r"-e3de7eb4", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-e3de7eb4")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only albatross==1.0.0 is available and albatross==1.0.0 is unusable because it was yanked, we can conclude that all versions of albatross cannot be used.
And because you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
// Yanked versions should not be installed, even if they are the only one
// available.
assert_not_installed(&context.venv, "a_e3de7eb4", &context.temp_dir);
}
/// package-only-yanked-in-range
///
/// The user requires a version of package `a` which only matches yanked versions.
///
/// ```text
/// 84b3720e
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>0.1.0
/// │ └── unsatisfied: no matching version
/// └── a
/// ├── a-0.1.0
/// └── a-1.0.0 (yanked)
/// ```
#[test]
fn package_only_yanked_in_range() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-84b3720e", "albatross"));
filters.push((r"-84b3720e", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-84b3720e>0.1.0")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of albatross are available:
albatross<=0.1.0
albatross==1.0.0
and albatross==1.0.0 is unusable because it was yanked, we can conclude that albatross>0.1.0 cannot be used.
And because you require albatross>0.1.0, we can conclude that the requirements are unsatisfiable.
"###);
// Since there are other versions of `a` available, yanked versions should not be
// selected without explicit opt-in.
assert_not_installed(&context.venv, "a_84b3720e", &context.temp_dir);
}
/// requires-package-yanked-and-unyanked-any
///
/// The user requires any version of package `a` has a yanked version available and
/// an older unyanked version.
///
/// ```text
/// 93eac6d7
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-0.1.0
/// └── a
/// ├── a-0.1.0
/// └── a-1.0.0 (yanked)
/// ```
#[test]
fn requires_package_yanked_and_unyanked_any() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-93eac6d7", "albatross"));
filters.push((r"-93eac6d7", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-93eac6d7")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==0.1.0
"###);
// The unyanked version should be selected.
assert_installed(&context.venv, "a_93eac6d7", "0.1.0", &context.temp_dir);
}
/// package-yanked-specified-mixed-available
///
/// The user requires any version of `a` and both yanked and unyanked releases are
/// available.
///
/// ```text
/// 3325916e
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a>=0.1.0
/// │ ├── satisfied by a-0.1.0
/// │ └── satisfied by a-0.3.0
/// └── a
/// ├── a-0.1.0
/// ├── a-0.2.0 (yanked)
/// ├── a-0.3.0
/// └── a-1.0.0 (yanked)
/// ```
#[test]
fn package_yanked_specified_mixed_available() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-3325916e", "albatross"));
filters.push((r"-3325916e", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-3325916e>=0.1.0")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Downloaded 1 package in [TIME]
Installed 1 package in [TIME]
+ albatross==0.3.0
"###);
// The latest unyanked version should be selected.
assert_installed(&context.venv, "a_3325916e", "0.3.0", &context.temp_dir);
}
/// transitive-package-only-yanked
///
/// The user requires any version of package `a` which requires `b` which only has
/// yanked versions available.
///
/// ```text
/// 9ec30fe2
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-0.1.0
/// ├── a
/// │ └── a-0.1.0
/// │ └── requires b
/// │ └── unsatisfied: no matching version
/// └── b
/// └── b-1.0.0 (yanked)
/// ```
#[test]
fn transitive_package_only_yanked() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-9ec30fe2", "albatross"));
filters.push((r"b-9ec30fe2", "bluebird"));
filters.push((r"-9ec30fe2", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-9ec30fe2")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only bluebird==1.0.0 is available and bluebird==1.0.0 is unusable because it was yanked, we can conclude that all versions of bluebird cannot be used.
And because albatross==0.1.0 depends on bluebird, we can conclude that albatross==0.1.0 cannot be used.
And because only albatross==0.1.0 is available and you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
// Yanked versions should not be installed, even if they are the only one
// available.
assert_not_installed(&context.venv, "a_9ec30fe2", &context.temp_dir);
}
/// transitive-package-only-yanked-in-range
///
/// The user requires package `a` which has a dependency on a package which only
/// matches yanked versions.
///
/// ```text
/// 872d714e
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-0.1.0
/// ├── a
/// │ └── a-0.1.0
/// │ └── requires b>0.1
/// │ └── unsatisfied: no matching version
/// └── b
/// ├── b-0.1.0
/// └── b-1.0.0 (yanked)
/// ```
#[test]
fn transitive_package_only_yanked_in_range() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-872d714e", "albatross"));
filters.push((r"b-872d714e", "bluebird"));
filters.push((r"-872d714e", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-872d714e")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of bluebird are available:
bluebird<=0.1
bluebird==1.0.0
and bluebird==1.0.0 is unusable because it was yanked, we can conclude that bluebird>0.1 cannot be used.
And because albatross==0.1.0 depends on bluebird>0.1, we can conclude that albatross==0.1.0 cannot be used.
And because only albatross==0.1.0 is available and you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
// Yanked versions should not be installed, even if they are the only valid version
// in a range.
assert_not_installed(&context.venv, "a_872d714e", &context.temp_dir);
}
/// transitive-package-only-yanked-in-range-opt-in
///
/// The user requires package `a` which has a dependency on a package which only
/// matches yanked versions; the user has opted into allowing the yanked version of
/// `b` explicitly.
///
/// ```text
/// 1bbd5d1b
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-0.1.0
/// │ └── requires b==1.0.0
/// │ └── unsatisfied: no matching version
/// ├── a
/// │ └── a-0.1.0
/// │ └── requires b>0.1
/// │ └── unsatisfied: no matching version
/// └── b
/// ├── b-0.1.0
/// └── b-1.0.0 (yanked)
/// ```
#[test]
fn transitive_package_only_yanked_in_range_opt_in() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-1bbd5d1b", "albatross"));
filters.push((r"b-1bbd5d1b", "bluebird"));
filters.push((r"-1bbd5d1b", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-1bbd5d1b")
.arg("b-1bbd5d1b==1.0.0")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
warning: bluebird==1.0.0 is yanked.
Downloaded 2 packages in [TIME]
Installed 2 packages in [TIME]
+ albatross==0.1.0
+ bluebird==1.0.0
"###);
// Since the user included a dependency on `b` with an exact specifier, the yanked
// version can be selected.
assert_installed(&context.venv, "a_1bbd5d1b", "0.1.0", &context.temp_dir);
assert_installed(&context.venv, "b_1bbd5d1b", "1.0.0", &context.temp_dir);
}
/// transitive-yanked-and-unyanked-dependency
///
/// A transitive dependency has both a yanked and an unyanked version, but can only
/// be satisfied by a yanked version
///
/// ```text
/// eb1ba5f5
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c==2.0.0
/// │ └── unsatisfied: no matching version
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c<=3.0.0,>=1.0.0
/// │ └── satisfied by c-1.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0 (yanked)
/// ```
#[test]
fn transitive_yanked_and_unyanked_dependency() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-eb1ba5f5", "albatross"));
filters.push((r"b-eb1ba5f5", "bluebird"));
filters.push((r"c-eb1ba5f5", "crow"));
filters.push((r"-eb1ba5f5", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-eb1ba5f5")
.arg("b-eb1ba5f5")
, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because crow==2.0.0 is unusable because it was yanked and albatross==1.0.0 depends on crow==2.0.0, we can conclude that albatross==1.0.0 cannot be used.
And because only albatross==1.0.0 is available and you require albatross, we can conclude that the requirements are unsatisfiable.
"###);
// Since the user did not explicitly select the yanked version, it cannot be used.
assert_not_installed(&context.venv, "a_eb1ba5f5", &context.temp_dir);
assert_not_installed(&context.venv, "b_eb1ba5f5", &context.temp_dir);
}
/// transitive-yanked-and-unyanked-dependency-opt-in
///
/// A transitive dependency has both a yanked and an unyanked version, but can only
/// be satisfied by a yanked. The user includes an opt-in to the yanked version of
/// the transitive dependency.
///
/// ```text
/// f0760ee9
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ └── satisfied by a-1.0.0
/// │ ├── requires b
/// │ │ └── satisfied by b-1.0.0
/// │ └── requires c==2.0.0
/// │ └── unsatisfied: no matching version
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c==2.0.0
/// │ └── unsatisfied: no matching version
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c<=3.0.0,>=1.0.0
/// │ └── satisfied by c-1.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0 (yanked)
/// ```
#[test]
fn transitive_yanked_and_unyanked_dependency_opt_in() {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for more realistic messages
let mut filters = INSTA_FILTERS.to_vec();
filters.push((r"a-f0760ee9", "albatross"));
filters.push((r"b-f0760ee9", "bluebird"));
filters.push((r"c-f0760ee9", "crow"));
filters.push((r"-f0760ee9", ""));
puffin_snapshot!(filters, command(&context)
.arg("a-f0760ee9")
.arg("b-f0760ee9")
.arg("c-f0760ee9==2.0.0")
, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
warning: crow==2.0.0 is yanked.
Downloaded 3 packages in [TIME]
Installed 3 packages in [TIME]
+ albatross==1.0.0
+ bluebird==1.0.0
+ crow==2.0.0
"###);
// Since the user explicitly selected the yanked version of `c`, it can be
// installed.
assert_installed(&context.venv, "a_f0760ee9", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "b_f0760ee9", "1.0.0", &context.temp_dir);
assert_installed(&context.venv, "c_f0760ee9", "2.0.0", &context.temp_dir);
}