1
1
Fork 0
mirror of https://github.com/pypa/pip synced 2023-12-13 21:30:23 +01:00
pip/tests/functional/test_build_env.py
Tzu-ping Chung 50e194f107 Selectively enable user site
The modern virtual environment structure does not allow us to enable
"fake user site" while disabling the global site, so we need to do more
fine-grained configuration to correctly set up test environments for
each test case.

With this done, we can also properly support the stdlib venv ad the test
environment backend, since it basically works identically with modern
virtualenv. The incompatible_with_test_venv is thus removed.
2022-10-28 01:51:13 +08:00

265 lines
8.9 KiB
Python

import os
from textwrap import dedent
from typing import Optional
import pytest
from pip._internal.build_env import BuildEnvironment, _get_system_sitepackages
from tests.lib import (
PipTestEnvironment,
TestPipResult,
create_basic_wheel_for_package,
make_test_finder,
)
def indent(text: str, prefix: str) -> str:
return "\n".join((prefix if line else "") + line for line in text.split("\n"))
def run_with_build_env(
script: PipTestEnvironment,
setup_script_contents: str,
test_script_contents: Optional[str] = None,
) -> TestPipResult:
build_env_script = script.scratch_path / "build_env.py"
build_env_script.write_text(
dedent(
"""
import subprocess
import sys
from pip._internal.build_env import BuildEnvironment
from pip._internal.index.collector import LinkCollector
from pip._internal.index.package_finder import PackageFinder
from pip._internal.models.search_scope import SearchScope
from pip._internal.models.selection_prefs import (
SelectionPreferences
)
from pip._internal.network.session import PipSession
from pip._internal.utils.temp_dir import global_tempdir_manager
link_collector = LinkCollector(
session=PipSession(),
search_scope=SearchScope.create([{scratch!r}], [], False),
)
selection_prefs = SelectionPreferences(
allow_yanked=True,
)
finder = PackageFinder.create(
link_collector=link_collector,
selection_prefs=selection_prefs,
)
with global_tempdir_manager():
build_env = BuildEnvironment()
""".format(
scratch=str(script.scratch_path)
)
)
+ indent(dedent(setup_script_contents), " ")
+ indent(
dedent(
"""
if len(sys.argv) > 1:
with build_env:
subprocess.check_call((sys.executable, sys.argv[1]))
"""
),
" ",
)
)
args = ["python", os.fspath(build_env_script)]
if test_script_contents is not None:
test_script = script.scratch_path / "test.py"
test_script.write_text(dedent(test_script_contents))
args.append(os.fspath(test_script))
return script.run(*args)
def test_build_env_allow_empty_requirements_install() -> None:
finder = make_test_finder()
build_env = BuildEnvironment()
for prefix in ("normal", "overlay"):
build_env.install_requirements(
finder, [], prefix, kind="Installing build dependencies"
)
def test_build_env_allow_only_one_install(script: PipTestEnvironment) -> None:
create_basic_wheel_for_package(script, "foo", "1.0")
create_basic_wheel_for_package(script, "bar", "1.0")
finder = make_test_finder(find_links=[os.fspath(script.scratch_path)])
build_env = BuildEnvironment()
for prefix in ("normal", "overlay"):
build_env.install_requirements(
finder, ["foo"], prefix, kind=f"installing foo in {prefix}"
)
with pytest.raises(AssertionError):
build_env.install_requirements(
finder, ["bar"], prefix, kind=f"installing bar in {prefix}"
)
with pytest.raises(AssertionError):
build_env.install_requirements(
finder, [], prefix, kind=f"installing in {prefix}"
)
def test_build_env_requirements_check(script: PipTestEnvironment) -> None:
create_basic_wheel_for_package(script, "foo", "2.0")
create_basic_wheel_for_package(script, "bar", "1.0")
create_basic_wheel_for_package(script, "bar", "3.0")
create_basic_wheel_for_package(script, "other", "0.5")
script.pip_install_local("-f", script.scratch_path, "foo", "bar", "other")
run_with_build_env(
script,
"""
r = build_env.check_requirements(['foo', 'bar', 'other'])
assert r == (set(), {'foo', 'bar', 'other'}), repr(r)
r = build_env.check_requirements(['foo>1.0', 'bar==3.0'])
assert r == (set(), {'foo>1.0', 'bar==3.0'}), repr(r)
r = build_env.check_requirements(['foo>3.0', 'bar>=2.5'])
assert r == (set(), {'foo>3.0', 'bar>=2.5'}), repr(r)
""",
)
run_with_build_env(
script,
"""
build_env.install_requirements(finder, ['foo', 'bar==3.0'], 'normal',
kind='installing foo in normal')
r = build_env.check_requirements(['foo', 'bar', 'other'])
assert r == (set(), {'other'}), repr(r)
r = build_env.check_requirements(['foo>1.0', 'bar==3.0'])
assert r == (set(), set()), repr(r)
r = build_env.check_requirements(['foo>3.0', 'bar>=2.5'])
assert r == ({('foo==2.0', 'foo>3.0')}, set()), repr(r)
""",
)
run_with_build_env(
script,
"""
build_env.install_requirements(finder, ['foo', 'bar==3.0'], 'normal',
kind='installing foo in normal')
build_env.install_requirements(finder, ['bar==1.0'], 'overlay',
kind='installing foo in overlay')
r = build_env.check_requirements(['foo', 'bar', 'other'])
assert r == (set(), {'other'}), repr(r)
r = build_env.check_requirements(['foo>1.0', 'bar==3.0'])
assert r == ({('bar==1.0', 'bar==3.0')}, set()), repr(r)
r = build_env.check_requirements(['foo>3.0', 'bar>=2.5'])
assert r == ({('bar==1.0', 'bar>=2.5'), ('foo==2.0', 'foo>3.0')}, \
set()), repr(r)
""",
)
run_with_build_env(
script,
"""
build_env.install_requirements(
finder,
["bar==3.0"],
"normal",
kind="installing bar in normal",
)
r = build_env.check_requirements(
[
"bar==2.0; python_version < '3.0'",
"bar==3.0; python_version >= '3.0'",
"foo==4.0; extra == 'dev'",
],
)
assert r == (set(), set()), repr(r)
""",
)
def test_build_env_overlay_prefix_has_priority(script: PipTestEnvironment) -> None:
create_basic_wheel_for_package(script, "pkg", "2.0")
create_basic_wheel_for_package(script, "pkg", "4.3")
result = run_with_build_env(
script,
"""
build_env.install_requirements(finder, ['pkg==2.0'], 'overlay',
kind='installing pkg==2.0 in overlay')
build_env.install_requirements(finder, ['pkg==4.3'], 'normal',
kind='installing pkg==4.3 in normal')
""",
"""
print(__import__('pkg').__version__)
""",
)
assert result.stdout.strip() == "2.0", str(result)
@pytest.mark.usefixtures("enable_user_site")
def test_build_env_isolation(script: PipTestEnvironment) -> None:
# Create dummy `pkg` wheel.
pkg_whl = create_basic_wheel_for_package(script, "pkg", "1.0")
# Install it to site packages.
script.pip_install_local(pkg_whl)
# And a copy in the user site.
script.pip_install_local("--ignore-installed", "--user", pkg_whl)
# And to another directory available through a .pth file.
target = script.scratch_path / "pth_install"
script.pip_install_local("-t", target, pkg_whl)
(script.site_packages_path / "build_requires.pth").write_text(str(target) + "\n")
# And finally to yet another directory available through PYTHONPATH.
target = script.scratch_path / "pypath_install"
script.pip_install_local("-t", target, pkg_whl)
script.environ["PYTHONPATH"] = target
system_sites = _get_system_sitepackages()
# there should always be something to exclude
assert system_sites
run_with_build_env(
script,
"",
r"""
from distutils.sysconfig import get_python_lib
import sys
try:
import pkg
except ImportError:
pass
else:
print(
f'imported `pkg` from `{pkg.__file__}`',
file=sys.stderr)
print('system sites:\n ' + '\n '.join(sorted({
get_python_lib(plat_specific=0),
get_python_lib(plat_specific=1),
})), file=sys.stderr)
print('sys.path:\n ' + '\n '.join(sys.path), file=sys.stderr)
sys.exit(1)
"""
f"""
# second check: direct check of exclusion of system site packages
import os
normalized_path = [os.path.normcase(path) for path in sys.path]
for system_path in {system_sites!r}:
assert system_path not in normalized_path, \
f"{{system_path}} found in {{normalized_path}}"
""",
)