from typing import Iterable from tests.lib import PipTestEnvironment, create_test_package_with_setup def assert_contains_expected_lines(string: str, expected_lines: Iterable[str]) -> None: for expected_line in expected_lines: assert (expected_line + "\n") in string def test_check_install_canonicalization(script: PipTestEnvironment) -> None: pkga_path = create_test_package_with_setup( script, name="pkgA", version="1.0", install_requires=["normal-missing", "SPECIAL.missing"], ) normal_path = create_test_package_with_setup( script, name="normal-missing", version="0.1", ) special_path = create_test_package_with_setup( script, name="SPECIAL.missing", version="0.1", ) # Let's install pkgA without its dependency result = script.pip("install", "--no-index", pkga_path, "--no-deps") assert "Successfully installed pkgA-1.0" in result.stdout, str(result) # Install the first missing dependency. Only an error for the # second dependency should remain. result = script.pip( "install", "--no-index", normal_path, "--quiet", allow_stderr_error=True, ) expected_lines = [ "pkga 1.0 requires SPECIAL.missing, which is not installed.", ] # Deprecated python versions produce an extra warning on stderr assert_contains_expected_lines(result.stderr, expected_lines) assert result.returncode == 0 # Install the second missing package and expect that there is no warning # during the installation. This is special as the package name requires # name normalization (as in https://github.com/pypa/pip/issues/5134) result = script.pip( "install", "--no-index", special_path, "--quiet", ) assert "requires" not in result.stderr assert result.returncode == 0 # Double check that all errors are resolved in the end result = script.pip("check") expected_lines = [ "No broken requirements found.", ] assert_contains_expected_lines(result.stdout, expected_lines) assert result.returncode == 0 def test_check_install_does_not_warn_for_out_of_graph_issues( script: PipTestEnvironment, ) -> None: pkg_broken_path = create_test_package_with_setup( script, name="broken", version="1.0", install_requires=["missing", "conflict < 1.0"], ) pkg_unrelated_path = create_test_package_with_setup( script, name="unrelated", version="1.0", ) pkg_conflict_path = create_test_package_with_setup( script, name="conflict", version="1.0", ) # Install a package without it's dependencies result = script.pip("install", "--no-index", pkg_broken_path, "--no-deps") assert "requires" not in result.stderr # Install conflict package result = script.pip( "install", "--no-index", pkg_conflict_path, allow_stderr_error=True, ) assert_contains_expected_lines( result.stderr, [ "broken 1.0 requires missing, which is not installed.", "broken 1.0 requires conflict<1.0, " "but you have conflict 1.0 which is incompatible.", ], ) # Install unrelated package result = script.pip( "install", "--no-index", pkg_unrelated_path, "--quiet", ) # should not warn about broken's deps when installing unrelated package assert "requires" not in result.stderr result = script.pip("check", expect_error=True) expected_lines = [ "broken 1.0 requires missing, which is not installed.", "broken 1.0 has requirement conflict<1.0, but you have conflict 1.0.", ] assert_contains_expected_lines(result.stdout, expected_lines)