diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 4bd3f7da5..890783ed5 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: py: - - "3.11.0-beta.5" + - "3.11.0-rc.2" - "3.10" - "3.9" - "3.8" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 889d5273b..4b94ef19b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,11 +12,14 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/asottile/pyupgrade - rev: v2.37.3 + rev: v3.1.0 hooks: - id: pyupgrade args: ["--py36-plus"] exclude: "^(src/virtualenv/create/via_global_ref/_virtualenv.py|src/virtualenv/create/via_global_ref/builtin/python2/site.py|src/virtualenv/discovery/py_info.py|tasks/__main__zipapp.py)$" +- repo: https://github.com/asottile/pyupgrade + rev: v2.38.4 + hooks: - id: pyupgrade files: "^(src/virtualenv/create/via_global_ref/_virtualenv.py|src/virtualenv/create/via_global_ref/builtin/python2/site.py|src/virtualenv/discovery/py_info.py|tasks/__main__zipapp.py)$" - repo: https://github.com/PyCQA/isort @@ -24,7 +27,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.8.0 + rev: 22.10.0 hooks: - id: black args: [--safe] @@ -32,7 +35,7 @@ repos: rev: v1.12.1 hooks: - id: blacken-docs - additional_dependencies: [black==22.6] + additional_dependencies: [black==22.10] - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.9.0 hooks: @@ -43,7 +46,7 @@ repos: - id: tox-ini-fmt args: ["-p", "fix_lint"] - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.0.0 + rev: v2.2.0 hooks: - id: setup-cfg-fmt args: [--min-py3-version, "3.6 ", "--max-py-version", "3.10"] @@ -52,10 +55,10 @@ repos: hooks: - id: flake8 additional_dependencies: - - flake8-bugbear==22.7.1 + - flake8-bugbear==22.10.25 - flake8-comprehensions==3.10 - flake8-pytest-style==1.6 - flake8-spellcheck==0.28 - - flake8-unused-arguments==0.0.11 + - flake8-unused-arguments==0.0.12 - flake8-noqa==1.2.9 - pep8-naming==0.13.2 diff --git a/docs/changelog.rst b/docs/changelog.rst index e7ea9886f..a8008662e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,21 @@ Release History .. towncrier release notes start +v20.16.6 (2022-10-25) +--------------------- + +Features - 20.16.6 +~~~~~~~~~~~~~~~~~~ +- Drop unneeded shims for PyPy3 directory structure (`#2426 `_) + +Bugfixes - 20.16.6 +~~~~~~~~~~~~~~~~~~ +- Fix selected scheme on debian derivatives for python 3.10 when ``python3-distutils`` is not installed or the ``venv`` scheme is not avaiable - by :user:`asottile`. (`#2350 `_) +- Allow the test suite to pass even with the original C shell (rather than ``tcsh``) - by :user:`kulikjak`. (`#2418 `_) +- Fix fallback handling of downloading wheels for bundled packages - by :user:`schaap`. (`#2429 `_) +- Upgrade embedded setuptools to ``65.5.0`` from ``65.3.0`` and pip to ``22.3`` from ``22.2.2`` - by :user:`gaborbernat`. (`#2434 `_) + + v20.16.5 (2022-09-07) --------------------- diff --git a/docs/installation.rst b/docs/installation.rst index 46956fe25..57e57d968 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -89,7 +89,7 @@ Python and OS Compatibility virtualenv works with the following Python interpreter implementations: - `CPython `_ versions 2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10 -- `PyPy `_ 2.7 and 3.5+. +- `PyPy `_ 2.7, 3.6, 3.7, 3.8, 3.9 This means virtualenv works on the latest patch version of each of these minor versions. Previous patch versions are supported on a best effort approach. diff --git a/setup.cfg b/setup.cfg index 12016fb3f..2b754068e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,7 +33,7 @@ project_urls = [options] packages = find: install_requires = - distlib>=0.3.5,<1 + distlib>=0.3.6,<1 filelock>=3.4.1,<4 platformdirs>=2.4,<3 importlib-metadata>=4.8.3;python_version < "3.8" @@ -79,10 +79,10 @@ virtualenv.seed = [options.extras_require] docs = proselint>=0.13 - sphinx>=5.1.1 - sphinx-argparse>=0.3.1 + sphinx>=5.3 + sphinx-argparse>=0.3.2 sphinx-rtd-theme>=1 - towncrier>=21.9 + towncrier>=22.8 testing = coverage>=6.2 coverage-enable-subprocess>=1 diff --git a/src/virtualenv/activation/activator.py b/src/virtualenv/activation/activator.py index fb813bc7d..99f2803bc 100644 --- a/src/virtualenv/activation/activator.py +++ b/src/virtualenv/activation/activator.py @@ -22,7 +22,7 @@ def supports(cls, interpreter): # noqa: U100 return True @classmethod - def add_parser_arguments(cls, parser, interpreter): # noqa: U100 + def add_parser_arguments(cls, parser, interpreter): # noqa: U100,B027 """ Add CLI arguments for this activation script. diff --git a/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py b/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py index ca5778c2c..9db36e848 100644 --- a/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py +++ b/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py @@ -20,11 +20,6 @@ def exe_names(cls, interpreter): class PyPy3Posix(PyPy3, PosixSupports): """PyPy 3 on POSIX""" - @property - def stdlib(self): - """PyPy3 respects sysconfig only for the host python, virtual envs is instead lib/pythonx.y/site-packages""" - return self.dest / "lib" / f"pypy{self.interpreter.version_release_str}" / "site-packages" - @classmethod def _shared_libs(cls, python_dir): # glob for libpypy3-c.so, libpypy3-c.dylib, libpypy3.9-c.so ... @@ -64,18 +59,6 @@ class Pypy3Windows(PyPy3, WindowsSupports): def less_v37(self): return self.interpreter.version_info.minor < 7 - @property - def stdlib(self): - """PyPy3 respects sysconfig only for the host python, virtual envs is instead Lib/site-packages""" - if self.less_v37: - return self.dest / "site-packages" - return self.dest / "Lib" / "site-packages" - - @property - def bin_dir(self): - """PyPy3 needs to fallback to pypy definition""" - return self.dest / "Scripts" - @classmethod def _shared_libs(cls, python_dir): # glob for libpypy*.dll and libffi*.dll diff --git a/src/virtualenv/discovery/py_info.py b/src/virtualenv/discovery/py_info.py index 2a648e049..7c680eeaa 100644 --- a/src/virtualenv/discovery/py_info.py +++ b/src/virtualenv/discovery/py_info.py @@ -77,10 +77,23 @@ def abs_path(v): self.file_system_encoding = u(sys.getfilesystemencoding()) self.stdout_encoding = u(getattr(sys.stdout, "encoding", None)) - if "venv" in sysconfig.get_scheme_names(): + scheme_names = sysconfig.get_scheme_names() + + if "venv" in scheme_names: self.sysconfig_scheme = "venv" self.sysconfig_paths = { - u(i): u(sysconfig.get_path(i, expand=False, scheme="venv")) for i in sysconfig.get_path_names() + u(i): u(sysconfig.get_path(i, expand=False, scheme=self.sysconfig_scheme)) + for i in sysconfig.get_path_names() + } + # we cannot use distutils at all if "venv" exists, distutils don't know it + self.distutils_install = {} + # debian / ubuntu python 3.10 without `python3-distutils` will report + # mangled `local/bin` / etc. names for the default prefix + # intentionally select `posix_prefix` which is the unaltered posix-like paths + elif sys.version_info[:2] == (3, 10) and "deb_system" in scheme_names: + self.sysconfig_scheme = "posix_prefix" + self.sysconfig_paths = { + i: sysconfig.get_path(i, expand=False, scheme=self.sysconfig_scheme) for i in sysconfig.get_path_names() } # we cannot use distutils at all if "venv" exists, distutils don't know it self.distutils_install = {} diff --git a/src/virtualenv/seed/wheels/acquire.py b/src/virtualenv/seed/wheels/acquire.py index d8e8d1e38..d1fb3f389 100644 --- a/src/virtualenv/seed/wheels/acquire.py +++ b/src/virtualenv/seed/wheels/acquire.py @@ -83,7 +83,7 @@ def _find_downloaded_wheel(distribution, version_spec, for_py_version, to_folder def find_compatible_in_house(distribution, version_spec, for_py_version, in_folder): wheels = discover_wheels(in_folder, distribution, None, for_py_version) start, end = 0, len(wheels) - if version_spec is not None: + if version_spec is not None and version_spec != "": if version_spec.startswith("<"): from_pos, op = 1, lt elif version_spec.startswith("=="): diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py index 70ea23c4b..3bd41ba37 100644 --- a/src/virtualenv/seed/wheels/embed/__init__.py +++ b/src/virtualenv/seed/wheels/embed/__init__.py @@ -5,28 +5,28 @@ BUNDLE_FOLDER = Path(__file__).absolute().parent BUNDLE_SUPPORT = { "3.11": { - "pip": "pip-22.2.2-py3-none-any.whl", - "setuptools": "setuptools-65.3.0-py3-none-any.whl", + "pip": "pip-22.3-py3-none-any.whl", + "setuptools": "setuptools-65.5.0-py3-none-any.whl", "wheel": "wheel-0.37.1-py2.py3-none-any.whl", }, "3.10": { - "pip": "pip-22.2.2-py3-none-any.whl", - "setuptools": "setuptools-65.3.0-py3-none-any.whl", + "pip": "pip-22.3-py3-none-any.whl", + "setuptools": "setuptools-65.5.0-py3-none-any.whl", "wheel": "wheel-0.37.1-py2.py3-none-any.whl", }, "3.9": { - "pip": "pip-22.2.2-py3-none-any.whl", - "setuptools": "setuptools-65.3.0-py3-none-any.whl", + "pip": "pip-22.3-py3-none-any.whl", + "setuptools": "setuptools-65.5.0-py3-none-any.whl", "wheel": "wheel-0.37.1-py2.py3-none-any.whl", }, "3.8": { - "pip": "pip-22.2.2-py3-none-any.whl", - "setuptools": "setuptools-65.3.0-py3-none-any.whl", + "pip": "pip-22.3-py3-none-any.whl", + "setuptools": "setuptools-65.5.0-py3-none-any.whl", "wheel": "wheel-0.37.1-py2.py3-none-any.whl", }, "3.7": { - "pip": "pip-22.2.2-py3-none-any.whl", - "setuptools": "setuptools-65.3.0-py3-none-any.whl", + "pip": "pip-22.3-py3-none-any.whl", + "setuptools": "setuptools-65.5.0-py3-none-any.whl", "wheel": "wheel-0.37.1-py2.py3-none-any.whl", }, "3.6": { diff --git a/src/virtualenv/seed/wheels/embed/pip-22.2.2-py3-none-any.whl b/src/virtualenv/seed/wheels/embed/pip-22.3-py3-none-any.whl similarity index 62% rename from src/virtualenv/seed/wheels/embed/pip-22.2.2-py3-none-any.whl rename to src/virtualenv/seed/wheels/embed/pip-22.3-py3-none-any.whl index 03099718b..d6fccd9de 100644 Binary files a/src/virtualenv/seed/wheels/embed/pip-22.2.2-py3-none-any.whl and b/src/virtualenv/seed/wheels/embed/pip-22.3-py3-none-any.whl differ diff --git a/src/virtualenv/seed/wheels/embed/setuptools-65.3.0-py3-none-any.whl b/src/virtualenv/seed/wheels/embed/setuptools-65.5.0-py3-none-any.whl similarity index 90% rename from src/virtualenv/seed/wheels/embed/setuptools-65.3.0-py3-none-any.whl rename to src/virtualenv/seed/wheels/embed/setuptools-65.5.0-py3-none-any.whl index 1422fc9ec..123a13e2c 100644 Binary files a/src/virtualenv/seed/wheels/embed/setuptools-65.3.0-py3-none-any.whl and b/src/virtualenv/seed/wheels/embed/setuptools-65.5.0-py3-none-any.whl differ diff --git a/tasks/update_embedded.py b/tasks/update_embedded.py index ba43b303f..2f44531e5 100755 --- a/tasks/update_embedded.py +++ b/tasks/update_embedded.py @@ -66,7 +66,7 @@ def handle_file(previous_content, filename, variable_name, previous_encoded): def report(exit_code, new, next_match, current, script_path): if new != current: print("Content updated; overwriting... ", end="") - with open(script_path, "wt") as current_fh: + with open(script_path, "w") as current_fh: current_fh.write(new) print("done.") else: diff --git a/tests/unit/activation/test_csh.py b/tests/unit/activation/test_csh.py index f9539c5af..afdb08f49 100644 --- a/tests/unit/activation/test_csh.py +++ b/tests/unit/activation/test_csh.py @@ -7,6 +7,8 @@ def __init__(self, session): super().__init__(CShellActivator, session, "csh", "activate.csh", "csh") def print_prompt(self): - return "echo 'source \"$VIRTUAL_ENV/bin/activate.csh\"; echo $prompt' | csh -i" + # Original csh doesn't print the last newline, + # breaking the test; hence the trailing echo. + return "echo 'source \"$VIRTUAL_ENV/bin/activate.csh\"; echo $prompt' | csh -i ; echo" activation_tester(Csh) diff --git a/tests/unit/discovery/py_info/test_py_info.py b/tests/unit/discovery/py_info/test_py_info.py index 9d3d762e5..f621224ee 100644 --- a/tests/unit/discovery/py_info/test_py_info.py +++ b/tests/unit/discovery/py_info/test_py_info.py @@ -1,4 +1,5 @@ import copy +import functools import itertools import json import logging @@ -375,3 +376,73 @@ def test_custom_venv_install_scheme_is_prefered(mocker): pyver = f"{pyinfo.version_info.major}.{pyinfo.version_info.minor}" assert pyinfo.install_path("scripts") == "bin" assert pyinfo.install_path("purelib").replace(os.sep, "/") == f"lib/python{pyver}/site-packages" + + +@pytest.mark.skipif(sys.version_info[:2] != (3, 10), reason="3.10 specific") +def test_uses_posix_prefix_on_debian_3_10_without_venv(mocker): + # this is taken from ubuntu 22.04 /usr/lib/python3.10/sysconfig.py + sysconfig_install_schemes = { + "posix_prefix": { + "stdlib": "{installed_base}/{platlibdir}/python{py_version_short}", + "platstdlib": "{platbase}/{platlibdir}/python{py_version_short}", + "purelib": "{base}/lib/python{py_version_short}/site-packages", + "platlib": "{platbase}/{platlibdir}/python{py_version_short}/site-packages", + "include": "{installed_base}/include/python{py_version_short}{abiflags}", + "platinclude": "{installed_platbase}/include/python{py_version_short}{abiflags}", + "scripts": "{base}/bin", + "data": "{base}", + }, + "posix_home": { + "stdlib": "{installed_base}/lib/python", + "platstdlib": "{base}/lib/python", + "purelib": "{base}/lib/python", + "platlib": "{base}/lib/python", + "include": "{installed_base}/include/python", + "platinclude": "{installed_base}/include/python", + "scripts": "{base}/bin", + "data": "{base}", + }, + "nt": { + "stdlib": "{installed_base}/Lib", + "platstdlib": "{base}/Lib", + "purelib": "{base}/Lib/site-packages", + "platlib": "{base}/Lib/site-packages", + "include": "{installed_base}/Include", + "platinclude": "{installed_base}/Include", + "scripts": "{base}/Scripts", + "data": "{base}", + }, + "deb_system": { + "stdlib": "{installed_base}/{platlibdir}/python{py_version_short}", + "platstdlib": "{platbase}/{platlibdir}/python{py_version_short}", + "purelib": "{base}/lib/python3/dist-packages", + "platlib": "{platbase}/{platlibdir}/python3/dist-packages", + "include": "{installed_base}/include/python{py_version_short}{abiflags}", + "platinclude": "{installed_platbase}/include/python{py_version_short}{abiflags}", + "scripts": "{base}/bin", + "data": "{base}", + }, + "posix_local": { + "stdlib": "{installed_base}/{platlibdir}/python{py_version_short}", + "platstdlib": "{platbase}/{platlibdir}/python{py_version_short}", + "purelib": "{base}/local/lib/python{py_version_short}/dist-packages", + "platlib": "{platbase}/local/lib/python{py_version_short}/dist-packages", + "include": "{installed_base}/local/include/python{py_version_short}{abiflags}", + "platinclude": "{installed_platbase}/local/include/python{py_version_short}{abiflags}", + "scripts": "{base}/local/bin", + "data": "{base}", + }, + } + # reset the default in case we're on a system which doesn't have this problem + sysconfig_get_path = functools.partial(sysconfig.get_path, scheme="posix_local") + + # make it look like python3-distutils is not available + mocker.patch.dict(sys.modules, {"distutils.command": None}) + mocker.patch("sysconfig._INSTALL_SCHEMES", sysconfig_install_schemes) + mocker.patch("sysconfig.get_path", sysconfig_get_path) + mocker.patch("sysconfig.get_default_scheme", return_value="posix_local") + + pyinfo = PythonInfo() + pyver = f"{pyinfo.version_info.major}.{pyinfo.version_info.minor}" + assert pyinfo.install_path("scripts") == "bin" + assert pyinfo.install_path("purelib").replace(os.sep, "/") == f"lib/python{pyver}/site-packages" diff --git a/tests/unit/seed/wheels/test_acquire_find_wheel.py b/tests/unit/seed/wheels/test_acquire_find_wheel.py index a4a28de8b..6ca1f2276 100644 --- a/tests/unit/seed/wheels/test_acquire_find_wheel.py +++ b/tests/unit/seed/wheels/test_acquire_find_wheel.py @@ -4,12 +4,18 @@ from virtualenv.seed.wheels.embed import BUNDLE_FOLDER, MAX, get_embed_wheel -def test_find_latest(for_py_version): +def test_find_latest_none(for_py_version): result = find_compatible_in_house("setuptools", None, for_py_version, BUNDLE_FOLDER) expected = get_embed_wheel("setuptools", for_py_version) assert result.path == expected.path +def test_find_latest_string(for_py_version): + result = find_compatible_in_house("setuptools", "", for_py_version, BUNDLE_FOLDER) + expected = get_embed_wheel("setuptools", for_py_version) + assert result.path == expected.path + + def test_find_exact(for_py_version): expected = get_embed_wheel("setuptools", for_py_version) result = find_compatible_in_house("setuptools", f"=={expected.version}", for_py_version, BUNDLE_FOLDER) diff --git a/tox.ini b/tox.ini index 567e30d2d..35bda8a10 100644 --- a/tox.ini +++ b/tox.ini @@ -113,7 +113,7 @@ passenv = UPGRADE_ADVISORY skip_install = true deps = - black>=22.6 + black>=22.10 changedir = {toxinidir}/tasks commands = python upgrade_wheels.py @@ -124,9 +124,9 @@ passenv = * basepython = python3.10 deps = - gitpython>=3.1.27 + gitpython>=3.1.29 packaging>=21.3 - towncrier>=21.9 + towncrier>=22.8 changedir = {toxinidir}/tasks commands = python release.py --version {posargs}