mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
265 lines
7.4 KiB
Python
265 lines
7.4 KiB
Python
import re
|
|
import textwrap
|
|
from os.path import join
|
|
|
|
import pytest
|
|
|
|
from tests.lib import (
|
|
PipTestEnvironment,
|
|
ResolverVariant,
|
|
TestData,
|
|
create_basic_wheel_for_package,
|
|
)
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_simple_extras_install_from_pypi(script: PipTestEnvironment) -> None:
|
|
"""
|
|
Test installing a package from PyPI using extras dependency Paste[openid].
|
|
"""
|
|
result = script.pip(
|
|
"install",
|
|
"Paste[openid]==1.7.5.1",
|
|
expect_stderr=True,
|
|
)
|
|
initools_folder = script.site_packages / "openid"
|
|
result.did_create(initools_folder)
|
|
|
|
|
|
def test_extras_after_wheel(script: PipTestEnvironment, data: TestData) -> None:
|
|
"""
|
|
Test installing a package with extras after installing from a wheel.
|
|
"""
|
|
simple = script.site_packages / "simple"
|
|
|
|
no_extra = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"requires_simple_extra",
|
|
expect_stderr=True,
|
|
)
|
|
no_extra.did_not_create(simple)
|
|
|
|
extra = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"requires_simple_extra[extra]",
|
|
expect_stderr=True,
|
|
)
|
|
extra.did_create(simple)
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_no_extras_uninstall(script: PipTestEnvironment) -> None:
|
|
"""
|
|
No extras dependency gets uninstalled when the root package is uninstalled
|
|
"""
|
|
result = script.pip(
|
|
"install",
|
|
"Paste[openid]==1.7.5.1",
|
|
expect_stderr=True,
|
|
)
|
|
result.did_create(join(script.site_packages, "paste"))
|
|
result.did_create(join(script.site_packages, "openid"))
|
|
result2 = script.pip("uninstall", "Paste", "-y")
|
|
# openid should not be uninstalled
|
|
initools_folder = script.site_packages / "openid"
|
|
assert initools_folder not in result2.files_deleted, result.files_deleted
|
|
|
|
|
|
def test_nonexistent_extra_warns_user_no_wheel(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
A warning is logged telling the user that the extra option they requested
|
|
does not exist in the project they are wishing to install.
|
|
|
|
This exercises source installs.
|
|
"""
|
|
result = script.pip(
|
|
"install",
|
|
"--no-binary=:all:",
|
|
"--no-index",
|
|
"--find-links=" + data.find_links,
|
|
"simple[nonexistent]",
|
|
expect_stderr=True,
|
|
)
|
|
assert "simple 3.0 does not provide the extra 'nonexistent'" in result.stderr, str(
|
|
result
|
|
)
|
|
|
|
|
|
def test_nonexistent_extra_warns_user_with_wheel(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
A warning is logged telling the user that the extra option they requested
|
|
does not exist in the project they are wishing to install.
|
|
|
|
This exercises wheel installs.
|
|
"""
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"--find-links=" + data.find_links,
|
|
"simplewheel[nonexistent]",
|
|
expect_stderr=True,
|
|
)
|
|
assert "simplewheel 2.0 does not provide the extra 'nonexistent'" in result.stderr
|
|
|
|
|
|
def test_nonexistent_options_listed_in_order(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Warn the user for each extra that doesn't exist.
|
|
"""
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"--find-links=" + data.find_links,
|
|
"simplewheel[nonexistent, nope]",
|
|
expect_stderr=True,
|
|
)
|
|
matches = re.findall(
|
|
"WARNING: simplewheel 2.0 does not provide the extra '([a-z]*)'", result.stderr
|
|
)
|
|
assert matches == ["nonexistent", "nope"]
|
|
|
|
|
|
def test_install_fails_if_extra_at_end(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Fail if order of specifiers and extras is incorrect.
|
|
|
|
Test uses a requirements file to avoid a testing issue where
|
|
the specifier gets interpreted as shell redirect.
|
|
"""
|
|
script.scratch_path.joinpath("requirements.txt").write_text(
|
|
"requires_simple_extra>=0.1[extra]"
|
|
)
|
|
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"--find-links=" + data.find_links,
|
|
"-r",
|
|
script.scratch_path / "requirements.txt",
|
|
expect_error=True,
|
|
)
|
|
assert "Extras after version" in result.stderr
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"specified_extra, requested_extra",
|
|
[
|
|
("Hop_hOp-hoP", "Hop_hOp-hoP"),
|
|
pytest.param(
|
|
"Hop_hOp-hoP",
|
|
"hop-hop-hop",
|
|
marks=pytest.mark.xfail(
|
|
reason=(
|
|
"matching a normalized extra request against an"
|
|
"unnormalized extra in metadata requires PEP 685 support "
|
|
"in packaging (see pypa/pip#11445)."
|
|
),
|
|
),
|
|
),
|
|
("hop-hop-hop", "Hop_hOp-hoP"),
|
|
],
|
|
)
|
|
def test_install_special_extra(
|
|
script: PipTestEnvironment,
|
|
specified_extra: str,
|
|
requested_extra: str,
|
|
) -> None:
|
|
"""Check extra normalization is implemented according to specification."""
|
|
pkga_path = create_basic_wheel_for_package(
|
|
script,
|
|
name="pkga",
|
|
version="0.1",
|
|
extras={specified_extra: ["missing_pkg"]},
|
|
)
|
|
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
f"pkga[{requested_extra}] @ {pkga_path.as_uri()}",
|
|
expect_error=True,
|
|
)
|
|
assert (
|
|
"Could not find a version that satisfies the requirement missing_pkg"
|
|
) in result.stderr, str(result)
|
|
|
|
|
|
def test_install_requirements_no_r_flag(script: PipTestEnvironment) -> None:
|
|
"""Beginners sometimes forget the -r and this leads to confusion"""
|
|
result = script.pip("install", "requirements.txt", expect_error=True)
|
|
assert 'literally named "requirements.txt"' in result.stdout
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"extra_to_install, simple_version, fails_on_legacy",
|
|
[
|
|
("", "3.0", False),
|
|
("[extra1]", "2.0", True),
|
|
("[extra2]", "1.0", True),
|
|
("[extra1,extra2]", "1.0", True),
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("data")
|
|
def test_install_extra_merging(
|
|
script: PipTestEnvironment,
|
|
resolver_variant: ResolverVariant,
|
|
extra_to_install: str,
|
|
simple_version: str,
|
|
fails_on_legacy: bool,
|
|
) -> None:
|
|
# Check that extra specifications in the extras section are honoured.
|
|
pkga_path = script.scratch_path / "pkga"
|
|
pkga_path.mkdir()
|
|
pkga_path.joinpath("setup.py").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
from setuptools import setup
|
|
setup(name='pkga',
|
|
version='0.1',
|
|
install_requires=['simple'],
|
|
extras_require={'extra1': ['simple<3'],
|
|
'extra2': ['simple==1.*']},
|
|
)
|
|
"""
|
|
)
|
|
)
|
|
|
|
result = script.pip_install_local(
|
|
f"{pkga_path}{extra_to_install}",
|
|
expect_error=(fails_on_legacy and resolver_variant == "legacy"),
|
|
)
|
|
|
|
if not fails_on_legacy or resolver_variant == "resolvelib":
|
|
expected = f"Successfully installed pkga-0.1 simple-{simple_version}"
|
|
assert expected in result.stdout
|
|
|
|
|
|
def test_install_extras(script: PipTestEnvironment) -> None:
|
|
create_basic_wheel_for_package(script, "a", "1", depends=["b", "dep[x-y]"])
|
|
create_basic_wheel_for_package(script, "b", "1", depends=["dep[x_y]"])
|
|
create_basic_wheel_for_package(script, "dep", "1", extras={"x-y": ["meh"]})
|
|
create_basic_wheel_for_package(script, "meh", "1")
|
|
|
|
script.pip(
|
|
"install",
|
|
"--no-cache-dir",
|
|
"--no-index",
|
|
"--find-links",
|
|
script.scratch_path,
|
|
"a",
|
|
)
|
|
script.assert_installed(a="1", b="1", dep="1", meh="1")
|