2022-06-07 11:52:38 +02:00
|
|
|
import os
|
2023-07-04 11:03:11 +02:00
|
|
|
import sys
|
2018-10-25 17:35:25 +02:00
|
|
|
from textwrap import dedent
|
2021-09-13 00:31:12 +02:00
|
|
|
from typing import Optional
|
2018-10-25 17:35:25 +02:00
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
2022-09-23 14:32:26 +02:00
|
|
|
from pip._internal.build_env import BuildEnvironment, _get_system_sitepackages
|
2021-09-13 00:31:12 +02:00
|
|
|
from tests.lib import (
|
|
|
|
PipTestEnvironment,
|
|
|
|
TestPipResult,
|
|
|
|
create_basic_wheel_for_package,
|
|
|
|
make_test_finder,
|
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
|
|
|
|
|
2021-09-13 00:31:12 +02:00
|
|
|
def indent(text: str, prefix: str) -> str:
|
2018-10-25 17:35:25 +02:00
|
|
|
return "\n".join((prefix if line else "") + line for line in text.split("\n"))
|
|
|
|
|
|
|
|
|
2021-09-13 00:31:12 +02:00
|
|
|
def run_with_build_env(
|
|
|
|
script: PipTestEnvironment,
|
|
|
|
setup_script_contents: str,
|
|
|
|
test_script_contents: Optional[str] = None,
|
|
|
|
) -> TestPipResult:
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env_script = script.scratch_path / "build_env.py"
|
2019-07-02 07:00:32 +02:00
|
|
|
build_env_script.write_text(
|
2018-10-25 17:35:25 +02:00
|
|
|
dedent(
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2018-10-25 17:35:25 +02:00
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from pip._internal.build_env import BuildEnvironment
|
2019-10-06 20:11:01 +02:00
|
|
|
from pip._internal.index.collector import LinkCollector
|
2019-10-06 18:59:05 +02:00
|
|
|
from pip._internal.index.package_finder import PackageFinder
|
2019-06-21 18:10:03 +02:00
|
|
|
from pip._internal.models.search_scope import SearchScope
|
2019-06-28 20:14:55 +02:00
|
|
|
from pip._internal.models.selection_prefs import (
|
|
|
|
SelectionPreferences
|
|
|
|
)
|
2019-10-14 00:44:23 +02:00
|
|
|
from pip._internal.network.session import PipSession
|
2020-01-31 04:08:57 +01:00
|
|
|
from pip._internal.utils.temp_dir import global_tempdir_manager
|
2018-10-25 17:35:25 +02:00
|
|
|
|
2019-09-14 20:08:32 +02:00
|
|
|
link_collector = LinkCollector(
|
|
|
|
session=PipSession(),
|
2022-07-20 15:55:17 +02:00
|
|
|
search_scope=SearchScope.create([{scratch!r}], [], False),
|
2019-09-14 20:08:32 +02:00
|
|
|
)
|
2019-06-28 20:14:55 +02:00
|
|
|
selection_prefs = SelectionPreferences(
|
|
|
|
allow_yanked=True,
|
|
|
|
)
|
2019-06-27 20:50:27 +02:00
|
|
|
finder = PackageFinder.create(
|
2019-09-14 20:08:32 +02:00
|
|
|
link_collector=link_collector,
|
2019-06-28 20:14:55 +02:00
|
|
|
selection_prefs=selection_prefs,
|
2019-06-27 20:50:27 +02:00
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
|
2020-01-31 04:08:57 +01:00
|
|
|
with global_tempdir_manager():
|
|
|
|
build_env = BuildEnvironment()
|
2020-02-29 20:53:59 +01:00
|
|
|
""".format(
|
|
|
|
scratch=str(script.scratch_path)
|
2021-08-13 15:23:45 +02:00
|
|
|
)
|
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
+ indent(dedent(setup_script_contents), " ")
|
2020-01-31 04:08:57 +01:00
|
|
|
+ indent(
|
|
|
|
dedent(
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2018-10-25 17:35:25 +02:00
|
|
|
if len(sys.argv) > 1:
|
|
|
|
with build_env:
|
|
|
|
subprocess.check_call((sys.executable, sys.argv[1]))
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2020-01-31 04:08:57 +01:00
|
|
|
),
|
2021-08-13 15:23:45 +02:00
|
|
|
" ",
|
2020-01-31 04:08:57 +01:00
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
)
|
2022-06-07 11:52:38 +02:00
|
|
|
args = ["python", os.fspath(build_env_script)]
|
2018-10-25 17:35:25 +02:00
|
|
|
if test_script_contents is not None:
|
|
|
|
test_script = script.scratch_path / "test.py"
|
2019-07-02 07:00:32 +02:00
|
|
|
test_script.write_text(dedent(test_script_contents))
|
2022-06-07 11:52:38 +02:00
|
|
|
args.append(os.fspath(test_script))
|
2018-10-25 17:35:25 +02:00
|
|
|
return script.run(*args)
|
|
|
|
|
|
|
|
|
2021-09-13 00:31:12 +02:00
|
|
|
def test_build_env_allow_empty_requirements_install() -> None:
|
|
|
|
finder = make_test_finder()
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env = BuildEnvironment()
|
|
|
|
for prefix in ("normal", "overlay"):
|
2021-09-13 00:31:12 +02:00
|
|
|
build_env.install_requirements(
|
2021-11-12 14:38:01 +01:00
|
|
|
finder, [], prefix, kind="Installing build dependencies"
|
2021-09-13 00:31:12 +02:00
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
|
|
|
|
|
2021-09-13 00:31:12 +02:00
|
|
|
def test_build_env_allow_only_one_install(script: PipTestEnvironment) -> None:
|
2018-10-25 17:35:25 +02:00
|
|
|
create_basic_wheel_for_package(script, "foo", "1.0")
|
|
|
|
create_basic_wheel_for_package(script, "bar", "1.0")
|
2022-06-07 11:52:38 +02:00
|
|
|
finder = make_test_finder(find_links=[os.fspath(script.scratch_path)])
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env = BuildEnvironment()
|
|
|
|
for prefix in ("normal", "overlay"):
|
2020-02-29 20:53:59 +01:00
|
|
|
build_env.install_requirements(
|
2021-11-12 14:38:01 +01:00
|
|
|
finder, ["foo"], prefix, kind=f"installing foo in {prefix}"
|
2021-02-13 07:27:17 +01:00
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
with pytest.raises(AssertionError):
|
2020-02-29 20:53:59 +01:00
|
|
|
build_env.install_requirements(
|
2021-11-12 14:38:01 +01:00
|
|
|
finder, ["bar"], prefix, kind=f"installing bar in {prefix}"
|
2021-02-13 07:27:17 +01:00
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
with pytest.raises(AssertionError):
|
2020-02-29 20:53:59 +01:00
|
|
|
build_env.install_requirements(
|
2021-11-12 14:38:01 +01:00
|
|
|
finder, [], prefix, kind=f"installing in {prefix}"
|
2021-02-13 07:27:17 +01:00
|
|
|
)
|
2018-10-25 17:35:25 +02:00
|
|
|
|
|
|
|
|
2021-09-13 00:31:12 +02:00
|
|
|
def test_build_env_requirements_check(script: PipTestEnvironment) -> None:
|
2018-10-25 17:35:25 +02:00
|
|
|
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,
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2018-10-25 17:35:25 +02:00
|
|
|
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)
|
2021-08-13 15:23:45 +02:00
|
|
|
""",
|
2018-10-25 17:35:25 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
run_with_build_env(
|
|
|
|
script,
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env.install_requirements(finder, ['foo', 'bar==3.0'], 'normal',
|
2021-11-12 14:38:01 +01:00
|
|
|
kind='installing foo in normal')
|
2018-10-25 17:35:25 +02:00
|
|
|
|
|
|
|
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)
|
2021-08-13 15:23:45 +02:00
|
|
|
""",
|
2018-10-25 17:35:25 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
run_with_build_env(
|
|
|
|
script,
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env.install_requirements(finder, ['foo', 'bar==3.0'], 'normal',
|
2021-11-12 14:38:01 +01:00
|
|
|
kind='installing foo in normal')
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env.install_requirements(finder, ['bar==1.0'], 'overlay',
|
2021-11-12 14:38:01 +01:00
|
|
|
kind='installing foo in overlay')
|
2018-10-25 17:35:25 +02:00
|
|
|
|
|
|
|
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)
|
2021-08-13 15:23:45 +02:00
|
|
|
""",
|
2018-10-25 17:35:25 +02:00
|
|
|
)
|
|
|
|
|
2022-04-13 00:00:22 +02:00
|
|
|
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'",
|
2022-05-12 02:04:11 +02:00
|
|
|
"foo==4.0; extra == 'dev'",
|
2022-04-13 00:00:22 +02:00
|
|
|
],
|
|
|
|
)
|
|
|
|
assert r == (set(), set()), repr(r)
|
|
|
|
""",
|
|
|
|
)
|
|
|
|
|
2018-10-25 17:35:25 +02:00
|
|
|
|
2021-09-13 00:31:12 +02:00
|
|
|
def test_build_env_overlay_prefix_has_priority(script: PipTestEnvironment) -> None:
|
2018-10-25 17:35:25 +02:00
|
|
|
create_basic_wheel_for_package(script, "pkg", "2.0")
|
|
|
|
create_basic_wheel_for_package(script, "pkg", "4.3")
|
|
|
|
result = run_with_build_env(
|
|
|
|
script,
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env.install_requirements(finder, ['pkg==2.0'], 'overlay',
|
2021-11-12 14:38:01 +01:00
|
|
|
kind='installing pkg==2.0 in overlay')
|
2018-10-25 17:35:25 +02:00
|
|
|
build_env.install_requirements(finder, ['pkg==4.3'], 'normal',
|
2021-11-12 14:38:01 +01:00
|
|
|
kind='installing pkg==4.3 in normal')
|
2018-10-25 17:35:25 +02:00
|
|
|
""",
|
2021-08-13 15:23:45 +02:00
|
|
|
"""
|
2018-10-25 17:35:25 +02:00
|
|
|
print(__import__('pkg').__version__)
|
2021-08-13 15:23:45 +02:00
|
|
|
""",
|
2018-10-25 17:35:25 +02:00
|
|
|
)
|
|
|
|
assert result.stdout.strip() == "2.0", str(result)
|
|
|
|
|
|
|
|
|
2023-07-04 11:03:11 +02:00
|
|
|
if sys.version_info < (3, 12):
|
|
|
|
BUILD_ENV_ERROR_DEBUG_CODE = r"""
|
|
|
|
from distutils.sysconfig import get_python_lib
|
|
|
|
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)
|
|
|
|
"""
|
|
|
|
else:
|
|
|
|
BUILD_ENV_ERROR_DEBUG_CODE = r"""
|
|
|
|
from sysconfig import get_paths
|
|
|
|
paths = get_paths()
|
|
|
|
print(
|
|
|
|
f'imported `pkg` from `{pkg.__file__}`',
|
|
|
|
file=sys.stderr)
|
|
|
|
print('system sites:\n ' + '\n '.join(sorted({
|
|
|
|
paths['platlib'],
|
|
|
|
paths['purelib'],
|
|
|
|
})), file=sys.stderr)
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
2022-10-27 15:34:17 +02:00
|
|
|
@pytest.mark.usefixtures("enable_user_site")
|
2021-09-13 00:31:12 +02:00
|
|
|
def test_build_env_isolation(script: PipTestEnvironment) -> None:
|
2018-10-25 17:35:25 +02:00
|
|
|
# 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)
|
2019-07-02 07:00:32 +02:00
|
|
|
(script.site_packages_path / "build_requires.pth").write_text(str(target) + "\n")
|
2018-10-25 17:35:25 +02:00
|
|
|
|
|
|
|
# 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
|
|
|
|
|
2022-09-23 14:32:26 +02:00
|
|
|
system_sites = _get_system_sitepackages()
|
|
|
|
# there should always be something to exclude
|
|
|
|
assert system_sites
|
|
|
|
|
2018-10-25 17:35:25 +02:00
|
|
|
run_with_build_env(
|
|
|
|
script,
|
|
|
|
"",
|
2023-07-04 11:03:11 +02:00
|
|
|
f"""
|
2018-10-25 17:35:25 +02:00
|
|
|
import sys
|
|
|
|
|
|
|
|
try:
|
|
|
|
import pkg
|
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
else:
|
2023-07-04 11:03:11 +02:00
|
|
|
{BUILD_ENV_ERROR_DEBUG_CODE}
|
|
|
|
print('sys.path:\\n ' + '\\n '.join(sys.path), file=sys.stderr)
|
2018-10-25 17:35:25 +02:00
|
|
|
sys.exit(1)
|
2022-09-23 14:32:26 +02:00
|
|
|
# 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}}"
|
2021-08-13 15:23:45 +02:00
|
|
|
""",
|
2018-10-25 17:35:25 +02:00
|
|
|
)
|