mirror of https://github.com/pypa/pip
Merge branch 'main' into darshanip/main
This commit is contained in:
commit
f927891b36
|
@ -26,8 +26,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- run: pip install nox
|
||||
- run: nox -s docs
|
||||
|
||||
|
@ -60,8 +62,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Set up git credentials
|
||||
run: |
|
||||
git config --global user.email "pypa-dev@googlegroups.com"
|
||||
|
@ -82,8 +86,10 @@ jobs:
|
|||
github.event_name != 'pull_request'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- run: pip install nox
|
||||
- run: nox -s vendoring
|
||||
|
@ -103,14 +109,15 @@ jobs:
|
|||
matrix:
|
||||
os: [Ubuntu, MacOS]
|
||||
python:
|
||||
- 3.7
|
||||
- 3.8
|
||||
- 3.9
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "3.9"
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
|
@ -120,9 +127,9 @@ jobs:
|
|||
|
||||
- name: Install MacOS dependencies
|
||||
if: matrix.os == 'MacOS'
|
||||
run: brew install bzr
|
||||
run: brew install breezy
|
||||
|
||||
- run: pip install nox 'virtualenv<20' 'setuptools != 60.6.0'
|
||||
- run: pip install nox
|
||||
|
||||
# Main check
|
||||
- name: Run unit tests
|
||||
|
@ -151,16 +158,17 @@ jobs:
|
|||
matrix:
|
||||
os: [Windows]
|
||||
python:
|
||||
- 3.7
|
||||
- "3.7"
|
||||
# Commented out, since Windows tests are expensively slow.
|
||||
# - 3.8
|
||||
# - 3.9
|
||||
- "3.10"
|
||||
# - "3.8"
|
||||
# - "3.9"
|
||||
# - "3.10"
|
||||
- "3.11"
|
||||
group: [1, 2]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
|
@ -179,7 +187,7 @@ jobs:
|
|||
$acl.AddAccessRule($rule)
|
||||
Set-Acl "R:\Temp" $acl
|
||||
|
||||
- run: pip install nox 'virtualenv<20'
|
||||
- run: pip install nox
|
||||
env:
|
||||
TEMP: "R:\\Temp"
|
||||
|
||||
|
@ -221,8 +229,8 @@ jobs:
|
|||
github.event_name != 'pull_request'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
|
@ -240,41 +248,6 @@ jobs:
|
|||
--durations=5
|
||||
--use-zipapp
|
||||
|
||||
# TODO: Remove this when we add Python 3.11 to CI.
|
||||
tests-importlib-metadata:
|
||||
name: tests for importlib.metadata backend
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
_PIP_USE_IMPORTLIB_METADATA: 'true'
|
||||
|
||||
needs: [packaging, determine-changes]
|
||||
if: >-
|
||||
needs.determine-changes.outputs.tests == 'true' ||
|
||||
github.event_name != 'pull_request'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install Ubuntu dependencies
|
||||
run: sudo apt-get install bzr
|
||||
|
||||
- run: pip install nox 'virtualenv<20'
|
||||
|
||||
- name: Run unit tests
|
||||
run: >-
|
||||
nox -s test-3.10 --
|
||||
-m unit
|
||||
--verbose --numprocesses auto --showlocals
|
||||
- name: Run integration tests
|
||||
run: >-
|
||||
nox -s test-3.10 --
|
||||
-m integration
|
||||
--verbose --numprocesses auto --showlocals
|
||||
--durations=5
|
||||
|
||||
check: # This job does nothing and is only used for the branch protection
|
||||
if: always()
|
||||
|
||||
|
@ -285,7 +258,6 @@ jobs:
|
|||
- tests-unix
|
||||
- tests-windows
|
||||
- tests-zipapp
|
||||
- tests-importlib-metadata
|
||||
- vendoring
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
# `towncrier check` runs `git diff --name-only origin/main...`, which
|
||||
# needs a non-shallow clone.
|
||||
|
|
11
NEWS.rst
11
NEWS.rst
|
@ -9,6 +9,17 @@
|
|||
|
||||
.. towncrier release notes start
|
||||
|
||||
22.3.1 (2022-11-05)
|
||||
===================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Fix entry point generation of ``pip.X``, ``pipX.Y``, and ``easy_install-X.Y``
|
||||
to correctly account for multi-digit Python version segments (e.g. the "11"
|
||||
part of 3.11). (`#11547 <https://github.com/pypa/pip/issues/11547>`_)
|
||||
|
||||
|
||||
22.3 (2022-10-15)
|
||||
=================
|
||||
|
||||
|
|
|
@ -65,6 +65,13 @@ their merits.
|
|||
``pip._internal.utils.deprecation.deprecated``. The function is not a part of
|
||||
pip's public API.
|
||||
|
||||
Supported Versions
|
||||
==================
|
||||
|
||||
The latest version of the pip is the only supported version, previous
|
||||
versions should be considered unsupported. Users are encouraged to make
|
||||
regular updates to their version of pip in order to remain supported.
|
||||
|
||||
.. _`Python 2 Support`:
|
||||
|
||||
Python 2 Support
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Fix entry point generation of ``pip.X``, ``pipX.Y``, and ``easy_install-X.Y``
|
||||
to correctly account for multi-digit Python version segments (e.g. the "11"
|
||||
part of 3.11).
|
|
@ -66,7 +66,7 @@ def should_update_common_wheels() -> bool:
|
|||
# -----------------------------------------------------------------------------
|
||||
# Development Commands
|
||||
# -----------------------------------------------------------------------------
|
||||
@nox.session(python=["3.7", "3.8", "3.9", "3.10", "pypy3"])
|
||||
@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "pypy3"])
|
||||
def test(session: nox.Session) -> None:
|
||||
# Get the common wheels.
|
||||
if should_update_common_wheels():
|
||||
|
|
|
@ -63,7 +63,6 @@ xfail_strict = True
|
|||
markers =
|
||||
network: tests that need network
|
||||
incompatible_with_sysconfig
|
||||
incompatible_with_test_venv
|
||||
incompatible_with_venv
|
||||
no_auto_tempdir_manager
|
||||
unit: unit tests
|
||||
|
|
|
@ -325,7 +325,7 @@ def get_console_script_specs(console: Dict[str, str]) -> List[str]:
|
|||
|
||||
scripts_to_generate.append(f"pip{get_major_minor_version()} = {pip_script}")
|
||||
# Delete any other versioned pip entry points
|
||||
pip_ep = [k for k in console if re.match(r"pip(\d(\.\d)?)?$", k)]
|
||||
pip_ep = [k for k in console if re.match(r"pip(\d+(\.\d+)?)?$", k)]
|
||||
for k in pip_ep:
|
||||
del console[k]
|
||||
easy_install_script = console.pop("easy_install", None)
|
||||
|
@ -340,7 +340,7 @@ def get_console_script_specs(console: Dict[str, str]) -> List[str]:
|
|||
)
|
||||
# Delete any other versioned easy_install entry points
|
||||
easy_install_ep = [
|
||||
k for k in console if re.match(r"easy_install(-\d\.\d)?$", k)
|
||||
k for k in console if re.match(r"easy_install(-\d+\.\d+)?$", k)
|
||||
]
|
||||
for k in easy_install_ep:
|
||||
del console[k]
|
||||
|
|
|
@ -19,7 +19,7 @@ def _running_under_venv() -> bool:
|
|||
return sys.prefix != getattr(sys, "base_prefix", sys.prefix)
|
||||
|
||||
|
||||
def _running_under_regular_virtualenv() -> bool:
|
||||
def _running_under_legacy_virtualenv() -> bool:
|
||||
"""Checks if sys.real_prefix is set.
|
||||
|
||||
This handles virtual environments created with pypa's virtualenv.
|
||||
|
@ -29,8 +29,8 @@ def _running_under_regular_virtualenv() -> bool:
|
|||
|
||||
|
||||
def running_under_virtualenv() -> bool:
|
||||
"""Return True if we're running inside a virtualenv, False otherwise."""
|
||||
return _running_under_venv() or _running_under_regular_virtualenv()
|
||||
"""True if we're running inside a virtual environment, False otherwise."""
|
||||
return _running_under_venv() or _running_under_legacy_virtualenv()
|
||||
|
||||
|
||||
def _get_pyvenv_cfg_lines() -> Optional[List[str]]:
|
||||
|
@ -77,7 +77,7 @@ def _no_global_under_venv() -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def _no_global_under_regular_virtualenv() -> bool:
|
||||
def _no_global_under_legacy_virtualenv() -> bool:
|
||||
"""Check if "no-global-site-packages.txt" exists beside site.py
|
||||
|
||||
This mirrors logic in pypa/virtualenv for determining whether system
|
||||
|
@ -98,7 +98,7 @@ def virtualenv_no_global() -> bool:
|
|||
if _running_under_venv():
|
||||
return _no_global_under_venv()
|
||||
|
||||
if _running_under_regular_virtualenv():
|
||||
return _no_global_under_regular_virtualenv()
|
||||
if _running_under_legacy_virtualenv():
|
||||
return _no_global_under_legacy_virtualenv()
|
||||
|
||||
return False
|
||||
|
|
|
@ -108,10 +108,6 @@ def pytest_collection_modifyitems(config: Config, items: List[pytest.Function])
|
|||
if item.get_closest_marker("network") is not None:
|
||||
item.add_marker(pytest.mark.flaky(reruns=3, reruns_delay=2))
|
||||
|
||||
if item.get_closest_marker("incompatible_with_test_venv") and config.getoption(
|
||||
"--use-venv"
|
||||
):
|
||||
item.add_marker(pytest.mark.skip("Incompatible with test venv"))
|
||||
if (
|
||||
item.get_closest_marker("incompatible_with_venv")
|
||||
and sys.prefix != sys.base_prefix
|
||||
|
@ -474,9 +470,6 @@ def virtualenv_template(
|
|||
):
|
||||
(venv.bin / exe).unlink()
|
||||
|
||||
# Enable user site packages.
|
||||
venv.user_site_packages = True
|
||||
|
||||
# Rename original virtualenv directory to make sure
|
||||
# it's not reused by mistake from one of the copies.
|
||||
venv_template = tmpdir / "venv_template"
|
||||
|
@ -742,3 +735,8 @@ def mock_server() -> Iterator[MockServer]:
|
|||
@pytest.fixture
|
||||
def proxy(request: pytest.FixtureRequest) -> str:
|
||||
return request.config.getoption("proxy")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def enable_user_site(virtualenv: VirtualEnvironment) -> None:
|
||||
virtualenv.user_site_packages = True
|
||||
|
|
|
@ -204,7 +204,7 @@ def test_build_env_overlay_prefix_has_priority(script: PipTestEnvironment) -> No
|
|||
assert result.stdout.strip() == "2.0", str(result)
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_build_env_isolation(script: PipTestEnvironment) -> None:
|
||||
|
||||
# Create dummy `pkg` wheel.
|
||||
|
|
|
@ -862,7 +862,7 @@ def test_freeze_with_requirement_option_package_repeated_multi_file(
|
|||
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_freeze_user(
|
||||
script: PipTestEnvironment, virtualenv: VirtualEnvironment, data: TestData
|
||||
) -> None:
|
||||
|
@ -900,7 +900,7 @@ def test_freeze_path(tmpdir: Path, script: PipTestEnvironment, data: TestData) -
|
|||
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_freeze_path_exclude_user(
|
||||
tmpdir: Path, script: PipTestEnvironment, data: TestData
|
||||
) -> None:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import distutils
|
||||
import os
|
||||
import re
|
||||
import ssl
|
||||
import sys
|
||||
import sysconfig
|
||||
import textwrap
|
||||
from os.path import curdir, join, pardir
|
||||
from pathlib import Path
|
||||
|
@ -171,7 +171,7 @@ def test_pep518_allows_missing_requires(
|
|||
assert result.files_created
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_pep518_with_user_pip(
|
||||
script: PipTestEnvironment, pip_src: Path, data: TestData, common_wheels: Path
|
||||
) -> None:
|
||||
|
@ -1145,6 +1145,39 @@ def test_install_with_target_or_prefix_and_scripts_no_warning(
|
|||
assert "--no-warn-script-location" not in result.stderr, str(result)
|
||||
|
||||
|
||||
def _change_root(new_root: str, pathname: str) -> str:
|
||||
"""
|
||||
Adapted from distutils.
|
||||
|
||||
Return 'pathname' with 'new_root' prepended. If 'pathname' is
|
||||
relative, this is equivalent to "os.path.join(new_root,pathname)".
|
||||
Otherwise, it requires making 'pathname' relative and then joining the
|
||||
two, which is tricky on DOS/Windows and Mac OS.
|
||||
"""
|
||||
try:
|
||||
from distutils.util import change_root
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return change_root(new_root, pathname)
|
||||
|
||||
if os.name == "posix":
|
||||
if not os.path.isabs(pathname):
|
||||
return os.path.join(new_root, pathname)
|
||||
else:
|
||||
return os.path.join(new_root, pathname[1:])
|
||||
|
||||
elif os.name == "nt":
|
||||
drive, path = os.path.splitdrive(pathname)
|
||||
if path[0] == "\\":
|
||||
path = path[1:]
|
||||
return os.path.join(new_root, path)
|
||||
|
||||
else:
|
||||
# distutils raise DistutilsPlatformError here
|
||||
raise RuntimeError(f"nothing known about platform '{os.name}'")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("with_wheel")
|
||||
def test_install_package_with_root(script: PipTestEnvironment, data: TestData) -> None:
|
||||
"""
|
||||
|
@ -1163,10 +1196,8 @@ def test_install_package_with_root(script: PipTestEnvironment, data: TestData) -
|
|||
normal_install_path = os.fspath(
|
||||
script.base_path / script.site_packages / "simple-1.0.dist-info"
|
||||
)
|
||||
# use distutils to change the root exactly how the --root option does it
|
||||
from distutils.util import change_root
|
||||
|
||||
root_path = change_root(os.path.join(script.scratch, "root"), normal_install_path)
|
||||
root_path = _change_root(os.path.join(script.scratch, "root"), normal_install_path)
|
||||
result.did_create(root_path)
|
||||
|
||||
# Should show find-links location in output
|
||||
|
@ -1195,7 +1226,7 @@ def test_install_package_with_prefix(
|
|||
|
||||
rel_prefix_path = script.scratch / "prefix"
|
||||
install_path = join(
|
||||
distutils.sysconfig.get_python_lib(prefix=rel_prefix_path),
|
||||
sysconfig.get_path("purelib", vars={"base": rel_prefix_path}),
|
||||
# we still test for egg-info because no-binary implies setup.py install
|
||||
f"simple-1.0-py{pyversion}.egg-info",
|
||||
)
|
||||
|
@ -1217,7 +1248,7 @@ def _test_install_editable_with_prefix(
|
|||
"prefix", "lib", f"python{pyversion}", "site-packages"
|
||||
)
|
||||
else:
|
||||
site_packages = distutils.sysconfig.get_python_lib(prefix="prefix")
|
||||
site_packages = sysconfig.get_path("purelib", vars={"base": "prefix"})
|
||||
|
||||
# make sure target path is in PYTHONPATH
|
||||
pythonpath = script.scratch_path / site_packages
|
||||
|
@ -2075,7 +2106,7 @@ def test_target_install_ignores_distutils_config_install_prefix(
|
|||
result.did_not_create(relative_script_base)
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_user_config_accepted(script: PipTestEnvironment) -> None:
|
||||
# user set in the config file is parsed as 0/1 instead of True/False.
|
||||
# Check that this doesn't cause a problem.
|
||||
|
|
|
@ -305,8 +305,7 @@ def test_install_local_with_subdirectory(script: PipTestEnvironment) -> None:
|
|||
result.assert_installed("version_subpkg.py", editable=False)
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("with_wheel")
|
||||
@pytest.mark.usefixtures("enable_user_site", "with_wheel")
|
||||
def test_wheel_user_with_prefix_in_pydistutils_cfg(
|
||||
script: PipTestEnvironment, data: TestData
|
||||
) -> None:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""
|
||||
tests specific to "pip install --user"
|
||||
"""
|
||||
import os
|
||||
import textwrap
|
||||
from os.path import curdir, isdir, isfile
|
||||
from pathlib import Path
|
||||
|
@ -8,7 +9,12 @@ from pathlib import Path
|
|||
import pytest
|
||||
|
||||
from tests.lib import pyversion # noqa: F401
|
||||
from tests.lib import PipTestEnvironment, TestData, need_svn
|
||||
from tests.lib import (
|
||||
PipTestEnvironment,
|
||||
TestData,
|
||||
create_basic_wheel_for_package,
|
||||
need_svn,
|
||||
)
|
||||
from tests.lib.local_repos import local_checkout
|
||||
from tests.lib.venv import VirtualEnvironment
|
||||
|
||||
|
@ -29,9 +35,9 @@ def _patch_dist_in_site_packages(virtualenv: VirtualEnvironment) -> None:
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
class Tests_UserSite:
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_reset_env_system_site_packages_usersite(
|
||||
self, script: PipTestEnvironment
|
||||
) -> None:
|
||||
|
@ -51,7 +57,6 @@ class Tests_UserSite:
|
|||
@pytest.mark.xfail
|
||||
@pytest.mark.network
|
||||
@need_svn
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_install_subversion_usersite_editable_with_distribute(
|
||||
self, script: PipTestEnvironment, tmpdir: Path
|
||||
) -> None:
|
||||
|
@ -71,7 +76,6 @@ class Tests_UserSite:
|
|||
)
|
||||
result.assert_installed("INITools", use_user_site=True)
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("with_wheel")
|
||||
def test_install_from_current_directory_into_usersite(
|
||||
self, script: PipTestEnvironment, data: TestData
|
||||
|
@ -117,7 +121,6 @@ class Tests_UserSite:
|
|||
)
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_install_user_conflict_in_usersite(
|
||||
self, script: PipTestEnvironment
|
||||
) -> None:
|
||||
|
@ -142,8 +145,6 @@ class Tests_UserSite:
|
|||
result2.did_create(egg_info_folder)
|
||||
assert not isfile(initools_v3_file), initools_v3_file
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_install_user_conflict_in_globalsite(
|
||||
self, virtualenv: VirtualEnvironment, script: PipTestEnvironment
|
||||
) -> None:
|
||||
|
@ -151,31 +152,41 @@ class Tests_UserSite:
|
|||
Test user install with conflict in global site ignores site and
|
||||
installs to usersite
|
||||
"""
|
||||
create_basic_wheel_for_package(script, "initools", "0.1")
|
||||
create_basic_wheel_for_package(script, "initools", "0.2")
|
||||
|
||||
_patch_dist_in_site_packages(virtualenv)
|
||||
|
||||
script.pip("install", "INITools==0.2", "--no-binary=:all:")
|
||||
|
||||
result2 = script.pip("install", "--user", "INITools==0.1", "--no-binary=:all:")
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"initools==0.2",
|
||||
)
|
||||
result2 = script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--user",
|
||||
"initools==0.1",
|
||||
)
|
||||
|
||||
# usersite has 0.1
|
||||
# we still test for egg-info because no-binary implies setup.py install
|
||||
egg_info_folder = script.user_site / f"INITools-0.1-py{pyversion}.egg-info"
|
||||
dist_info_folder = script.user_site / "initools-0.1.dist-info"
|
||||
initools_folder = script.user_site / "initools"
|
||||
result2.did_create(egg_info_folder)
|
||||
result2.did_create(dist_info_folder)
|
||||
result2.did_create(initools_folder)
|
||||
|
||||
# site still has 0.2 (can't look in result1; have to check)
|
||||
egg_info_folder = (
|
||||
script.base_path
|
||||
/ script.site_packages
|
||||
/ f"INITools-0.2-py{pyversion}.egg-info"
|
||||
dist_info_folder = (
|
||||
script.base_path / script.site_packages / "initools-0.2.dist-info"
|
||||
)
|
||||
initools_folder = script.base_path / script.site_packages / "initools"
|
||||
assert isdir(egg_info_folder)
|
||||
assert isdir(dist_info_folder)
|
||||
assert isdir(initools_folder)
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_upgrade_user_conflict_in_globalsite(
|
||||
self, virtualenv: VirtualEnvironment, script: PipTestEnvironment
|
||||
) -> None:
|
||||
|
@ -183,32 +194,42 @@ class Tests_UserSite:
|
|||
Test user install/upgrade with conflict in global site ignores site and
|
||||
installs to usersite
|
||||
"""
|
||||
create_basic_wheel_for_package(script, "initools", "0.2")
|
||||
create_basic_wheel_for_package(script, "initools", "0.3.1")
|
||||
|
||||
_patch_dist_in_site_packages(virtualenv)
|
||||
|
||||
script.pip("install", "INITools==0.2", "--no-binary=:all:")
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"initools==0.2",
|
||||
)
|
||||
result2 = script.pip(
|
||||
"install", "--user", "--upgrade", "INITools", "--no-binary=:all:"
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--user",
|
||||
"--upgrade",
|
||||
"initools",
|
||||
)
|
||||
|
||||
# usersite has 0.3.1
|
||||
# we still test for egg-info because no-binary implies setup.py install
|
||||
egg_info_folder = script.user_site / f"INITools-0.3.1-py{pyversion}.egg-info"
|
||||
dist_info_folder = script.user_site / "initools-0.3.1.dist-info"
|
||||
initools_folder = script.user_site / "initools"
|
||||
result2.did_create(egg_info_folder)
|
||||
result2.did_create(dist_info_folder)
|
||||
result2.did_create(initools_folder)
|
||||
|
||||
# site still has 0.2 (can't look in result1; have to check)
|
||||
egg_info_folder = (
|
||||
script.base_path
|
||||
/ script.site_packages
|
||||
/ f"INITools-0.2-py{pyversion}.egg-info"
|
||||
dist_info_folder = (
|
||||
script.base_path / script.site_packages / "initools-0.2.dist-info"
|
||||
)
|
||||
initools_folder = script.base_path / script.site_packages / "initools"
|
||||
assert isdir(egg_info_folder), result2.stdout
|
||||
assert isdir(dist_info_folder), result2.stdout
|
||||
assert isdir(initools_folder)
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_install_user_conflict_in_globalsite_and_usersite(
|
||||
self, virtualenv: VirtualEnvironment, script: PipTestEnvironment
|
||||
) -> None:
|
||||
|
@ -216,38 +237,56 @@ class Tests_UserSite:
|
|||
Test user install with conflict in globalsite and usersite ignores
|
||||
global site and updates usersite.
|
||||
"""
|
||||
initools_v3_file_name = os.path.join("initools", "configparser.py")
|
||||
create_basic_wheel_for_package(script, "initools", "0.1")
|
||||
create_basic_wheel_for_package(script, "initools", "0.2")
|
||||
create_basic_wheel_for_package(
|
||||
script,
|
||||
"initools",
|
||||
"0.3",
|
||||
extra_files={initools_v3_file_name: "# Hi!"},
|
||||
)
|
||||
|
||||
_patch_dist_in_site_packages(virtualenv)
|
||||
|
||||
script.pip("install", "INITools==0.2", "--no-binary=:all:")
|
||||
script.pip("install", "--user", "INITools==0.3", "--no-binary=:all:")
|
||||
|
||||
result3 = script.pip("install", "--user", "INITools==0.1", "--no-binary=:all:")
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"initools==0.2",
|
||||
)
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--user",
|
||||
"initools==0.3",
|
||||
)
|
||||
result3 = script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--user",
|
||||
"initools==0.1",
|
||||
)
|
||||
|
||||
# usersite has 0.1
|
||||
# we still test for egg-info because no-binary implies setup.py install
|
||||
egg_info_folder = script.user_site / f"INITools-0.1-py{pyversion}.egg-info"
|
||||
initools_v3_file = (
|
||||
# file only in 0.3
|
||||
script.base_path
|
||||
/ script.user_site
|
||||
/ "initools"
|
||||
/ "configparser.py"
|
||||
)
|
||||
result3.did_create(egg_info_folder)
|
||||
dist_info_folder = script.user_site / "initools-0.1.dist-info"
|
||||
result3.did_create(dist_info_folder)
|
||||
initools_v3_file = script.base_path / script.user_site / initools_v3_file_name
|
||||
assert not isfile(initools_v3_file), initools_v3_file
|
||||
|
||||
# site still has 0.2 (can't just look in result1; have to check)
|
||||
egg_info_folder = (
|
||||
script.base_path
|
||||
/ script.site_packages
|
||||
/ f"INITools-0.2-py{pyversion}.egg-info"
|
||||
dist_info_folder = (
|
||||
script.base_path / script.site_packages / "initools-0.2.dist-info"
|
||||
)
|
||||
initools_folder = script.base_path / script.site_packages / "initools"
|
||||
assert isdir(egg_info_folder)
|
||||
assert isdir(dist_info_folder)
|
||||
assert isdir(initools_folder)
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_install_user_in_global_virtualenv_with_conflict_fails(
|
||||
self, script: PipTestEnvironment
|
||||
) -> None:
|
||||
|
@ -255,27 +294,37 @@ class Tests_UserSite:
|
|||
Test user install in --system-site-packages virtualenv with conflict in
|
||||
site fails.
|
||||
"""
|
||||
create_basic_wheel_for_package(script, "pkg", "0.1")
|
||||
create_basic_wheel_for_package(script, "pkg", "0.2")
|
||||
|
||||
script.pip("install", "INITools==0.2")
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-cache-dir",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"pkg==0.2",
|
||||
)
|
||||
|
||||
result2 = script.pip(
|
||||
"install",
|
||||
"--no-cache-dir",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--user",
|
||||
"INITools==0.1",
|
||||
"pkg==0.1",
|
||||
expect_error=True,
|
||||
)
|
||||
resultp = script.run(
|
||||
"python",
|
||||
"-c",
|
||||
"import pkg_resources; print(pkg_resources.get_distribution"
|
||||
"('initools').location)",
|
||||
"from pip._internal.metadata import get_default_environment; "
|
||||
"print(get_default_environment().get_distribution('pkg').location)",
|
||||
)
|
||||
dist_location = resultp.stdout.strip()
|
||||
|
||||
assert (
|
||||
"Will not install to the user site because it will lack sys.path "
|
||||
"precedence to {name} in {location}".format(
|
||||
name="INITools",
|
||||
location=dist_location,
|
||||
)
|
||||
in result2.stderr
|
||||
)
|
||||
f"Will not install to the user site because it will lack sys.path "
|
||||
f"precedence to pkg in {dist_location}"
|
||||
) in result2.stderr
|
||||
|
|
|
@ -544,6 +544,11 @@ def test_reinstalling_works_with_editable_non_master_branch(
|
|||
|
||||
# TODO(pnasrat) fix all helpers to do right things with paths on windows.
|
||||
@pytest.mark.skipif("sys.platform == 'win32'")
|
||||
@pytest.mark.xfail(
|
||||
condition=True,
|
||||
reason="Git submodule against file: is not working; waiting for a good solution",
|
||||
run=True,
|
||||
)
|
||||
def test_check_submodule_addition(script: PipTestEnvironment) -> None:
|
||||
"""
|
||||
Submodules are pulled in on install and updated on upgrade.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import base64
|
||||
import csv
|
||||
import distutils
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
import sysconfig
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
@ -284,7 +284,9 @@ def test_install_wheel_with_prefix(
|
|||
"--find-links",
|
||||
tmpdir,
|
||||
)
|
||||
lib = distutils.sysconfig.get_python_lib(prefix=os.path.join("scratch", "prefix"))
|
||||
lib = sysconfig.get_path(
|
||||
"purelib", vars={"base": os.path.join("scratch", "prefix")}
|
||||
)
|
||||
result.did_create(lib)
|
||||
|
||||
|
||||
|
@ -404,8 +406,7 @@ def test_wheel_record_lines_have_updated_hash_for_scripts(
|
|||
]
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("with_wheel")
|
||||
@pytest.mark.usefixtures("enable_user_site", "with_wheel")
|
||||
def test_install_user_wheel(
|
||||
script: PipTestEnvironment, shared_data: TestData, tmpdir: Path
|
||||
) -> None:
|
||||
|
|
|
@ -129,7 +129,7 @@ def test_multiple_exclude_and_normalization(
|
|||
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_user_flag(script: PipTestEnvironment, data: TestData) -> None:
|
||||
"""
|
||||
Test the behavior of --user flag in the list command
|
||||
|
@ -144,7 +144,7 @@ def test_user_flag(script: PipTestEnvironment, data: TestData) -> None:
|
|||
|
||||
|
||||
@pytest.mark.network
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_user_columns_flag(script: PipTestEnvironment, data: TestData) -> None:
|
||||
"""
|
||||
Test the behavior of --user --format=columns flags in the list command
|
||||
|
@ -656,7 +656,7 @@ def test_list_path(tmpdir: Path, script: PipTestEnvironment, data: TestData) ->
|
|||
assert {"name": "simple", "version": "2.0"} in json_result
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_list_path_exclude_user(
|
||||
tmpdir: Path, script: PipTestEnvironment, data: TestData
|
||||
) -> None:
|
||||
|
|
|
@ -7,7 +7,7 @@ from tests.lib import PipTestEnvironment, create_basic_wheel_for_package
|
|||
from tests.lib.venv import VirtualEnvironment
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_new_resolver_install_user(script: PipTestEnvironment) -> None:
|
||||
create_basic_wheel_for_package(script, "base", "0.1.0")
|
||||
result = script.pip(
|
||||
|
@ -22,7 +22,7 @@ def test_new_resolver_install_user(script: PipTestEnvironment) -> None:
|
|||
result.did_create(script.user_site / "base")
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_new_resolver_install_user_satisfied_by_global_site(
|
||||
script: PipTestEnvironment,
|
||||
) -> None:
|
||||
|
@ -53,7 +53,7 @@ def test_new_resolver_install_user_satisfied_by_global_site(
|
|||
result.did_not_create(script.user_site / "base")
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
def test_new_resolver_install_user_conflict_in_user_site(
|
||||
script: PipTestEnvironment,
|
||||
) -> None:
|
||||
|
@ -91,39 +91,6 @@ def test_new_resolver_install_user_conflict_in_user_site(
|
|||
result.did_not_create(base_2_dist_info)
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_new_resolver_install_user_in_virtualenv_with_conflict_fails(
|
||||
script: PipTestEnvironment,
|
||||
) -> None:
|
||||
create_basic_wheel_for_package(script, "base", "1.0.0")
|
||||
create_basic_wheel_for_package(script, "base", "2.0.0")
|
||||
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-cache-dir",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"base==2.0.0",
|
||||
)
|
||||
result = script.pip(
|
||||
"install",
|
||||
"--no-cache-dir",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--user",
|
||||
"base==1.0.0",
|
||||
expect_error=True,
|
||||
)
|
||||
|
||||
error_message = (
|
||||
"Will not install to the user site because it will lack sys.path "
|
||||
"precedence to base in {}"
|
||||
).format(os.path.normcase(script.site_packages_path))
|
||||
assert error_message in result.stderr
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def patch_dist_in_site_packages(virtualenv: VirtualEnvironment) -> None:
|
||||
# Since the tests are run from a virtualenv, and to avoid the "Will not
|
||||
|
@ -141,8 +108,7 @@ def patch_dist_in_site_packages(virtualenv: VirtualEnvironment) -> None:
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("patch_dist_in_site_packages")
|
||||
@pytest.mark.usefixtures("enable_user_site", "patch_dist_in_site_packages")
|
||||
def test_new_resolver_install_user_reinstall_global_site(
|
||||
script: PipTestEnvironment,
|
||||
) -> None:
|
||||
|
@ -177,8 +143,7 @@ def test_new_resolver_install_user_reinstall_global_site(
|
|||
assert "base" in site_packages_content
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("patch_dist_in_site_packages")
|
||||
@pytest.mark.usefixtures("enable_user_site", "patch_dist_in_site_packages")
|
||||
def test_new_resolver_install_user_conflict_in_global_site(
|
||||
script: PipTestEnvironment,
|
||||
) -> None:
|
||||
|
@ -215,8 +180,7 @@ def test_new_resolver_install_user_conflict_in_global_site(
|
|||
assert "base-1.0.0.dist-info" in site_packages_content
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("patch_dist_in_site_packages")
|
||||
@pytest.mark.usefixtures("enable_user_site", "patch_dist_in_site_packages")
|
||||
def test_new_resolver_install_user_conflict_in_global_and_user_sites(
|
||||
script: PipTestEnvironment,
|
||||
) -> None:
|
||||
|
|
|
@ -6,12 +6,12 @@ from os.path import isdir, isfile, normcase
|
|||
import pytest
|
||||
|
||||
from tests.functional.test_install_user import _patch_dist_in_site_packages
|
||||
from tests.lib import pyversion # noqa: F401
|
||||
from tests.lib import PipTestEnvironment, TestData, assert_all_changes
|
||||
from tests.lib.venv import VirtualEnvironment
|
||||
from tests.lib.wheel import make_wheel
|
||||
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
@pytest.mark.usefixtures("enable_user_site")
|
||||
class Tests_UninstallUserSite:
|
||||
@pytest.mark.network
|
||||
def test_uninstall_from_usersite(self, script: PipTestEnvironment) -> None:
|
||||
|
@ -28,14 +28,39 @@ class Tests_UninstallUserSite:
|
|||
"""
|
||||
Test uninstall from usersite (with same dist in global site)
|
||||
"""
|
||||
entry_points_txt = "[console_scripts]\nscript = pkg:func"
|
||||
make_wheel(
|
||||
"pkg",
|
||||
"0.1",
|
||||
extra_metadata_files={"entry_points.txt": entry_points_txt},
|
||||
).save_to_dir(script.scratch_path)
|
||||
make_wheel(
|
||||
"pkg",
|
||||
"0.1.1",
|
||||
extra_metadata_files={"entry_points.txt": entry_points_txt},
|
||||
).save_to_dir(script.scratch_path)
|
||||
|
||||
_patch_dist_in_site_packages(virtualenv)
|
||||
|
||||
script.pip_install_local("pip-test-package==0.1", "--no-binary=:all:")
|
||||
|
||||
result2 = script.pip_install_local(
|
||||
"--user", "pip-test-package==0.1.1", "--no-binary=:all:"
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--no-warn-script-location",
|
||||
"pkg==0.1",
|
||||
)
|
||||
result3 = script.pip("uninstall", "-vy", "pip-test-package")
|
||||
|
||||
result2 = script.pip(
|
||||
"install",
|
||||
"--no-index",
|
||||
"--find-links",
|
||||
script.scratch_path,
|
||||
"--no-warn-script-location",
|
||||
"--user",
|
||||
"pkg==0.1.1",
|
||||
)
|
||||
result3 = script.pip("uninstall", "-vy", "pkg")
|
||||
|
||||
# uninstall console is mentioning user scripts, but not global scripts
|
||||
assert normcase(script.user_bin_path) in result3.stdout, str(result3)
|
||||
|
@ -45,13 +70,8 @@ class Tests_UninstallUserSite:
|
|||
assert_all_changes(result2, result3, [script.venv / "build", "cache"])
|
||||
|
||||
# site still has 0.2 (can't look in result1; have to check)
|
||||
# keep checking for egg-info because no-binary implies setup.py install
|
||||
egg_info_folder = (
|
||||
script.base_path
|
||||
/ script.site_packages
|
||||
/ f"pip_test_package-0.1-py{pyversion}.egg-info"
|
||||
)
|
||||
assert isdir(egg_info_folder)
|
||||
dist_info_folder = script.base_path / script.site_packages / "pkg-0.1.dist-info"
|
||||
assert isdir(dist_info_folder)
|
||||
|
||||
def test_uninstall_editable_from_usersite(
|
||||
self, script: PipTestEnvironment, data: TestData
|
||||
|
|
|
@ -3,10 +3,11 @@ import os
|
|||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
import textwrap
|
||||
import venv as _venv
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
from typing import TYPE_CHECKING, Dict, Optional, Union
|
||||
|
||||
import virtualenv as _virtualenv
|
||||
|
||||
|
@ -30,7 +31,7 @@ class VirtualEnvironment:
|
|||
location: Path,
|
||||
template: Optional["VirtualEnvironment"] = None,
|
||||
venv_type: Optional[VirtualEnvironmentType] = None,
|
||||
):
|
||||
) -> None:
|
||||
self.location = location
|
||||
assert template is None or venv_type is None
|
||||
self._venv_type: VirtualEnvironmentType
|
||||
|
@ -46,7 +47,13 @@ class VirtualEnvironment:
|
|||
self._update_paths()
|
||||
self._create()
|
||||
|
||||
def _update_paths(self) -> None:
|
||||
@property
|
||||
def _legacy_virtualenv(self) -> bool:
|
||||
if self._venv_type != "virtualenv":
|
||||
return False
|
||||
return int(_virtualenv.__version__.split(".", 1)[0]) < 20
|
||||
|
||||
def __update_paths_legacy(self) -> None:
|
||||
home, lib, inc, bin = _virtualenv.path_locations(self.location)
|
||||
self.bin = Path(bin)
|
||||
self.site = Path(lib) / "site-packages"
|
||||
|
@ -57,6 +64,21 @@ class VirtualEnvironment:
|
|||
else:
|
||||
self.lib = Path(lib)
|
||||
|
||||
def _update_paths(self) -> None:
|
||||
if self._legacy_virtualenv:
|
||||
self.__update_paths_legacy()
|
||||
return
|
||||
bases = {
|
||||
"installed_base": self.location,
|
||||
"installed_platbase": self.location,
|
||||
"base": self.location,
|
||||
"platbase": self.location,
|
||||
}
|
||||
paths = sysconfig.get_paths(vars=bases)
|
||||
self.bin = Path(paths["scripts"])
|
||||
self.site = Path(paths["purelib"])
|
||||
self.lib = Path(paths["stdlib"])
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<VirtualEnvironment {self.location}>"
|
||||
|
||||
|
@ -66,7 +88,11 @@ class VirtualEnvironment:
|
|||
if self._template:
|
||||
# On Windows, calling `_virtualenv.path_locations(target)`
|
||||
# will have created the `target` directory...
|
||||
if sys.platform == "win32" and self.location.exists():
|
||||
if (
|
||||
self._legacy_virtualenv
|
||||
and sys.platform == "win32"
|
||||
and self.location.exists()
|
||||
):
|
||||
self.location.rmdir()
|
||||
# Clone virtual environment from template.
|
||||
shutil.copytree(self._template.location, self.location, symlinks=True)
|
||||
|
@ -74,7 +100,7 @@ class VirtualEnvironment:
|
|||
self._user_site_packages = self._template.user_site_packages
|
||||
else:
|
||||
# Create a new virtual environment.
|
||||
if self._venv_type == "virtualenv":
|
||||
if self._legacy_virtualenv:
|
||||
subprocess.check_call(
|
||||
[
|
||||
sys.executable,
|
||||
|
@ -83,20 +109,31 @@ class VirtualEnvironment:
|
|||
"--no-pip",
|
||||
"--no-wheel",
|
||||
"--no-setuptools",
|
||||
str(self.location),
|
||||
os.fspath(self.location),
|
||||
]
|
||||
)
|
||||
self._fix_virtualenv_site_module()
|
||||
self._fix_legacy_virtualenv_site_module()
|
||||
elif self._venv_type == "virtualenv":
|
||||
_virtualenv.cli_run(
|
||||
[
|
||||
"--no-pip",
|
||||
"--no-wheel",
|
||||
"--no-setuptools",
|
||||
os.fspath(self.location),
|
||||
],
|
||||
)
|
||||
elif self._venv_type == "venv":
|
||||
builder = _venv.EnvBuilder()
|
||||
context = builder.ensure_directories(self.location)
|
||||
builder.create_configuration(context)
|
||||
builder.setup_python(context)
|
||||
self.site.mkdir(parents=True, exist_ok=True)
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported venv type {self._venv_type!r}")
|
||||
self.sitecustomize = self._sitecustomize
|
||||
self.user_site_packages = self._user_site_packages
|
||||
|
||||
def _fix_virtualenv_site_module(self) -> None:
|
||||
def _fix_legacy_virtualenv_site_module(self) -> None:
|
||||
# Patch `site.py` so user site work as expected.
|
||||
site_py = self.lib / "site.py"
|
||||
with open(site_py) as fp:
|
||||
|
@ -131,17 +168,15 @@ class VirtualEnvironment:
|
|||
assert compileall.compile_file(str(site_py), quiet=1, force=True)
|
||||
|
||||
def _customize_site(self) -> None:
|
||||
contents = ""
|
||||
if self._venv_type == "venv":
|
||||
if self._legacy_virtualenv:
|
||||
contents = ""
|
||||
else:
|
||||
# Enable user site (before system).
|
||||
contents += textwrap.dedent(
|
||||
"""
|
||||
contents = textwrap.dedent(
|
||||
f"""
|
||||
import os, site, sys
|
||||
|
||||
if not os.environ.get('PYTHONNOUSERSITE', False):
|
||||
|
||||
site.ENABLE_USER_SITE = True
|
||||
|
||||
site.ENABLE_USER_SITE = {self._user_site_packages}
|
||||
# First, drop system-sites related paths.
|
||||
original_sys_path = sys.path[:]
|
||||
known_paths = set()
|
||||
|
@ -152,10 +187,9 @@ class VirtualEnvironment:
|
|||
if path in original_sys_path:
|
||||
original_sys_path.remove(path)
|
||||
sys.path = original_sys_path
|
||||
|
||||
# Second, add user-site.
|
||||
site.addsitedir(site.getusersitepackages())
|
||||
|
||||
if {self._user_site_packages}:
|
||||
site.addsitedir(site.getusersitepackages())
|
||||
# Third, add back system-sites related paths.
|
||||
for path in site.getsitepackages():
|
||||
site.addsitedir(path)
|
||||
|
@ -168,6 +202,21 @@ class VirtualEnvironment:
|
|||
# Make sure bytecode is up-to-date too.
|
||||
assert compileall.compile_file(str(sitecustomize), quiet=1, force=True)
|
||||
|
||||
def _rewrite_pyvenv_cfg(self, replacements: Dict[str, str]) -> None:
|
||||
pyvenv_cfg = self.location.joinpath("pyvenv.cfg")
|
||||
lines = pyvenv_cfg.read_text(encoding="utf-8").splitlines()
|
||||
|
||||
def maybe_replace_line(line: str) -> str:
|
||||
key = line.split("=", 1)[0].strip()
|
||||
try:
|
||||
value = replacements[key]
|
||||
except KeyError: # No need to replace.
|
||||
return line
|
||||
return f"{key} = {value}"
|
||||
|
||||
lines = [maybe_replace_line(line) for line in lines]
|
||||
pyvenv_cfg.write_text("\n".join(lines), encoding="utf-8")
|
||||
|
||||
def clear(self) -> None:
|
||||
self._create(clear=True)
|
||||
|
||||
|
@ -192,11 +241,14 @@ class VirtualEnvironment:
|
|||
@user_site_packages.setter
|
||||
def user_site_packages(self, value: bool) -> None:
|
||||
self._user_site_packages = value
|
||||
if self._venv_type == "virtualenv":
|
||||
if self._legacy_virtualenv:
|
||||
marker = self.lib / "no-global-site-packages.txt"
|
||||
if self._user_site_packages:
|
||||
marker.unlink()
|
||||
else:
|
||||
marker.touch()
|
||||
elif self._venv_type == "venv":
|
||||
else:
|
||||
self._rewrite_pyvenv_cfg(
|
||||
{"include-system-site-packages": str(bool(value)).lower()}
|
||||
)
|
||||
self._customize_site()
|
||||
|
|
|
@ -7,7 +7,8 @@ pytest-rerunfailures
|
|||
pytest-xdist
|
||||
scripttest
|
||||
setuptools
|
||||
virtualenv < 20.0
|
||||
virtualenv < 20.0 ; python_version < '3.10'
|
||||
virtualenv >= 20.0 ; python_version >= '3.10'
|
||||
werkzeug
|
||||
wheel
|
||||
tomli-w
|
||||
|
|
|
@ -63,7 +63,7 @@ def test_virtualenv_no_global_with_regular_virtualenv(
|
|||
monkeypatch.setattr(site, "__file__", os.fspath(tmpdir / "site.py"))
|
||||
monkeypatch.setattr(
|
||||
virtualenv,
|
||||
"_running_under_regular_virtualenv",
|
||||
"_running_under_legacy_virtualenv",
|
||||
lambda: under_virtualenv,
|
||||
)
|
||||
if no_global_file:
|
||||
|
@ -73,7 +73,7 @@ def test_virtualenv_no_global_with_regular_virtualenv(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"pyvenv_cfg_lines, under_venv, expected, expect_warning",
|
||||
"pyvenv_cfg_lines, under_venv, expect_no_global, expect_warning",
|
||||
[
|
||||
(None, False, False, False),
|
||||
(None, True, True, True), # this has a warning.
|
||||
|
@ -104,15 +104,15 @@ def test_virtualenv_no_global_with_pep_405_virtual_environment(
|
|||
caplog: pytest.LogCaptureFixture,
|
||||
pyvenv_cfg_lines: Optional[List[str]],
|
||||
under_venv: bool,
|
||||
expected: bool,
|
||||
expect_no_global: bool,
|
||||
expect_warning: bool,
|
||||
) -> None:
|
||||
monkeypatch.setattr(virtualenv, "_running_under_regular_virtualenv", lambda: False)
|
||||
monkeypatch.setattr(virtualenv, "_running_under_legacy_virtualenv", lambda: False)
|
||||
monkeypatch.setattr(virtualenv, "_get_pyvenv_cfg_lines", lambda: pyvenv_cfg_lines)
|
||||
monkeypatch.setattr(virtualenv, "_running_under_venv", lambda: under_venv)
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
assert virtualenv.virtualenv_no_global() == expected
|
||||
assert virtualenv.virtualenv_no_global() == expect_no_global
|
||||
|
||||
if expect_warning:
|
||||
assert caplog.records
|
||||
|
|
|
@ -3,6 +3,7 @@ import csv
|
|||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import textwrap
|
||||
from email import message_from_string
|
||||
from pathlib import Path
|
||||
|
@ -22,7 +23,11 @@ from pip._internal.models.direct_url import (
|
|||
from pip._internal.models.scheme import Scheme
|
||||
from pip._internal.operations.build.wheel_legacy import get_legacy_build_wheel_path
|
||||
from pip._internal.operations.install import wheel
|
||||
from pip._internal.operations.install.wheel import InstalledCSVRow, RecordPath
|
||||
from pip._internal.operations.install.wheel import (
|
||||
InstalledCSVRow,
|
||||
RecordPath,
|
||||
get_console_script_specs,
|
||||
)
|
||||
from pip._internal.utils.compat import WINDOWS
|
||||
from pip._internal.utils.misc import hash_file
|
||||
from pip._internal.utils.unpacking import unpack_file
|
||||
|
@ -681,3 +686,31 @@ class TestWheelHashCalculators:
|
|||
h, length = wheel.rehash(os.fspath(self.test_file))
|
||||
assert length == str(self.test_file_len)
|
||||
assert h == self.test_file_hash_encoded
|
||||
|
||||
|
||||
def test_get_console_script_specs_replaces_python_version(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
# Fake Python version.
|
||||
monkeypatch.setattr(sys, "version_info", (10, 11))
|
||||
|
||||
entry_points = {
|
||||
"pip": "real_pip",
|
||||
"pip99": "whatever",
|
||||
"pip99.88": "whatever",
|
||||
"easy_install": "real_easy_install",
|
||||
"easy_install-99.88": "whatever",
|
||||
# The following shouldn't be replaced.
|
||||
"not_pip_or_easy_install-99": "whatever",
|
||||
"not_pip_or_easy_install-99.88": "whatever",
|
||||
}
|
||||
specs = get_console_script_specs(entry_points)
|
||||
assert specs == [
|
||||
"pip = real_pip",
|
||||
"pip10 = real_pip",
|
||||
"pip10.11 = real_pip",
|
||||
"easy_install = real_easy_install",
|
||||
"easy_install-10.11 = real_easy_install",
|
||||
"not_pip_or_easy_install-99 = whatever",
|
||||
"not_pip_or_easy_install-99.88 = whatever",
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue