summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernát Gábor <gaborjbernat@gmail.com>2023-04-19 16:05:21 -0700
committerGitHub <noreply@github.com>2023-04-19 16:05:21 -0700
commit04af5026d8eff9ab34cd6f4a47e2f9de4f10a25c (patch)
tree7a7beb20e885285b6838f75db5c647a4d20317fc
parentcdd7eb129e5a31b5ff6779f00bc7621908962626 (diff)
downloadvirtualenv-04af5026d8eff9ab34cd6f4a47e2f9de4f10a25c.tar.gz
Drop Python 2 support (#2548)
-rw-r--r--.github/workflows/check.yml6
-rw-r--r--.pre-commit-config.yaml6
-rw-r--r--docs/changelog/2496.docs.rst1
-rw-r--r--docs/changelog/2548.feature.rst2
-rw-r--r--docs/conf.py2
-rw-r--r--docs/render_cli.py2
-rw-r--r--pyproject.toml13
-rw-r--r--src/virtualenv/__init__.py2
-rw-r--r--src/virtualenv/__main__.py2
-rw-r--r--src/virtualenv/activation/__init__.py2
-rw-r--r--src/virtualenv/activation/activator.py2
-rw-r--r--src/virtualenv/activation/bash/__init__.py2
-rw-r--r--src/virtualenv/activation/batch/__init__.py2
-rw-r--r--src/virtualenv/activation/cshell/__init__.py2
-rw-r--r--src/virtualenv/activation/fish/__init__.py2
-rw-r--r--src/virtualenv/activation/nushell/__init__.py2
-rw-r--r--src/virtualenv/activation/powershell/__init__.py2
-rw-r--r--src/virtualenv/activation/python/__init__.py14
-rw-r--r--src/virtualenv/activation/python/activate_this.py2
-rw-r--r--src/virtualenv/activation/via_template.py2
-rw-r--r--src/virtualenv/app_data/__init__.py2
-rw-r--r--src/virtualenv/app_data/base.py2
-rw-r--r--src/virtualenv/app_data/na.py2
-rw-r--r--src/virtualenv/app_data/read_only.py2
-rw-r--r--src/virtualenv/app_data/via_disk_folder.py2
-rw-r--r--src/virtualenv/app_data/via_tempdir.py2
-rw-r--r--src/virtualenv/config/cli/parser.py2
-rw-r--r--src/virtualenv/config/convert.py2
-rw-r--r--src/virtualenv/config/env_var.py2
-rw-r--r--src/virtualenv/config/ini.py2
-rw-r--r--src/virtualenv/create/creator.py2
-rw-r--r--src/virtualenv/create/debug.py6
-rw-r--r--src/virtualenv/create/describe.py11
-rw-r--r--src/virtualenv/create/pyenv_cfg.py2
-rw-r--r--src/virtualenv/create/via_global_ref/_virtualenv.py156
-rw-r--r--src/virtualenv/create/via_global_ref/api.py2
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/builtin_way.py2
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/common.py9
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py98
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py2
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py88
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/pypy/common.py5
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/pypy/pypy2.py124
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py2
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/python2/__init__.py0
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/python2/python2.py104
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/python2/site.py190
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/ref.py2
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/via_global_self_do.py2
-rw-r--r--src/virtualenv/create/via_global_ref/store.py2
-rw-r--r--src/virtualenv/create/via_global_ref/venv.py4
-rw-r--r--src/virtualenv/discovery/builtin.py2
-rw-r--r--src/virtualenv/discovery/cached_py_info.py2
-rw-r--r--src/virtualenv/discovery/discover.py2
-rw-r--r--src/virtualenv/discovery/py_info.py86
-rw-r--r--src/virtualenv/discovery/py_spec.py2
-rw-r--r--src/virtualenv/discovery/windows/__init__.py2
-rw-r--r--src/virtualenv/discovery/windows/pep514.py2
-rw-r--r--src/virtualenv/info.py2
-rw-r--r--src/virtualenv/report.py2
-rw-r--r--src/virtualenv/run/__init__.py2
-rw-r--r--src/virtualenv/run/plugin/activators.py2
-rw-r--r--src/virtualenv/run/plugin/base.py2
-rw-r--r--src/virtualenv/run/plugin/creators.py2
-rw-r--r--src/virtualenv/run/plugin/discovery.py2
-rw-r--r--src/virtualenv/run/plugin/seeders.py2
-rw-r--r--src/virtualenv/run/session.py2
-rw-r--r--src/virtualenv/seed/embed/base_embed.py2
-rw-r--r--src/virtualenv/seed/embed/pip_invoke.py2
-rw-r--r--src/virtualenv/seed/embed/via_app_data/pip_install/base.py2
-rw-r--r--src/virtualenv/seed/embed/via_app_data/pip_install/copy.py2
-rw-r--r--src/virtualenv/seed/embed/via_app_data/pip_install/symlink.py2
-rw-r--r--src/virtualenv/seed/embed/via_app_data/via_app_data.py2
-rw-r--r--src/virtualenv/seed/seeder.py2
-rw-r--r--src/virtualenv/seed/wheels/__init__.py2
-rw-r--r--src/virtualenv/seed/wheels/acquire.py2
-rw-r--r--src/virtualenv/seed/wheels/bundle.py2
-rw-r--r--src/virtualenv/seed/wheels/embed/__init__.py31
-rw-r--r--src/virtualenv/seed/wheels/embed/pip-20.3.4-py2.py3-none-any.whlbin1522101 -> 0 bytes
-rw-r--r--src/virtualenv/seed/wheels/embed/pip-21.3.1-py3-none-any.whlbin1723581 -> 0 bytes
-rw-r--r--src/virtualenv/seed/wheels/embed/setuptools-44.1.1-py2.py3-none-any.whlbin583493 -> 0 bytes
-rw-r--r--src/virtualenv/seed/wheels/embed/setuptools-50.3.2-py3-none-any.whlbin785194 -> 0 bytes
-rw-r--r--src/virtualenv/seed/wheels/embed/setuptools-59.6.0-py3-none-any.whlbin952597 -> 0 bytes
-rw-r--r--src/virtualenv/seed/wheels/embed/wheel-0.37.1-py2.py3-none-any.whlbin35301 -> 0 bytes
-rw-r--r--src/virtualenv/seed/wheels/periodic_update.py2
-rw-r--r--src/virtualenv/seed/wheels/util.py2
-rw-r--r--src/virtualenv/util/error.py3
-rw-r--r--src/virtualenv/util/lock.py2
-rw-r--r--src/virtualenv/util/path/__init__.py2
-rw-r--r--src/virtualenv/util/path/_permission.py2
-rw-r--r--src/virtualenv/util/path/_sync.py2
-rw-r--r--src/virtualenv/util/path/_win.py3
-rw-r--r--src/virtualenv/util/subprocess/__init__.py2
-rw-r--r--src/virtualenv/util/zipapp.py2
-rw-r--r--tasks/__main__zipapp.py14
-rw-r--r--tasks/make_zipapp.py12
-rw-r--r--tasks/release.py5
-rwxr-xr-xtasks/update_embedded.py2
-rw-r--r--tasks/upgrade_wheels.py6
-rw-r--r--tests/conftest.py19
-rw-r--r--tests/integration/test_run_int.py4
-rw-r--r--tests/integration/test_zipapp.py2
-rw-r--r--tests/unit/activation/conftest.py2
-rw-r--r--tests/unit/activation/test_activate_this.py26
-rw-r--r--tests/unit/activation/test_activation_support.py2
-rw-r--r--tests/unit/activation/test_activator.py2
-rw-r--r--tests/unit/activation/test_bash.py2
-rw-r--r--tests/unit/activation/test_batch.py2
-rw-r--r--tests/unit/activation/test_csh.py2
-rw-r--r--tests/unit/activation/test_fish.py2
-rw-r--r--tests/unit/activation/test_nushell.py2
-rw-r--r--tests/unit/activation/test_powershell.py2
-rw-r--r--tests/unit/activation/test_python_activator.py2
-rw-r--r--tests/unit/config/cli/test_parser.py2
-rw-r--r--tests/unit/config/test___main__.py2
-rw-r--r--tests/unit/config/test_env_var.py2
-rw-r--r--tests/unit/config/test_ini.py2
-rw-r--r--tests/unit/create/conftest.py55
-rw-r--r--tests/unit/create/console_app/demo/__init__.py3
-rw-r--r--tests/unit/create/console_app/demo/__main__.py3
-rw-r--r--tests/unit/create/console_app/setup.py2
-rw-r--r--tests/unit/create/test_creator.py85
-rw-r--r--tests/unit/create/test_interpreters.py2
-rw-r--r--tests/unit/create/via_global_ref/builtin/conftest.py2
-rw-r--r--tests/unit/create/via_global_ref/builtin/cpython/test_cpython3_win.py2
-rw-r--r--tests/unit/create/via_global_ref/builtin/pypy/test_pypy3.py2
-rw-r--r--tests/unit/create/via_global_ref/builtin/testing/helpers.py2
-rw-r--r--tests/unit/create/via_global_ref/builtin/testing/path.py2
-rw-r--r--tests/unit/create/via_global_ref/builtin/testing/py_info.py2
-rw-r--r--tests/unit/create/via_global_ref/greet/setup.py2
-rw-r--r--tests/unit/create/via_global_ref/test_api.py2
-rw-r--r--tests/unit/create/via_global_ref/test_build_c_ext.py2
-rw-r--r--tests/unit/discovery/py_info/test_py_info.py8
-rw-r--r--tests/unit/discovery/py_info/test_py_info_exe_based_of.py2
-rw-r--r--tests/unit/discovery/test_discovery.py2
-rw-r--r--tests/unit/discovery/test_py_spec.py2
-rw-r--r--tests/unit/discovery/windows/conftest.py2
-rw-r--r--tests/unit/discovery/windows/test_windows.py2
-rw-r--r--tests/unit/discovery/windows/test_windows_pep514.py2
-rw-r--r--tests/unit/discovery/windows/winreg-mock-values.py2
-rw-r--r--tests/unit/seed/embed/test_base_embed.py2
-rw-r--r--tests/unit/seed/embed/test_bootstrap_link_via_app_data.py5
-rw-r--r--tests/unit/seed/embed/test_pip_invoke.py4
-rw-r--r--tests/unit/seed/wheels/test_acquire.py2
-rw-r--r--tests/unit/seed/wheels/test_acquire_find_wheel.py9
-rw-r--r--tests/unit/seed/wheels/test_bundle.py2
-rw-r--r--tests/unit/seed/wheels/test_periodic_update.py2
-rw-r--r--tests/unit/seed/wheels/test_wheels_util.py2
-rw-r--r--tests/unit/test_run.py2
-rw-r--r--tests/unit/test_util.py2
150 files changed, 415 insertions, 1017 deletions
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 3bddd4a..69470c6 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -27,7 +27,7 @@ jobs:
- pypy-3.8
- pypy-3.7
os:
- - ubuntu-20.04
+ - ubuntu-22.04
- macos-12
- windows-2022
include:
@@ -60,10 +60,6 @@ jobs:
fetch-depth: 0
- name: Use local virtualenv for tox
run: python -m pip install .
- - name: Install Python 2 for cross test
- uses: actions/setup-python@v4
- with:
- python-version: "2.7"
- name: Setup brew python for test ${{ matrix.py }}
if: startsWith(matrix.py,'brew@')
run: |
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 84a7048..80bb905 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -21,12 +21,6 @@ repos:
hooks:
- id: pyupgrade
args: ["--py37-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
rev: 5.12.0
hooks:
diff --git a/docs/changelog/2496.docs.rst b/docs/changelog/2496.docs.rst
deleted file mode 100644
index a624e57..0000000
--- a/docs/changelog/2496.docs.rst
+++ /dev/null
@@ -1 +0,0 @@
-Use ``furo`` theme - by :user:`gaborbernat`.
diff --git a/docs/changelog/2548.feature.rst b/docs/changelog/2548.feature.rst
new file mode 100644
index 0000000..33d0209
--- /dev/null
+++ b/docs/changelog/2548.feature.rst
@@ -0,0 +1,2 @@
+Drop support for creating Python <3.6 (including 2) interpreters. Removed pip of ``20.3.4``, ``21.3.1``; wheel of
+``0.37.1``; setuptools of ``59.6.0``, ``44.1.1``, ``50.3.2``- by :user:`gaborbernat`.
diff --git a/docs/conf.py b/docs/conf.py
index da7fb16..ca53448 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import subprocess
import sys
from datetime import date, datetime
diff --git a/docs/render_cli.py b/docs/render_cli.py
index ca75e41..5e76611 100644
--- a/docs/render_cli.py
+++ b/docs/render_cli.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from argparse import SUPPRESS
from collections import namedtuple
from contextlib import contextmanager
diff --git a/pyproject.toml b/pyproject.toml
index 8833f6c..92f4b18 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -37,9 +37,9 @@ dynamic = [
]
dependencies = [
"distlib<1,>=0.3.6",
- "filelock<4,>=3.4.1",
- 'importlib-metadata>=4.8.3; python_version < "3.8"',
- "platformdirs<4,>=2.4",
+ "filelock<4,>=3.11",
+ 'importlib-metadata>=6.4.1; python_version < "3.8"',
+ "platformdirs<4,>=3.2",
]
optional-dependencies.docs = [
"furo>=2023.3.27",
@@ -76,15 +76,9 @@ nushell = "virtualenv.activation.nushell:NushellActivator"
powershell = "virtualenv.activation.powershell:PowerShellActivator"
python = "virtualenv.activation.python:PythonActivator"
[project.entry-points."virtualenv.create"]
-cpython2-mac-arm-framework = "virtualenv.create.via_global_ref.builtin.cpython.mac_os:CPython2macOsArmFramework"
-cpython2-mac-framework = "virtualenv.create.via_global_ref.builtin.cpython.mac_os:CPython2macOsFramework"
-cpython2-posix = "virtualenv.create.via_global_ref.builtin.cpython.cpython2:CPython2Posix"
-cpython2-win = "virtualenv.create.via_global_ref.builtin.cpython.cpython2:CPython2Windows"
cpython3-mac-framework = "virtualenv.create.via_global_ref.builtin.cpython.mac_os:CPython3macOsFramework"
cpython3-posix = "virtualenv.create.via_global_ref.builtin.cpython.cpython3:CPython3Posix"
cpython3-win = "virtualenv.create.via_global_ref.builtin.cpython.cpython3:CPython3Windows"
-pypy2-posix = "virtualenv.create.via_global_ref.builtin.pypy.pypy2:PyPy2Posix"
-pypy2-win = "virtualenv.create.via_global_ref.builtin.pypy.pypy2:Pypy2Windows"
pypy3-posix = "virtualenv.create.via_global_ref.builtin.pypy.pypy3:PyPy3Posix"
pypy3-win = "virtualenv.create.via_global_ref.builtin.pypy.pypy3:Pypy3Windows"
venv = "virtualenv.create.via_global_ref.venv:Venv"
@@ -105,6 +99,7 @@ line-length = 120
[tool.isort]
profile = "black"
known_first_party = ["virtualenv"]
+add_imports = ["from __future__ import annotations"]
[tool.flake8]
max-complexity = 22
diff --git a/src/virtualenv/__init__.py b/src/virtualenv/__init__.py
index e40e8b7..cc11e7f 100644
--- a/src/virtualenv/__init__.py
+++ b/src/virtualenv/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from .run import cli_run, session_via_cli
from .version import __version__
diff --git a/src/virtualenv/__main__.py b/src/virtualenv/__main__.py
index c3c5adf..0ff40d8 100644
--- a/src/virtualenv/__main__.py
+++ b/src/virtualenv/__main__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import sys
diff --git a/src/virtualenv/activation/__init__.py b/src/virtualenv/activation/__init__.py
index 99984bc..f6cf756 100644
--- a/src/virtualenv/activation/__init__.py
+++ b/src/virtualenv/activation/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from .bash import BashActivator
from .batch import BatchActivator
from .cshell import CShellActivator
diff --git a/src/virtualenv/activation/activator.py b/src/virtualenv/activation/activator.py
index 10b1cf7..ef35b17 100644
--- a/src/virtualenv/activation/activator.py
+++ b/src/virtualenv/activation/activator.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from abc import ABCMeta, abstractmethod
diff --git a/src/virtualenv/activation/bash/__init__.py b/src/virtualenv/activation/bash/__init__.py
index 9860b72..0267fe4 100644
--- a/src/virtualenv/activation/bash/__init__.py
+++ b/src/virtualenv/activation/bash/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from pathlib import Path
from ..via_template import ViaTemplateActivator
diff --git a/src/virtualenv/activation/batch/__init__.py b/src/virtualenv/activation/batch/__init__.py
index 13ba097..e445005 100644
--- a/src/virtualenv/activation/batch/__init__.py
+++ b/src/virtualenv/activation/batch/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from ..via_template import ViaTemplateActivator
diff --git a/src/virtualenv/activation/cshell/__init__.py b/src/virtualenv/activation/cshell/__init__.py
index 20a7a18..9065d99 100644
--- a/src/virtualenv/activation/cshell/__init__.py
+++ b/src/virtualenv/activation/cshell/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from ..via_template import ViaTemplateActivator
diff --git a/src/virtualenv/activation/fish/__init__.py b/src/virtualenv/activation/fish/__init__.py
index 49b5e14..b630450 100644
--- a/src/virtualenv/activation/fish/__init__.py
+++ b/src/virtualenv/activation/fish/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from ..via_template import ViaTemplateActivator
diff --git a/src/virtualenv/activation/nushell/__init__.py b/src/virtualenv/activation/nushell/__init__.py
index 4e2ea77..2691f70 100644
--- a/src/virtualenv/activation/nushell/__init__.py
+++ b/src/virtualenv/activation/nushell/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from ..via_template import ViaTemplateActivator
diff --git a/src/virtualenv/activation/powershell/__init__.py b/src/virtualenv/activation/powershell/__init__.py
index 4e74ecb..f8de975 100644
--- a/src/virtualenv/activation/powershell/__init__.py
+++ b/src/virtualenv/activation/powershell/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from ..via_template import ViaTemplateActivator
diff --git a/src/virtualenv/activation/python/__init__.py b/src/virtualenv/activation/python/__init__.py
index eb83504..28861f9 100644
--- a/src/virtualenv/activation/python/__init__.py
+++ b/src/virtualenv/activation/python/__init__.py
@@ -1,5 +1,6 @@
+from __future__ import annotations
+
import os
-import sys
from collections import OrderedDict
from ..via_template import ViaTemplateActivator
@@ -12,23 +13,14 @@ class PythonActivator(ViaTemplateActivator):
def replacements(self, creator, dest_folder):
replacements = super().replacements(creator, dest_folder)
lib_folders = OrderedDict((os.path.relpath(str(i), str(dest_folder)), None) for i in creator.libs)
- win_py2 = creator.interpreter.platform == "win32" and creator.interpreter.version_info.major == 2
replacements.update(
{
"__LIB_FOLDERS__": os.pathsep.join(lib_folders.keys()),
- "__DECODE_PATH__": ("yes" if win_py2 else ""),
+ "__DECODE_PATH__": "",
},
)
return replacements
- @staticmethod
- def _repr_unicode(creator, value):
- py2 = creator.interpreter.version_info.major == 2
- if py2: # on Python 2 we need to encode this into explicit utf-8, py3 supports unicode literals
- start = 2 if sys.version_info[0] == 3 else 1
- value = repr(value.encode("utf-8"))[start:-1]
- return value
-
__all__ = [
"PythonActivator",
diff --git a/src/virtualenv/activation/python/activate_this.py b/src/virtualenv/activation/python/activate_this.py
index e8eeb84..192c796 100644
--- a/src/virtualenv/activation/python/activate_this.py
+++ b/src/virtualenv/activation/python/activate_this.py
@@ -4,6 +4,8 @@ Use exec(open(this_file).read(), {'__file__': this_file}).
This can be used when you must use an existing Python interpreter, not the virtualenv bin/python.
"""
+from __future__ import annotations
+
import os
import site
import sys
diff --git a/src/virtualenv/activation/via_template.py b/src/virtualenv/activation/via_template.py
index 069d52e..e8ec164 100644
--- a/src/virtualenv/activation/via_template.py
+++ b/src/virtualenv/activation/via_template.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
import sys
from abc import ABCMeta, abstractmethod
diff --git a/src/virtualenv/app_data/__init__.py b/src/virtualenv/app_data/__init__.py
index 262ac07..ebff2f3 100644
--- a/src/virtualenv/app_data/__init__.py
+++ b/src/virtualenv/app_data/__init__.py
@@ -2,6 +2,8 @@
Application data stored by virtualenv.
"""
+from __future__ import annotations
+
import logging
import os
diff --git a/src/virtualenv/app_data/base.py b/src/virtualenv/app_data/base.py
index bc28b23..db08931 100644
--- a/src/virtualenv/app_data/base.py
+++ b/src/virtualenv/app_data/base.py
@@ -2,6 +2,8 @@
Application data stored by virtualenv.
"""
+from __future__ import annotations
+
from abc import ABCMeta, abstractmethod
from contextlib import contextmanager
diff --git a/src/virtualenv/app_data/na.py b/src/virtualenv/app_data/na.py
index 784c76b..9b80ef5 100644
--- a/src/virtualenv/app_data/na.py
+++ b/src/virtualenv/app_data/na.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from contextlib import contextmanager
from .base import AppData, ContentStore
diff --git a/src/virtualenv/app_data/read_only.py b/src/virtualenv/app_data/read_only.py
index b11f4a6..3cec79a 100644
--- a/src/virtualenv/app_data/read_only.py
+++ b/src/virtualenv/app_data/read_only.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os.path
from virtualenv.util.lock import NoOpFileLock
diff --git a/src/virtualenv/app_data/via_disk_folder.py b/src/virtualenv/app_data/via_disk_folder.py
index 6c7f558..7abdd1e 100644
--- a/src/virtualenv/app_data/via_disk_folder.py
+++ b/src/virtualenv/app_data/via_disk_folder.py
@@ -22,6 +22,8 @@ virtualenv-app-data
└── _virtualenv.py
"""
+from __future__ import annotations
+
import json
import logging
from abc import ABCMeta
diff --git a/src/virtualenv/app_data/via_tempdir.py b/src/virtualenv/app_data/via_tempdir.py
index 7854642..8ae86ec 100644
--- a/src/virtualenv/app_data/via_tempdir.py
+++ b/src/virtualenv/app_data/via_tempdir.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
from tempfile import mkdtemp
diff --git a/src/virtualenv/config/cli/parser.py b/src/virtualenv/config/cli/parser.py
index f68e56e..915257b 100644
--- a/src/virtualenv/config/cli/parser.py
+++ b/src/virtualenv/config/cli/parser.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from argparse import SUPPRESS, ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace
from collections import OrderedDict
diff --git a/src/virtualenv/config/convert.py b/src/virtualenv/config/convert.py
index 38d3551..e5f1ae8 100644
--- a/src/virtualenv/config/convert.py
+++ b/src/virtualenv/config/convert.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
diff --git a/src/virtualenv/config/env_var.py b/src/virtualenv/config/env_var.py
index 5dc0c1d..c6549e2 100644
--- a/src/virtualenv/config/env_var.py
+++ b/src/virtualenv/config/env_var.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from .convert import convert
diff --git a/src/virtualenv/config/ini.py b/src/virtualenv/config/ini.py
index f977fc0..c56665c 100644
--- a/src/virtualenv/config/ini.py
+++ b/src/virtualenv/config/ini.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
from configparser import ConfigParser
diff --git a/src/virtualenv/create/creator.py b/src/virtualenv/create/creator.py
index e561a3f..12d7424 100644
--- a/src/virtualenv/create/creator.py
+++ b/src/virtualenv/create/creator.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import json
import logging
import os
diff --git a/src/virtualenv/create/debug.py b/src/virtualenv/create/debug.py
index 583d999..a922fb1 100644
--- a/src/virtualenv/create/debug.py
+++ b/src/virtualenv/create/debug.py
@@ -1,7 +1,7 @@
"""Inspect a target Python interpreter virtual environment wise"""
-import sys # built-in
+from __future__ import annotations
-PYPY2_WIN = hasattr(sys, "pypy_version_info") and sys.platform != "win32" and sys.version_info[0] == 2
+import sys # built-in
def encode_path(value):
@@ -12,7 +12,7 @@ def encode_path(value):
value = repr(value)
else:
value = repr(type(value))
- if isinstance(value, bytes) and not PYPY2_WIN:
+ if isinstance(value, bytes):
value = value.decode(sys.getfilesystemencoding())
return value
diff --git a/src/virtualenv/create/describe.py b/src/virtualenv/create/describe.py
index 8575267..e39afe6 100644
--- a/src/virtualenv/create/describe.py
+++ b/src/virtualenv/create/describe.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta
from collections import OrderedDict
from pathlib import Path
@@ -58,7 +60,7 @@ class Describe(metaclass=ABCMeta):
def _calc_config_vars(self, to):
sys_vars = self.interpreter.sysconfig_vars
- return {k: (to if v.startswith(self.interpreter.prefix) else v) for k, v in sys_vars.items()}
+ return {k: (to if v is not None and v.startswith(self.interpreter.prefix) else v) for k, v in sys_vars.items()}
@classmethod
def can_describe(cls, interpreter): # noqa: U100
@@ -82,12 +84,6 @@ class Describe(metaclass=ABCMeta):
return self.script_dir / f"{name}{self.suffix}"
-class Python2Supports(Describe, metaclass=ABCMeta):
- @classmethod
- def can_describe(cls, interpreter):
- return interpreter.version_info.major == 2 and super().can_describe(interpreter)
-
-
class Python3Supports(Describe, metaclass=ABCMeta):
@classmethod
def can_describe(cls, interpreter):
@@ -108,7 +104,6 @@ class WindowsSupports(Describe, metaclass=ABCMeta):
__all__ = [
"Describe",
- "Python2Supports",
"Python3Supports",
"PosixSupports",
"WindowsSupports",
diff --git a/src/virtualenv/create/pyenv_cfg.py b/src/virtualenv/create/pyenv_cfg.py
index 9193a28..44919ab 100644
--- a/src/virtualenv/create/pyenv_cfg.py
+++ b/src/virtualenv/create/pyenv_cfg.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
from collections import OrderedDict
diff --git a/src/virtualenv/create/via_global_ref/_virtualenv.py b/src/virtualenv/create/via_global_ref/_virtualenv.py
index faee64c..90c32df 100644
--- a/src/virtualenv/create/via_global_ref/_virtualenv.py
+++ b/src/virtualenv/create/via_global_ref/_virtualenv.py
@@ -1,5 +1,6 @@
"""Patches that are applied at runtime to the virtual environment"""
-# -*- coding: utf-8 -*-
+
+from __future__ import annotations
import os
import sys
@@ -24,7 +25,7 @@ def patch_dist(dist):
if "prefix" in install: # the prefix governs where to install the libraries
install["prefix"] = VIRTUALENV_PATCH_FILE, os.path.abspath(sys.prefix)
for base in ("purelib", "platlib", "headers", "scripts", "data"):
- key = "install_{}".format(base)
+ key = f"install_{base}"
if key in install: # do not allow global configs to hijack venv paths
install.pop(key, None)
return result
@@ -35,96 +36,67 @@ def patch_dist(dist):
# Import hook that patches some modules to ignore configuration values that break package installation in case
# of virtual environments.
_DISTUTILS_PATCH = "distutils.dist", "setuptools.dist"
-if sys.version_info > (3, 4):
- # https://docs.python.org/3/library/importlib.html#setting-up-an-importer
-
- class _Finder:
- """A meta path finder that allows patching the imported distutils modules"""
-
- fullname = None
-
- # lock[0] is threading.Lock(), but initialized lazily to avoid importing threading very early at startup,
- # because there are gevent-based applications that need to be first to import threading by themselves.
- # See https://github.com/pypa/virtualenv/issues/1895 for details.
- lock = []
-
- def find_spec(self, fullname, path, target=None): # noqa: U100
- if fullname in _DISTUTILS_PATCH and self.fullname is None:
- # initialize lock[0] lazily
- if len(self.lock) == 0:
- import threading
-
- lock = threading.Lock()
- # there is possibility that two threads T1 and T2 are simultaneously running into find_spec,
- # observing .lock as empty, and further going into hereby initialization. However due to the GIL,
- # list.append() operation is atomic and this way only one of the threads will "win" to put the lock
- # - that every thread will use - into .lock[0].
- # https://docs.python.org/3/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
- self.lock.append(lock)
-
- from functools import partial
- from importlib.util import find_spec
-
- with self.lock[0]:
- self.fullname = fullname
- try:
- spec = find_spec(fullname, path)
- if spec is not None:
- # https://www.python.org/dev/peps/pep-0451/#how-loading-will-work
- is_new_api = hasattr(spec.loader, "exec_module")
- func_name = "exec_module" if is_new_api else "load_module"
- old = getattr(spec.loader, func_name)
- func = self.exec_module if is_new_api else self.load_module
- if old is not func:
- try:
- setattr(spec.loader, func_name, partial(func, old))
- except AttributeError:
- pass # C-Extension loaders are r/o such as zipimporter with <python 3.7
- return spec
- finally:
- self.fullname = None
-
- @staticmethod
- def exec_module(old, module):
- old(module)
- if module.__name__ in _DISTUTILS_PATCH:
- patch_dist(module)
-
- @staticmethod
- def load_module(old, name):
- module = old(name)
- if module.__name__ in _DISTUTILS_PATCH:
- patch_dist(module)
- return module
-
- sys.meta_path.insert(0, _Finder())
-else:
- # https://www.python.org/dev/peps/pep-0302/
- from imp import find_module
- from pkgutil import ImpImporter, ImpLoader
-
- class _VirtualenvImporter(object, ImpImporter):
- def __init__(self, path=None):
- object.__init__(self)
- ImpImporter.__init__(self, path)
-
- def find_module(self, fullname, path=None):
- if fullname in _DISTUTILS_PATCH:
+# https://docs.python.org/3/library/importlib.html#setting-up-an-importer
+
+
+class _Finder:
+ """A meta path finder that allows patching the imported distutils modules"""
+
+ fullname = None
+
+ # lock[0] is threading.Lock(), but initialized lazily to avoid importing threading very early at startup,
+ # because there are gevent-based applications that need to be first to import threading by themselves.
+ # See https://github.com/pypa/virtualenv/issues/1895 for details.
+ lock = []
+
+ def find_spec(self, fullname, path, target=None): # noqa: U100
+ if fullname in _DISTUTILS_PATCH and self.fullname is None:
+ # initialize lock[0] lazily
+ if len(self.lock) == 0:
+ import threading
+
+ lock = threading.Lock()
+ # there is possibility that two threads T1 and T2 are simultaneously running into find_spec,
+ # observing .lock as empty, and further going into hereby initialization. However due to the GIL,
+ # list.append() operation is atomic and this way only one of the threads will "win" to put the lock
+ # - that every thread will use - into .lock[0].
+ # https://docs.python.org/3/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
+ self.lock.append(lock)
+
+ from functools import partial
+ from importlib.util import find_spec
+
+ with self.lock[0]:
+ self.fullname = fullname
try:
- return _VirtualenvLoader(fullname, *find_module(fullname.split(".")[-1], path))
- except ImportError:
- pass
- return None
-
- class _VirtualenvLoader(object, ImpLoader):
- def __init__(self, fullname, file, filename, etc):
- object.__init__(self)
- ImpLoader.__init__(self, fullname, file, filename, etc)
-
- def load_module(self, fullname):
- module = super(_VirtualenvLoader, self).load_module(fullname)
+ spec = find_spec(fullname, path)
+ if spec is not None:
+ # https://www.python.org/dev/peps/pep-0451/#how-loading-will-work
+ is_new_api = hasattr(spec.loader, "exec_module")
+ func_name = "exec_module" if is_new_api else "load_module"
+ old = getattr(spec.loader, func_name)
+ func = self.exec_module if is_new_api else self.load_module
+ if old is not func:
+ try:
+ setattr(spec.loader, func_name, partial(func, old))
+ except AttributeError:
+ pass # C-Extension loaders are r/o such as zipimporter with <python 3.7
+ return spec
+ finally:
+ self.fullname = None
+
+ @staticmethod
+ def exec_module(old, module):
+ old(module)
+ if module.__name__ in _DISTUTILS_PATCH:
patch_dist(module)
- module.__loader__ = None # distlib fallback
- return module
- sys.meta_path.append(_VirtualenvImporter())
+ @staticmethod
+ def load_module(old, name):
+ module = old(name)
+ if module.__name__ in _DISTUTILS_PATCH:
+ patch_dist(module)
+ return module
+
+
+sys.meta_path.insert(0, _Finder())
diff --git a/src/virtualenv/create/via_global_ref/api.py b/src/virtualenv/create/via_global_ref/api.py
index 884452e..79d707c 100644
--- a/src/virtualenv/create/via_global_ref/api.py
+++ b/src/virtualenv/create/via_global_ref/api.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
from abc import ABCMeta
diff --git a/src/virtualenv/create/via_global_ref/builtin/builtin_way.py b/src/virtualenv/create/via_global_ref/builtin/builtin_way.py
index e321593..5705a7b 100644
--- a/src/virtualenv/create/via_global_ref/builtin/builtin_way.py
+++ b/src/virtualenv/create/via_global_ref/builtin/builtin_way.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta
from virtualenv.create.creator import Creator
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/common.py b/src/virtualenv/create/via_global_ref/builtin/cpython/common.py
index b2f7944..f704621 100644
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/common.py
+++ b/src/virtualenv/create/via_global_ref/builtin/cpython/common.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta
from collections import OrderedDict
from pathlib import Path
@@ -26,8 +28,7 @@ class CPythonPosix(CPython, PosixSupports, metaclass=ABCMeta):
host_exe = Path(interpreter.system_executable)
major, minor = interpreter.version_info.major, interpreter.version_info.minor
targets = OrderedDict((i, None) for i in ["python", f"python{major}", f"python{major}.{minor}", host_exe.name])
- must = RefMust.COPY if interpreter.version_info.major == 2 else RefMust.NA
- yield host_exe, list(targets.keys()), must, RefWhen.ANY
+ yield host_exe, list(targets.keys()), RefMust.NA, RefWhen.ANY
class CPythonWindows(CPython, WindowsSupports, metaclass=ABCMeta):
@@ -50,9 +51,7 @@ class CPythonWindows(CPython, WindowsSupports, metaclass=ABCMeta):
def is_mac_os_framework(interpreter):
if interpreter.platform == "darwin":
- framework_var = interpreter.sysconfig_vars.get("PYTHONFRAMEWORK")
- value = "Python3" if interpreter.version_info.major == 3 else "Python"
- return framework_var == value
+ return interpreter.sysconfig_vars.get("PYTHONFRAMEWORK") == "Python3"
return False
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py
deleted file mode 100644
index 9e29234..0000000
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import abc
-import logging
-from pathlib import Path
-
-from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
-
-from ..python2.python2 import Python2
-from .common import CPython, CPythonPosix, CPythonWindows, is_mac_os_framework
-
-
-class CPython2(CPython, Python2, metaclass=abc.ABCMeta):
- """Create a CPython version 2 virtual environment"""
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- # include folder needed on Python 2 as we don't have pyenv.cfg
- host_include_marker = cls.host_include_marker(interpreter)
- if host_include_marker.exists():
- yield PathRefToDest(host_include_marker.parent, dest=lambda self, _: self.include) # noqa: U101
-
- @classmethod
- def needs_stdlib_py_module(cls):
- return False
-
- @classmethod
- def host_include_marker(cls, interpreter):
- return Path(interpreter.system_include) / "Python.h"
-
- @property
- def include(self):
- # the pattern include the distribution name too at the end, remove that via the parent call
- return (self.dest / self.interpreter.install_path("headers")).parent
-
- @classmethod
- def modules(cls):
- return ["os"] # landmark to set sys.prefix
-
- def ensure_directories(self):
- dirs = super().ensure_directories()
- host_include_marker = self.host_include_marker(self.interpreter)
- if host_include_marker.exists():
- dirs.add(self.include.parent)
- else:
- logging.debug("no include folders as can't find include marker %s", host_include_marker)
- return dirs
-
-
-class CPython2PosixBase(CPython2, CPythonPosix, metaclass=abc.ABCMeta):
- """common to macOs framework builds and other posix CPython2"""
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
-
- # check if the makefile exists and if so make it available under the virtual environment
- make_file = Path(interpreter.sysconfig["makefile_filename"])
- if make_file.exists() and str(make_file).startswith(interpreter.prefix):
- under_prefix = make_file.relative_to(Path(interpreter.prefix))
- yield PathRefToDest(make_file, dest=lambda self, s: self.dest / under_prefix) # noqa: U100
-
-
-class CPython2Posix(CPython2PosixBase):
- """CPython 2 on POSIX (excluding macOs framework builds)"""
-
- @classmethod
- def can_describe(cls, interpreter):
- return is_mac_os_framework(interpreter) is False and super().can_describe(interpreter)
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- # landmark for exec_prefix
- exec_marker_file, to_path, _ = cls.from_stdlib(cls.mappings(interpreter), "lib-dynload")
- yield PathRefToDest(exec_marker_file, dest=to_path)
-
-
-class CPython2Windows(CPython2, CPythonWindows):
- """CPython 2 on Windows"""
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- py27_dll = Path(interpreter.system_executable).parent / "python27.dll"
- if py27_dll.exists(): # this might be global in the Windows folder in which case it's alright to be missing
- yield PathRefToDest(py27_dll, dest=cls.to_bin)
-
- libs = Path(interpreter.system_prefix) / "libs"
- if libs.exists():
- yield PathRefToDest(libs, dest=lambda self, s: self.dest / s.name)
-
-
-__all__ = [
- "CPython2",
- "CPython2PosixBase",
- "CPython2Posix",
- "CPython2Windows",
-]
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py
index 433dc4a..3d9a5c4 100644
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py
+++ b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import abc
import fnmatch
from itertools import chain
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py b/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py
index d23f53b..8fa09aa 100644
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py
+++ b/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py
@@ -1,4 +1,6 @@
"""The Apple Framework builds require their own customization"""
+from __future__ import annotations
+
import logging
import os
import struct
@@ -12,10 +14,8 @@ from virtualenv.create.via_global_ref.builtin.ref import (
PathRefToDest,
RefMust,
)
-from virtualenv.info import IS_MAC_ARM64
from .common import CPython, CPythonPosix, is_mac_os_framework
-from .cpython2 import CPython2PosixBase
from .cpython3 import CPython3
@@ -57,89 +57,6 @@ class CPythonmacOsFramework(CPython, metaclass=ABCMeta):
raise NotImplementedError
-class CPython2macOsFramework(CPythonmacOsFramework, CPython2PosixBase):
- @classmethod
- def can_create(cls, interpreter):
- if not IS_MAC_ARM64 and super().can_describe(interpreter):
- return super().can_create(interpreter)
- return False
-
- def current_mach_o_image_path(self):
- return os.path.join(self.interpreter.prefix, "Python")
-
- def desired_mach_o_image_path(self):
- return "@executable_path/../Python"
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- # landmark for exec_prefix
- exec_marker_file, to_path, _ = cls.from_stdlib(cls.mappings(interpreter), "lib-dynload")
- yield PathRefToDest(exec_marker_file, dest=to_path)
-
- # add a copy of the host python image
- exe = Path(interpreter.prefix) / "Python"
- yield PathRefToDest(exe, dest=lambda self, _: self.dest / "Python", must=RefMust.COPY) # noqa: U101
-
- # add a symlink to the Resources dir
- resources = Path(interpreter.prefix) / "Resources"
- yield PathRefToDest(resources, dest=lambda self, _: self.dest / "Resources") # noqa: U101
-
- @property
- def reload_code(self):
- result = super().reload_code
- result = dedent(
- f"""
- # the bundled site.py always adds the global site package if we're on python framework build, escape this
- import sysconfig
- config = sysconfig.get_config_vars()
- before = config["PYTHONFRAMEWORK"]
- try:
- config["PYTHONFRAMEWORK"] = ""
- {result}
- finally:
- config["PYTHONFRAMEWORK"] = before
- """,
- )
- return result
-
-
-class CPython2macOsArmFramework(CPython2macOsFramework, CPythonmacOsFramework, CPython2PosixBase):
- @classmethod
- def can_create(cls, interpreter):
- if IS_MAC_ARM64 and super(CPythonmacOsFramework, cls).can_describe(interpreter):
- return super(CPythonmacOsFramework, cls).can_create(interpreter)
- return False
-
- def create(self):
- super(CPython2macOsFramework, self).create()
- self.fix_signature()
-
- def fix_signature(self):
- """
- On Apple M1 machines (arm64 chips), rewriting the python executable invalidates its signature.
- In python2 this results in a unusable python exe which just dies.
- As a temporary workaround we can codesign the python exe during the creation process.
- """
- exe = self.exe
- try:
- logging.debug("Changing signature of copied python exe %s", exe)
- bak_dir = exe.parent / "bk"
- # Reset the signing on Darwin since the exe has been modified.
- # Note codesign fails on the original exe, it needs to be copied and moved back.
- bak_dir.mkdir(parents=True, exist_ok=True)
- subprocess.check_call(["cp", str(exe), str(bak_dir)])
- subprocess.check_call(["mv", str(bak_dir / exe.name), str(exe)])
- bak_dir.rmdir()
- metadata = "--preserve-metadata=identifier,entitlements,flags,runtime"
- cmd = ["codesign", "-s", "-", metadata, "-f", str(exe)]
- logging.debug("Changing Signature: %s", cmd)
- subprocess.check_call(cmd)
- except Exception:
- logging.fatal("Could not change MacOS code signing on copied python exe at %s", exe)
- raise
-
-
class CPython3macOsFramework(CPythonmacOsFramework, CPython3, CPythonPosix):
def current_mach_o_image_path(self):
return "@executable_path/../../../../Python3"
@@ -342,6 +259,5 @@ def _builtin_change_mach_o(maxint):
__all__ = [
"CPythonmacOsFramework",
- "CPython2macOsFramework",
"CPython3macOsFramework",
]
diff --git a/src/virtualenv/create/via_global_ref/builtin/pypy/common.py b/src/virtualenv/create/via_global_ref/builtin/pypy/common.py
index 17cf733..f695d6e 100644
--- a/src/virtualenv/create/via_global_ref/builtin/pypy/common.py
+++ b/src/virtualenv/create/via_global_ref/builtin/pypy/common.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import abc
from pathlib import Path
@@ -15,8 +17,7 @@ class PyPy(ViaGlobalRefVirtualenvBuiltin, metaclass=abc.ABCMeta):
def _executables(cls, interpreter):
host = Path(interpreter.system_executable)
targets = sorted(f"{name}{PyPy.suffix}" for name in cls.exe_names(interpreter))
- must = RefMust.COPY if interpreter.version_info.major == 2 else RefMust.NA
- yield host, targets, must, RefWhen.ANY
+ yield host, targets, RefMust.NA, RefWhen.ANY
@classmethod
def executables(cls, interpreter):
diff --git a/src/virtualenv/create/via_global_ref/builtin/pypy/pypy2.py b/src/virtualenv/create/via_global_ref/builtin/pypy/pypy2.py
deleted file mode 100644
index 8031339..0000000
--- a/src/virtualenv/create/via_global_ref/builtin/pypy/pypy2.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import abc
-import logging
-import os
-from pathlib import Path
-
-from virtualenv.create.describe import PosixSupports, WindowsSupports
-from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
-
-from ..python2.python2 import Python2
-from .common import PyPy
-
-
-class PyPy2(PyPy, Python2, metaclass=abc.ABCMeta):
- """PyPy 2"""
-
- @classmethod
- def exe_stem(cls):
- return "pypy"
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- # include folder needed on Python 2 as we don't have pyenv.cfg
- host_include_marker = cls.host_include_marker(interpreter)
- if host_include_marker.exists():
- yield PathRefToDest(host_include_marker.parent, dest=lambda self, _: self.include) # noqa: U101
-
- @classmethod
- def needs_stdlib_py_module(cls):
- return True
-
- @classmethod
- def host_include_marker(cls, interpreter):
- return Path(interpreter.system_include) / "PyPy.h"
-
- @property
- def include(self):
- return self.dest / self.interpreter.install_path("headers")
-
- @classmethod
- def modules(cls):
- # pypy2 uses some modules before the site.py loads, so we need to include these too
- return super().modules() + [
- "os",
- "copy_reg",
- "genericpath",
- "linecache",
- "stat",
- "UserDict",
- "warnings",
- ]
-
- @property
- def lib_pypy(self):
- return self.dest / "lib_pypy"
-
- def ensure_directories(self):
- dirs = super().ensure_directories()
- dirs.add(self.lib_pypy)
- host_include_marker = self.host_include_marker(self.interpreter)
- if host_include_marker.exists():
- dirs.add(self.include.parent)
- else:
- logging.debug("no include folders as can't find include marker %s", host_include_marker)
- return dirs
-
- @property
- def skip_rewrite(self):
- """
- PyPy2 built-in imports are handled by this path entry, don't overwrite to not disable it
- see: https://github.com/pypa/virtualenv/issues/1652
- """
- return f'or path.endswith("lib_pypy{os.sep}__extensions__") # PyPy2 built-in import marker'
-
-
-class PyPy2Posix(PyPy2, PosixSupports):
- """PyPy 2 on POSIX"""
-
- @classmethod
- def modules(cls):
- return super().modules() + ["posixpath"]
-
- @classmethod
- def _shared_libs(cls, python_dir):
- return python_dir.glob("libpypy*.*")
-
- @property
- def lib(self):
- return self.dest / "lib"
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- host_lib = Path(interpreter.system_prefix) / "lib"
- if host_lib.exists():
- yield PathRefToDest(host_lib, dest=lambda self, _: self.lib) # noqa: U101
-
-
-class Pypy2Windows(PyPy2, WindowsSupports):
- """PyPy 2 on Windows"""
-
- @classmethod
- def modules(cls):
- return super().modules() + ["ntpath"]
-
- @classmethod
- def _shared_libs(cls, python_dir):
- # No glob in python2 PathLib
- for candidate in ["libpypy-c.dll", "libffi-7.dll", "libffi-8.dll"]:
- dll = python_dir / candidate
- if dll.exists():
- yield dll
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- yield PathRefToDest(Path(interpreter.system_prefix) / "libs", dest=lambda self, s: self.dest / s.name)
-
-
-__all__ = [
- "PyPy2",
- "PyPy2Posix",
- "Pypy2Windows",
-]
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 9db36e8..b06ecea 100644
--- a/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py
+++ b/src/virtualenv/create/via_global_ref/builtin/pypy/pypy3.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import abc
from pathlib import Path
diff --git a/src/virtualenv/create/via_global_ref/builtin/python2/__init__.py b/src/virtualenv/create/via_global_ref/builtin/python2/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/src/virtualenv/create/via_global_ref/builtin/python2/__init__.py
+++ /dev/null
diff --git a/src/virtualenv/create/via_global_ref/builtin/python2/python2.py b/src/virtualenv/create/via_global_ref/builtin/python2/python2.py
deleted file mode 100644
index 3452577..0000000
--- a/src/virtualenv/create/via_global_ref/builtin/python2/python2.py
+++ /dev/null
@@ -1,104 +0,0 @@
-import abc
-import json
-import os
-from pathlib import Path
-
-from virtualenv.create.describe import Python2Supports
-from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
-from virtualenv.info import IS_ZIPAPP
-from virtualenv.util.zipapp import read as read_from_zipapp
-
-from ..via_global_self_do import ViaGlobalRefVirtualenvBuiltin
-
-HERE = Path(os.path.abspath(__file__)).parent
-
-
-class Python2(ViaGlobalRefVirtualenvBuiltin, Python2Supports, metaclass=abc.ABCMeta):
- def create(self):
- """Perform operations needed to make the created environment work on Python 2"""
- super().create()
- # install a patched site-package, the default Python 2 site.py is not smart enough to understand pyvenv.cfg,
- # so we inject a small shim that can do this, the location of this depends where it's on host
- sys_std_plat = Path(self.interpreter.system_stdlib_platform)
- site_py_in = (
- self.stdlib_platform
- if ((sys_std_plat / "site.py").exists() or (sys_std_plat / "site.pyc").exists())
- else self.stdlib
- )
- site_py = site_py_in / "site.py"
-
- custom_site = get_custom_site()
- if IS_ZIPAPP:
- custom_site_text = read_from_zipapp(custom_site)
- else:
- custom_site_text = custom_site.read_text(encoding="utf-8")
- expected = json.dumps([os.path.relpath(str(i), str(site_py)) for i in self.libs])
-
- custom_site_text = custom_site_text.replace("___EXPECTED_SITE_PACKAGES___", expected)
-
- reload_code = os.linesep.join(f" {i}" for i in self.reload_code.splitlines()).lstrip()
- custom_site_text = custom_site_text.replace("# ___RELOAD_CODE___", reload_code)
-
- skip_rewrite = os.linesep.join(f" {i}" for i in self.skip_rewrite.splitlines()).lstrip()
- custom_site_text = custom_site_text.replace("# ___SKIP_REWRITE____", skip_rewrite)
-
- site_py.write_text(custom_site_text, encoding="utf-8")
-
- @property
- def reload_code(self):
- return 'reload(sys.modules["site"]) # noqa # call system site.py to setup import libraries'
-
- @property
- def skip_rewrite(self):
- return ""
-
- @classmethod
- def sources(cls, interpreter):
- yield from super().sources(interpreter)
- # install files needed to run site.py, either from stdlib or stdlib_platform, at least pyc, but both if exists
- # if neither exists return the module file to trigger failure
- mappings, needs_py_module = (
- cls.mappings(interpreter),
- cls.needs_stdlib_py_module(),
- )
- for req in cls.modules():
- module_file, to_module, module_exists = cls.from_stdlib(mappings, f"{req}.py")
- compiled_file, to_compiled, compiled_exists = cls.from_stdlib(mappings, f"{req}.pyc")
- if needs_py_module or module_exists or not compiled_exists:
- yield PathRefToDest(module_file, dest=to_module)
- if compiled_exists:
- yield PathRefToDest(compiled_file, dest=to_compiled)
-
- @staticmethod
- def from_stdlib(mappings, name):
- for from_std, to_std in mappings:
- src = from_std / name
- if src.exists():
- return src, to_std, True
- # if not exists, fallback to first in list
- return mappings[0][0] / name, mappings[0][1], False
-
- @classmethod
- def mappings(cls, interpreter):
- mappings = [(Path(interpreter.system_stdlib_platform), cls.to_stdlib_platform)]
- if interpreter.system_stdlib_platform != interpreter.system_stdlib:
- mappings.append((Path(interpreter.system_stdlib), cls.to_stdlib))
- return mappings
-
- def to_stdlib(self, src):
- return self.stdlib / src.name
-
- def to_stdlib_platform(self, src):
- return self.stdlib_platform / src.name
-
- @classmethod
- def needs_stdlib_py_module(cls):
- raise NotImplementedError
-
- @classmethod
- def modules(cls):
- return []
-
-
-def get_custom_site():
- return HERE / "site.py"
diff --git a/src/virtualenv/create/via_global_ref/builtin/python2/site.py b/src/virtualenv/create/via_global_ref/builtin/python2/site.py
deleted file mode 100644
index 4decd87..0000000
--- a/src/virtualenv/create/via_global_ref/builtin/python2/site.py
+++ /dev/null
@@ -1,190 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-A simple shim module to fix up things on Python 2 only.
-
-Note: until we setup correctly the paths we can only import built-ins.
-"""
-import sys
-
-
-def main():
- """Patch what needed, and invoke the original site.py"""
- here = __file__ # the distutils.install patterns will be injected relative to this site.py, save it here
- config = read_pyvenv()
- sys.real_prefix = sys.base_prefix = config["base-prefix"]
- sys.base_exec_prefix = config["base-exec-prefix"]
- sys.base_executable = config["base-executable"]
- global_site_package_enabled = config.get("include-system-site-packages", False) == "true"
- rewrite_standard_library_sys_path()
- disable_user_site_package()
- load_host_site(here)
- if global_site_package_enabled:
- add_global_site_package()
- rewrite_getsitepackages(here)
-
-
-def load_host_site(here):
- """trigger reload of site.py - now it will use the standard library instance that will take care of init"""
- # we have a duality here, we generate the platform and pure library path based on what distutils.install specifies
- # because this is what pip will be using; the host site.py though may contain it's own pattern for where the
- # platform and pure library paths should exist
-
- # notably on Ubuntu there's a patch for getsitepackages to point to
- # - prefix + local/lib/pythonx.y/dist-packages
- # - prefix + lib/pythonx.y/dist-packages
- # while distutils.install.cmd still points both of these to
- # - prefix + lib/python2.7/site-packages
-
- # to facilitate when the two match, or not we first reload the site.py, now triggering the import of host site.py,
- # as this will ensure that initialization code within host site.py runs
-
- # ___RELOAD_CODE___
-
- # and then if the distutils site packages are not on the sys.path we add them via add_site_dir; note we must add
- # them by invoking add_site_dir to trigger the processing of pth files
-
- add_site_dir = sys.modules["site"].addsitedir
- for path in get_site_packages_dirs(here):
- add_site_dir(path)
-
-
-def get_site_packages_dirs(here):
- import json
- import os
-
- site_packages = r"""
- ___EXPECTED_SITE_PACKAGES___
- """
-
- for path in json.loads(site_packages):
- yield os.path.abspath(os.path.join(here, path.encode("utf-8")))
-
-
-sep = "\\" if sys.platform == "win32" else "/" # no os module here yet - poor mans version
-
-
-def read_pyvenv():
- """read pyvenv.cfg"""
- config_file = "{}{}pyvenv.cfg".format(sys.prefix, sep)
- with open(config_file) as file_handler:
- lines = file_handler.readlines()
- config = {}
- for line in lines:
- try:
- split_at = line.index("=")
- except ValueError:
- continue # ignore bad/empty lines
- else:
- config[line[:split_at].strip()] = line[split_at + 1 :].strip()
- return config
-
-
-def rewrite_standard_library_sys_path():
- """Once this site file is loaded the standard library paths have already been set, fix them up"""
- exe, prefix, exec_prefix = get_exe_prefixes(base=False)
- base_exe, base_prefix, base_exec = get_exe_prefixes(base=True)
- exe_dir = exe[: exe.rfind(sep)]
- for at, path in enumerate(sys.path):
- path = abs_path(path) # replace old sys prefix path starts with new
- skip_rewrite = path == exe_dir # don't fix the current executable location, notably on Windows this gets added
- skip_rewrite = skip_rewrite # ___SKIP_REWRITE____
- if not skip_rewrite:
- sys.path[at] = map_path(path, base_exe, exe_dir, exec_prefix, base_prefix, prefix, base_exec)
-
- # the rewrite above may have changed elements from PYTHONPATH, revert these if on
- if sys.flags.ignore_environment:
- return
- import os
-
- python_paths = []
- if "PYTHONPATH" in os.environ and os.environ["PYTHONPATH"]:
- for path in os.environ["PYTHONPATH"].split(os.pathsep):
- if path not in python_paths:
- python_paths.append(path)
- sys.path[: len(python_paths)] = python_paths
-
-
-def get_exe_prefixes(base=False):
- return tuple(abs_path(getattr(sys, ("base_" if base else "") + i)) for i in ("executable", "prefix", "exec_prefix"))
-
-
-def abs_path(value):
- values, keep = value.split(sep), []
- at = len(values) - 1
- while at >= 0:
- if values[at] == "..":
- at -= 1
- else:
- keep.append(values[at])
- at -= 1
- return sep.join(keep[::-1])
-
-
-def map_path(path, base_executable, exe_dir, exec_prefix, base_prefix, prefix, base_exec_prefix):
- if path_starts_with(path, exe_dir):
- # content inside the exe folder needs to remap to original executables folder
- orig_exe_folder = base_executable[: base_executable.rfind(sep)]
- return "{}{}".format(orig_exe_folder, path[len(exe_dir) :])
- elif path_starts_with(path, prefix):
- return "{}{}".format(base_prefix, path[len(prefix) :])
- elif path_starts_with(path, exec_prefix):
- return "{}{}".format(base_exec_prefix, path[len(exec_prefix) :])
- return path
-
-
-def path_starts_with(directory, value):
- return directory.startswith(value if value[-1] == sep else value + sep)
-
-
-def disable_user_site_package():
- """Flip the switch on enable user site package"""
- # sys.flags is a c-extension type, so we cannot monkeypatch it, replace it with a python class to flip it
- sys.original_flags = sys.flags
-
- class Flags(object):
- def __init__(self):
- self.__dict__ = {key: getattr(sys.flags, key) for key in dir(sys.flags) if not key.startswith("_")}
-
- sys.flags = Flags()
- sys.flags.no_user_site = 1
-
-
-def add_global_site_package():
- """add the global site package"""
- import site
-
- # add user site package
- sys.flags = sys.original_flags # restore original
- site.ENABLE_USER_SITE = None # reset user site check
- # add the global site package to the path - use new prefix and delegate to site.py
- orig_prefixes = None
- try:
- orig_prefixes = site.PREFIXES
- site.PREFIXES = [sys.base_prefix, sys.base_exec_prefix]
- site.main()
- finally:
- site.PREFIXES = orig_prefixes + site.PREFIXES
-
-
-# Debian and it's derivatives patch this function. We undo the damage
-def rewrite_getsitepackages(here):
- site = sys.modules["site"]
-
- site_package_dirs = get_site_packages_dirs(here)
- orig_getsitepackages = site.getsitepackages
-
- def getsitepackages():
- sitepackages = orig_getsitepackages()
- if sys.prefix not in site.PREFIXES or sys.exec_prefix not in site.PREFIXES:
- # Someone messed with the prefixes, so we stop patching
- return sitepackages
- for path in site_package_dirs:
- if path not in sitepackages:
- sitepackages.insert(0, path)
-
- return sitepackages
-
- site.getsitepackages = getsitepackages
-
-
-main()
diff --git a/src/virtualenv/create/via_global_ref/builtin/ref.py b/src/virtualenv/create/via_global_ref/builtin/ref.py
index fb1cf2e..19210ad 100644
--- a/src/virtualenv/create/via_global_ref/builtin/ref.py
+++ b/src/virtualenv/create/via_global_ref/builtin/ref.py
@@ -4,6 +4,8 @@ references to elements on the file system, allowing our system to automatically
the constraints: e.g. can the file system symlink, can the files be read, executed, etc.
"""
+from __future__ import annotations
+
import os
from abc import ABCMeta, abstractmethod
from collections import OrderedDict
diff --git a/src/virtualenv/create/via_global_ref/builtin/via_global_self_do.py b/src/virtualenv/create/via_global_ref/builtin/via_global_self_do.py
index d57235c..ccf4289 100644
--- a/src/virtualenv/create/via_global_ref/builtin/via_global_self_do.py
+++ b/src/virtualenv/create/via_global_ref/builtin/via_global_self_do.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta
from virtualenv.create.via_global_ref.builtin.ref import (
diff --git a/src/virtualenv/create/via_global_ref/store.py b/src/virtualenv/create/via_global_ref/store.py
index a9c559c..0169f82 100644
--- a/src/virtualenv/create/via_global_ref/store.py
+++ b/src/virtualenv/create/via_global_ref/store.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from pathlib import Path
diff --git a/src/virtualenv/create/via_global_ref/venv.py b/src/virtualenv/create/via_global_ref/venv.py
index 071375a..f0ee844 100644
--- a/src/virtualenv/create/via_global_ref/venv.py
+++ b/src/virtualenv/create/via_global_ref/venv.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
from copy import copy
@@ -26,7 +28,7 @@ class Venv(ViaGlobalRefApi):
def can_create(cls, interpreter):
if interpreter.has_venv:
meta = ViaGlobalRefMeta()
- if interpreter.platform == "win32" and interpreter.version_info.major == 3:
+ if interpreter.platform == "win32":
meta = handle_store_python(meta, interpreter)
return meta
return None
diff --git a/src/virtualenv/discovery/builtin.py b/src/virtualenv/discovery/builtin.py
index 40320d3..58a912d 100644
--- a/src/virtualenv/discovery/builtin.py
+++ b/src/virtualenv/discovery/builtin.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import sys
diff --git a/src/virtualenv/discovery/cached_py_info.py b/src/virtualenv/discovery/cached_py_info.py
index 3edaca9..e8cc34c 100644
--- a/src/virtualenv/discovery/cached_py_info.py
+++ b/src/virtualenv/discovery/cached_py_info.py
@@ -5,6 +5,8 @@ cheap, especially not on Windows. To not have to pay this hefty cost every time
caching.
"""
+from __future__ import annotations
+
import logging
import os
import random
diff --git a/src/virtualenv/discovery/discover.py b/src/virtualenv/discovery/discover.py
index d44758c..28e07dd 100644
--- a/src/virtualenv/discovery/discover.py
+++ b/src/virtualenv/discovery/discover.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta, abstractmethod
diff --git a/src/virtualenv/discovery/py_info.py b/src/virtualenv/discovery/py_info.py
index ffff7aa..a28c518 100644
--- a/src/virtualenv/discovery/py_info.py
+++ b/src/virtualenv/discovery/py_info.py
@@ -3,7 +3,8 @@ The PythonInfo contains information about a concrete instance of a Python interp
Note: this file is also used to query target interpreters, so can only use standard library methods
"""
-from __future__ import absolute_import, print_function
+
+from __future__ import annotations
import json
import logging
@@ -27,44 +28,41 @@ EXTENSIONS = _get_path_extensions()
_CONF_VAR_RE = re.compile(r"\{\w+\}")
-class PythonInfo(object):
+class PythonInfo:
"""Contains information for a Python interpreter"""
def __init__(self):
- def u(v):
- return v.decode("utf-8") if isinstance(v, bytes) else v
-
def abs_path(v):
return None if v is None else os.path.abspath(v) # unroll relative elements from path (e.g. ..)
# qualifies the python
- self.platform = u(sys.platform)
- self.implementation = u(platform.python_implementation())
+ self.platform = sys.platform
+ self.implementation = platform.python_implementation()
if self.implementation == "PyPy":
- self.pypy_version_info = tuple(u(i) for i in sys.pypy_version_info)
+ self.pypy_version_info = tuple(sys.pypy_version_info)
# this is a tuple in earlier, struct later, unify to our own named tuple
- self.version_info = VersionInfo(*[u(i) for i in sys.version_info])
+ self.version_info = VersionInfo(*sys.version_info)
self.architecture = 64 if sys.maxsize > 2**32 else 32
# Used to determine some file names.
# See `CPython3Windows.python_zip()`.
self.version_nodot = sysconfig.get_config_var("py_version_nodot")
- self.version = u(sys.version)
- self.os = u(os.name)
+ self.version = sys.version
+ self.os = os.name
# information about the prefix - determines python home
- self.prefix = u(abs_path(getattr(sys, "prefix", None))) # prefix we think
- self.base_prefix = u(abs_path(getattr(sys, "base_prefix", None))) # venv
- self.real_prefix = u(abs_path(getattr(sys, "real_prefix", None))) # old virtualenv
+ self.prefix = abs_path(getattr(sys, "prefix", None)) # prefix we think
+ self.base_prefix = abs_path(getattr(sys, "base_prefix", None)) # venv
+ self.real_prefix = abs_path(getattr(sys, "real_prefix", None)) # old virtualenv
# information about the exec prefix - dynamic stdlib modules
- self.base_exec_prefix = u(abs_path(getattr(sys, "base_exec_prefix", None)))
- self.exec_prefix = u(abs_path(getattr(sys, "exec_prefix", None)))
+ self.base_exec_prefix = abs_path(getattr(sys, "base_exec_prefix", None))
+ self.exec_prefix = abs_path(getattr(sys, "exec_prefix", None))
- self.executable = u(abs_path(sys.executable)) # the executable we were invoked via
- self.original_executable = u(abs_path(self.executable)) # the executable as known by the interpreter
+ self.executable = abs_path(sys.executable) # the executable we were invoked via
+ self.original_executable = abs_path(self.executable) # the executable as known by the interpreter
self.system_executable = self._fast_get_system_executable() # the executable we are based of (if available)
try:
@@ -73,17 +71,16 @@ class PythonInfo(object):
except ImportError:
has = False
self.has_venv = has
- self.path = [u(i) for i in sys.path]
- self.file_system_encoding = u(sys.getfilesystemencoding())
- self.stdout_encoding = u(getattr(sys.stdout, "encoding", None))
+ self.path = sys.path
+ self.file_system_encoding = sys.getfilesystemencoding()
+ self.stdout_encoding = getattr(sys.stdout, "encoding", None)
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=self.sysconfig_scheme))
- for i in sysconfig.get_path_names()
+ 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 = {}
@@ -99,13 +96,13 @@ class PythonInfo(object):
self.distutils_install = {}
else:
self.sysconfig_scheme = None
- self.sysconfig_paths = {u(i): u(sysconfig.get_path(i, expand=False)) for i in sysconfig.get_path_names()}
- self.distutils_install = {u(k): u(v) for k, v in self._distutils_install().items()}
+ self.sysconfig_paths = {i: sysconfig.get_path(i, expand=False) for i in sysconfig.get_path_names()}
+ self.distutils_install = self._distutils_install().copy()
# https://bugs.python.org/issue22199
makefile = getattr(sysconfig, "get_makefile_filename", getattr(sysconfig, "_get_makefile_filename", None))
self.sysconfig = {
- u(k): u(v)
+ k: v
for k, v in [
# a list of content to store from sysconfig
("makefile_filename", makefile()),
@@ -116,14 +113,15 @@ class PythonInfo(object):
config_var_keys = set()
for element in self.sysconfig_paths.values():
for k in _CONF_VAR_RE.findall(element):
- config_var_keys.add(u(k[1:-1]))
+ config_var_keys.add(k[1:-1])
config_var_keys.add("PYTHONFRAMEWORK")
- self.sysconfig_vars = {u(i): u(sysconfig.get_config_var(i) or "") for i in config_var_keys}
- if self.implementation == "PyPy" and sys.version_info.major == 2:
- self.sysconfig_vars["implementation_lower"] = "python"
+ self.sysconfig_vars = {i: sysconfig.get_config_var(i or "") for i in config_var_keys}
- confs = {k: (self.system_prefix if v.startswith(self.prefix) else v) for k, v in self.sysconfig_vars.items()}
+ confs = {
+ k: (self.system_prefix if v is not None and v.startswith(self.prefix) else v)
+ for k, v in self.sysconfig_vars.items()
+ }
self.system_stdlib = self.sysconfig_path("stdlib", confs)
self.system_stdlib_platform = self.sysconfig_path("platstdlib", confs)
self.max_size = getattr(sys, "maxsize", getattr(sys, "maxint", None))
@@ -151,8 +149,7 @@ class PythonInfo(object):
# search relative to the directory of sys._base_executable
base_dir = os.path.dirname(base_executable)
for base_executable in [
- os.path.join(base_dir, exe)
- for exe in ("python{}".format(major), "python{}.{}".format(major, minor))
+ os.path.join(base_dir, exe) for exe in (f"python{major}", f"python{major}.{minor}")
]:
if os.path.exists(base_executable):
return base_executable
@@ -193,7 +190,7 @@ class PythonInfo(object):
i.prefix = os.sep # paths generated are relative to prefix that contains the path sep, this makes it relative
i.finalize_options()
- result = {key: (getattr(i, "install_{}".format(key))[1:]).lstrip(os.sep) for key in SCHEME_KEYS}
+ result = {key: (getattr(i, f"install_{key}")[1:]).lstrip(os.sep) for key in SCHEME_KEYS}
return result
@property
@@ -207,7 +204,7 @@ class PythonInfo(object):
@property
def python_name(self):
version_info = self.version_info
- return "python{}.{}".format(version_info.major, version_info.minor)
+ return f"python{version_info.major}.{version_info.minor}"
@property
def is_old_virtualenv(self):
@@ -215,7 +212,7 @@ class PythonInfo(object):
@property
def is_venv(self):
- return self.base_prefix is not None and self.version_info.major == 3
+ return self.base_prefix is not None
def sysconfig_path(self, key, config_var=None, sep=os.sep):
pattern = self.sysconfig_paths[key]
@@ -238,7 +235,10 @@ class PythonInfo(object):
def system_include(self):
path = self.sysconfig_path(
"include",
- {k: (self.system_prefix if v.startswith(self.prefix) else v) for k, v in self.sysconfig_vars.items()},
+ {
+ k: (self.system_prefix if v is not None and v.startswith(self.prefix) else v)
+ for k, v in self.sysconfig_vars.items()
+ },
)
if not os.path.exists(path): # some broken packaging don't respect the sysconfig, fallback to distutils path
# the pattern include the distribution name too at the end, remove that via the parent call
@@ -257,8 +257,6 @@ class PythonInfo(object):
def __unicode__(self):
content = repr(self)
- if sys.version_info == 2:
- content = content.decode("utf-8")
return content
def __repr__(self):
@@ -271,7 +269,7 @@ class PythonInfo(object):
content = "{}({})".format(
self.__class__.__name__,
", ".join(
- "{}={}".format(k, v)
+ f"{k}={v}"
for k, v in (
("spec", self.spec),
(
@@ -292,7 +290,7 @@ class PythonInfo(object):
("exe", self.executable),
("platform", self.platform),
("version", repr(self.version)),
- ("encoding_fs_io", "{}-{}".format(self.file_system_encoding, self.stdout_encoding)),
+ ("encoding_fs_io", f"{self.file_system_encoding}-{self.stdout_encoding}"),
)
if k is not None
),
@@ -512,7 +510,7 @@ class PythonInfo(object):
# following path pattern of the current
if base.startswith(self.prefix):
relative = base[len(self.prefix) :]
- candidate_folder["{}{}".format(inside_folder, relative)] = None
+ candidate_folder[f"{inside_folder}{relative}"] = None
# or at root level
candidate_folder[inside_folder] = None
@@ -523,9 +521,9 @@ class PythonInfo(object):
for name in self._possible_base():
for at in (3, 2, 1, 0):
version = ".".join(str(i) for i in self.version_info[:at])
- for arch in ["-{}".format(self.architecture), ""]:
+ for arch in [f"-{self.architecture}", ""]:
for ext in EXTENSIONS:
- candidate = "{}{}{}{}".format(name, version, arch, ext)
+ candidate = f"{name}{version}{arch}{ext}"
name_candidate[candidate] = None
return list(name_candidate.keys())
diff --git a/src/virtualenv/discovery/py_spec.py b/src/virtualenv/discovery/py_spec.py
index 103c7ae..04ff645 100644
--- a/src/virtualenv/discovery/py_spec.py
+++ b/src/virtualenv/discovery/py_spec.py
@@ -1,5 +1,7 @@
"""A Python specification is an abstract requirement definition of an interpreter"""
+from __future__ import annotations
+
import os
import re
from collections import OrderedDict
diff --git a/src/virtualenv/discovery/windows/__init__.py b/src/virtualenv/discovery/windows/__init__.py
index 068a187..f2ceb4b 100644
--- a/src/virtualenv/discovery/windows/__init__.py
+++ b/src/virtualenv/discovery/windows/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from ..py_info import PythonInfo
from ..py_spec import PythonSpec
from .pep514 import discover_pythons
diff --git a/src/virtualenv/discovery/windows/pep514.py b/src/virtualenv/discovery/windows/pep514.py
index beb1d81..ccf3ec1 100644
--- a/src/virtualenv/discovery/windows/pep514.py
+++ b/src/virtualenv/discovery/windows/pep514.py
@@ -1,5 +1,7 @@
"""Implement https://www.python.org/dev/peps/pep-0514/ to discover interpreters - Windows only"""
+from __future__ import annotations
+
import os
import re
import winreg
diff --git a/src/virtualenv/info.py b/src/virtualenv/info.py
index a4fc4bf..1562ff2 100644
--- a/src/virtualenv/info.py
+++ b/src/virtualenv/info.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import platform
diff --git a/src/virtualenv/report.py b/src/virtualenv/report.py
index 0236f21..be17216 100644
--- a/src/virtualenv/report.py
+++ b/src/virtualenv/report.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import sys
diff --git a/src/virtualenv/run/__init__.py b/src/virtualenv/run/__init__.py
index 6d22b71..ea2a40c 100644
--- a/src/virtualenv/run/__init__.py
+++ b/src/virtualenv/run/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
from functools import partial
diff --git a/src/virtualenv/run/plugin/activators.py b/src/virtualenv/run/plugin/activators.py
index 320cae7..0d4fd8f 100644
--- a/src/virtualenv/run/plugin/activators.py
+++ b/src/virtualenv/run/plugin/activators.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from argparse import ArgumentTypeError
from collections import OrderedDict
diff --git a/src/virtualenv/run/plugin/base.py b/src/virtualenv/run/plugin/base.py
index 3eb8ab3..ddb2369 100644
--- a/src/virtualenv/run/plugin/base.py
+++ b/src/virtualenv/run/plugin/base.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
from collections import OrderedDict
diff --git a/src/virtualenv/run/plugin/creators.py b/src/virtualenv/run/plugin/creators.py
index 8953064..fd47db2 100644
--- a/src/virtualenv/run/plugin/creators.py
+++ b/src/virtualenv/run/plugin/creators.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from collections import OrderedDict, defaultdict, namedtuple
from virtualenv.create.describe import Describe
diff --git a/src/virtualenv/run/plugin/discovery.py b/src/virtualenv/run/plugin/discovery.py
index 13f39ed..caabc95 100644
--- a/src/virtualenv/run/plugin/discovery.py
+++ b/src/virtualenv/run/plugin/discovery.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from .base import PluginLoader
diff --git a/src/virtualenv/run/plugin/seeders.py b/src/virtualenv/run/plugin/seeders.py
index 1a51d2e..f1cd605 100644
--- a/src/virtualenv/run/plugin/seeders.py
+++ b/src/virtualenv/run/plugin/seeders.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from .base import ComponentBuilder
diff --git a/src/virtualenv/run/session.py b/src/virtualenv/run/session.py
index 2c8821c..15ec597 100644
--- a/src/virtualenv/run/session.py
+++ b/src/virtualenv/run/session.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import json
import logging
diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py
index f29110b..65f2b97 100644
--- a/src/virtualenv/seed/embed/base_embed.py
+++ b/src/virtualenv/seed/embed/base_embed.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta
from pathlib import Path
diff --git a/src/virtualenv/seed/embed/pip_invoke.py b/src/virtualenv/seed/embed/pip_invoke.py
index 2ca9438..032f14d 100644
--- a/src/virtualenv/seed/embed/pip_invoke.py
+++ b/src/virtualenv/seed/embed/pip_invoke.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
from contextlib import contextmanager
from subprocess import Popen
diff --git a/src/virtualenv/seed/embed/via_app_data/pip_install/base.py b/src/virtualenv/seed/embed/via_app_data/pip_install/base.py
index 4fa3304..5e87b80 100644
--- a/src/virtualenv/seed/embed/via_app_data/pip_install/base.py
+++ b/src/virtualenv/seed/embed/via_app_data/pip_install/base.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import re
diff --git a/src/virtualenv/seed/embed/via_app_data/pip_install/copy.py b/src/virtualenv/seed/embed/via_app_data/pip_install/copy.py
index f5717e1..b5f01aa 100644
--- a/src/virtualenv/seed/embed/via_app_data/pip_install/copy.py
+++ b/src/virtualenv/seed/embed/via_app_data/pip_install/copy.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from pathlib import Path
diff --git a/src/virtualenv/seed/embed/via_app_data/pip_install/symlink.py b/src/virtualenv/seed/embed/via_app_data/pip_install/symlink.py
index 4695de5..7460fff 100644
--- a/src/virtualenv/seed/embed/via_app_data/pip_install/symlink.py
+++ b/src/virtualenv/seed/embed/via_app_data/pip_install/symlink.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from stat import S_IREAD, S_IRGRP, S_IROTH
from subprocess import PIPE, Popen
diff --git a/src/virtualenv/seed/embed/via_app_data/via_app_data.py b/src/virtualenv/seed/embed/via_app_data/via_app_data.py
index f31ecf6..0c36250 100644
--- a/src/virtualenv/seed/embed/via_app_data/via_app_data.py
+++ b/src/virtualenv/seed/embed/via_app_data/via_app_data.py
@@ -1,5 +1,7 @@
"""Bootstrap"""
+from __future__ import annotations
+
import logging
import sys
import traceback
diff --git a/src/virtualenv/seed/seeder.py b/src/virtualenv/seed/seeder.py
index d06d1a0..a87c2a3 100644
--- a/src/virtualenv/seed/seeder.py
+++ b/src/virtualenv/seed/seeder.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta, abstractmethod
diff --git a/src/virtualenv/seed/wheels/__init__.py b/src/virtualenv/seed/wheels/__init__.py
index c563181..94b4cc9 100644
--- a/src/virtualenv/seed/wheels/__init__.py
+++ b/src/virtualenv/seed/wheels/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from .acquire import get_wheel, pip_wheel_env_run
from .util import Version, Wheel
diff --git a/src/virtualenv/seed/wheels/acquire.py b/src/virtualenv/seed/wheels/acquire.py
index 21fde34..aaa0eb0 100644
--- a/src/virtualenv/seed/wheels/acquire.py
+++ b/src/virtualenv/seed/wheels/acquire.py
@@ -1,5 +1,7 @@
"""Bootstrap"""
+from __future__ import annotations
+
import logging
import sys
from operator import eq, lt
diff --git a/src/virtualenv/seed/wheels/bundle.py b/src/virtualenv/seed/wheels/bundle.py
index 66bbe56..e2c6095 100644
--- a/src/virtualenv/seed/wheels/bundle.py
+++ b/src/virtualenv/seed/wheels/bundle.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from ..wheels.embed import get_embed_wheel
from .periodic_update import periodic_update
from .util import Version, Wheel, discover_wheels
diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py
index 782051a..8f15d16 100644
--- a/src/virtualenv/seed/wheels/embed/__init__.py
+++ b/src/virtualenv/seed/wheels/embed/__init__.py
@@ -1,56 +1,43 @@
+from __future__ import annotations
+
from pathlib import Path
from virtualenv.seed.wheels.util import Wheel
BUNDLE_FOLDER = Path(__file__).absolute().parent
BUNDLE_SUPPORT = {
- "3.12": {
+ "3.7": {
"pip": "pip-23.1-py3-none-any.whl",
"setuptools": "setuptools-67.6.1-py3-none-any.whl",
"wheel": "wheel-0.40.0-py3-none-any.whl",
},
- "3.11": {
+ "3.8": {
"pip": "pip-23.1-py3-none-any.whl",
"setuptools": "setuptools-67.6.1-py3-none-any.whl",
"wheel": "wheel-0.40.0-py3-none-any.whl",
},
- "3.10": {
+ "3.9": {
"pip": "pip-23.1-py3-none-any.whl",
"setuptools": "setuptools-67.6.1-py3-none-any.whl",
"wheel": "wheel-0.40.0-py3-none-any.whl",
},
- "3.9": {
+ "3.10": {
"pip": "pip-23.1-py3-none-any.whl",
"setuptools": "setuptools-67.6.1-py3-none-any.whl",
"wheel": "wheel-0.40.0-py3-none-any.whl",
},
- "3.8": {
+ "3.11": {
"pip": "pip-23.1-py3-none-any.whl",
"setuptools": "setuptools-67.6.1-py3-none-any.whl",
"wheel": "wheel-0.40.0-py3-none-any.whl",
},
- "3.7": {
+ "3.12": {
"pip": "pip-23.1-py3-none-any.whl",
"setuptools": "setuptools-67.6.1-py3-none-any.whl",
"wheel": "wheel-0.40.0-py3-none-any.whl",
},
- "3.6": {
- "pip": "pip-21.3.1-py3-none-any.whl",
- "setuptools": "setuptools-59.6.0-py3-none-any.whl",
- "wheel": "wheel-0.37.1-py2.py3-none-any.whl",
- },
- "3.5": {
- "pip": "pip-20.3.4-py2.py3-none-any.whl",
- "setuptools": "setuptools-50.3.2-py3-none-any.whl",
- "wheel": "wheel-0.37.1-py2.py3-none-any.whl",
- },
- "2.7": {
- "pip": "pip-20.3.4-py2.py3-none-any.whl",
- "setuptools": "setuptools-44.1.1-py2.py3-none-any.whl",
- "wheel": "wheel-0.37.1-py2.py3-none-any.whl",
- },
}
-MAX = "3.12"
+MAX = "3.7"
def get_embed_wheel(distribution, for_py_version):
diff --git a/src/virtualenv/seed/wheels/embed/pip-20.3.4-py2.py3-none-any.whl b/src/virtualenv/seed/wheels/embed/pip-20.3.4-py2.py3-none-any.whl
deleted file mode 100644
index 95de4d7..0000000
--- a/src/virtualenv/seed/wheels/embed/pip-20.3.4-py2.py3-none-any.whl
+++ /dev/null
Binary files differ
diff --git a/src/virtualenv/seed/wheels/embed/pip-21.3.1-py3-none-any.whl b/src/virtualenv/seed/wheels/embed/pip-21.3.1-py3-none-any.whl
deleted file mode 100644
index 769bae6..0000000
--- a/src/virtualenv/seed/wheels/embed/pip-21.3.1-py3-none-any.whl
+++ /dev/null
Binary files differ
diff --git a/src/virtualenv/seed/wheels/embed/setuptools-44.1.1-py2.py3-none-any.whl b/src/virtualenv/seed/wheels/embed/setuptools-44.1.1-py2.py3-none-any.whl
deleted file mode 100644
index bf28513..0000000
--- a/src/virtualenv/seed/wheels/embed/setuptools-44.1.1-py2.py3-none-any.whl
+++ /dev/null
Binary files differ
diff --git a/src/virtualenv/seed/wheels/embed/setuptools-50.3.2-py3-none-any.whl b/src/virtualenv/seed/wheels/embed/setuptools-50.3.2-py3-none-any.whl
deleted file mode 100644
index 56d1bf9..0000000
--- a/src/virtualenv/seed/wheels/embed/setuptools-50.3.2-py3-none-any.whl
+++ /dev/null
Binary files differ
diff --git a/src/virtualenv/seed/wheels/embed/setuptools-59.6.0-py3-none-any.whl b/src/virtualenv/seed/wheels/embed/setuptools-59.6.0-py3-none-any.whl
deleted file mode 100644
index 08d7e94..0000000
--- a/src/virtualenv/seed/wheels/embed/setuptools-59.6.0-py3-none-any.whl
+++ /dev/null
Binary files differ
diff --git a/src/virtualenv/seed/wheels/embed/wheel-0.37.1-py2.py3-none-any.whl b/src/virtualenv/seed/wheels/embed/wheel-0.37.1-py2.py3-none-any.whl
deleted file mode 100644
index e6c4d95..0000000
--- a/src/virtualenv/seed/wheels/embed/wheel-0.37.1-py2.py3-none-any.whl
+++ /dev/null
Binary files differ
diff --git a/src/virtualenv/seed/wheels/periodic_update.py b/src/virtualenv/seed/wheels/periodic_update.py
index 2088c9d..d1767ce 100644
--- a/src/virtualenv/seed/wheels/periodic_update.py
+++ b/src/virtualenv/seed/wheels/periodic_update.py
@@ -3,6 +3,8 @@ Periodically update bundled versions.
"""
+from __future__ import annotations
+
import json
import logging
import os
diff --git a/src/virtualenv/seed/wheels/util.py b/src/virtualenv/seed/wheels/util.py
index f09d873..5843575 100644
--- a/src/virtualenv/seed/wheels/util.py
+++ b/src/virtualenv/seed/wheels/util.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from operator import attrgetter
from zipfile import ZipFile
diff --git a/src/virtualenv/util/error.py b/src/virtualenv/util/error.py
index 945a25e..5862226 100644
--- a/src/virtualenv/util/error.py
+++ b/src/virtualenv/util/error.py
@@ -1,6 +1,9 @@
"""Errors"""
+from __future__ import annotations
+
+
class ProcessCallFailed(RuntimeError):
"""Failed a process call"""
diff --git a/src/virtualenv/util/lock.py b/src/virtualenv/util/lock.py
index cf026f4..c0774d1 100644
--- a/src/virtualenv/util/lock.py
+++ b/src/virtualenv/util/lock.py
@@ -1,5 +1,7 @@
"""holds locking functionality that works across processes"""
+from __future__ import annotations
+
import logging
import os
from abc import ABCMeta, abstractmethod
diff --git a/src/virtualenv/util/path/__init__.py b/src/virtualenv/util/path/__init__.py
index 39a8db7..dc827f3 100644
--- a/src/virtualenv/util/path/__init__.py
+++ b/src/virtualenv/util/path/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from ._permission import make_exe, set_tree
from ._sync import copy, copytree, ensure_dir, safe_delete, symlink
from ._win import get_short_path_name
diff --git a/src/virtualenv/util/path/_permission.py b/src/virtualenv/util/path/_permission.py
index ca92314..8dcad0c 100644
--- a/src/virtualenv/util/path/_permission.py
+++ b/src/virtualenv/util/path/_permission.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from stat import S_IXGRP, S_IXOTH, S_IXUSR
diff --git a/src/virtualenv/util/path/_sync.py b/src/virtualenv/util/path/_sync.py
index 604379d..f0e0173 100644
--- a/src/virtualenv/util/path/_sync.py
+++ b/src/virtualenv/util/path/_sync.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import shutil
diff --git a/src/virtualenv/util/path/_win.py b/src/virtualenv/util/path/_win.py
index d83eabb..94eaf65 100644
--- a/src/virtualenv/util/path/_win.py
+++ b/src/virtualenv/util/path/_win.py
@@ -1,3 +1,6 @@
+from __future__ import annotations
+
+
def get_short_path_name(long_name):
"""
Gets the short path name of a given long path.
diff --git a/src/virtualenv/util/subprocess/__init__.py b/src/virtualenv/util/subprocess/__init__.py
index efae569..cb71fa7 100644
--- a/src/virtualenv/util/subprocess/__init__.py
+++ b/src/virtualenv/util/subprocess/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import subprocess
CREATE_NO_WINDOW = 0x80000000
diff --git a/src/virtualenv/util/zipapp.py b/src/virtualenv/util/zipapp.py
index e7578c4..5271ebb 100644
--- a/src/virtualenv/util/zipapp.py
+++ b/src/virtualenv/util/zipapp.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import zipfile
diff --git a/tasks/__main__zipapp.py b/tasks/__main__zipapp.py
index 87d4589..e48620b 100644
--- a/tasks/__main__zipapp.py
+++ b/tasks/__main__zipapp.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import json
import os
import sys
@@ -7,7 +9,7 @@ ABS_HERE = os.path.abspath(os.path.dirname(__file__))
NEW_IMPORT_SYSTEM = sys.version_info[0] == 3
-class VersionPlatformSelect(object):
+class VersionPlatformSelect:
def __init__(self):
self.archive = ABS_HERE
self._zip_file = zipfile.ZipFile(ABS_HERE, "r")
@@ -20,11 +22,11 @@ class VersionPlatformSelect(object):
per_version = json.loads(self.get_data(of_file).decode("utf-8"))
all_platforms = per_version[version] if version in per_version else per_version["3.9"]
content = all_platforms.get("==any", {}) # start will all platforms
- not_us = "!={}".format(sys.platform)
+ not_us = f"!={sys.platform}"
for key, value in all_platforms.items(): # now override that with not platform
if key.startswith("!=") and key != not_us:
content.update(value)
- content.update(all_platforms.get("=={}".format(sys.platform), {})) # and finish it off with our platform
+ content.update(all_platforms.get(f"=={sys.platform}", {})) # and finish it off with our platform
return content
def __enter__(self):
@@ -61,19 +63,19 @@ class VersionPlatformSelect(object):
yield result
def __repr__(self):
- return "{}(path={})".format(self.__class__.__name__, ABS_HERE)
+ return f"{self.__class__.__name__}(path={ABS_HERE})"
def _register_distutils_finder(self):
if "distlib" not in self.modules:
return
- class DistlibFinder(object):
+ class DistlibFinder:
def __init__(self, path, loader):
self.path = path
self.loader = loader
def find(self, name):
- class Resource(object):
+ class Resource:
def __init__(self, content):
self.bytes = content
diff --git a/tasks/make_zipapp.py b/tasks/make_zipapp.py
index 67286f6..5303f41 100644
--- a/tasks/make_zipapp.py
+++ b/tasks/make_zipapp.py
@@ -1,4 +1,6 @@
"""https://docs.python.org/3/library/zipapp.html"""
+from __future__ import annotations
+
import argparse
import io
import json
@@ -20,7 +22,7 @@ from packaging.requirements import Requirement
HERE = Path(__file__).parent.absolute()
-VERSIONS = [f"3.{i}" for i in range(10, 5, -1)]
+VERSIONS = [f"3.{i}" for i in range(10, 6, -1)]
def main():
@@ -223,7 +225,13 @@ class WheelDownloader:
def run_suppress_output(cmd, stop_print_on_fail=False):
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+ process = subprocess.Popen(
+ cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ encoding="utf-8",
+ )
out, err = process.communicate()
if stop_print_on_fail and process.returncode != 0:
print(f"exit with {process.returncode} of {' '.join(quote(i) for i in cmd)}", file=sys.stdout)
diff --git a/tasks/release.py b/tasks/release.py
index 8724bf2..0d5ac38 100644
--- a/tasks/release.py
+++ b/tasks/release.py
@@ -1,7 +1,8 @@
"""Handles creating a release PR"""
+from __future__ import annotations
+
from pathlib import Path
from subprocess import check_call
-from typing import Tuple
from git import Commit, Head, Remote, Repo, TagReference
from packaging.version import Version
@@ -25,7 +26,7 @@ def main(version_str: str) -> None:
print("All done! ✨ 🍰 ✨")
-def create_release_branch(repo: Repo, version: Version) -> Tuple[Remote, Head]:
+def create_release_branch(repo: Repo, version: Version) -> tuple[Remote, Head]:
print("create release branch from upstream main")
upstream = get_upstream(repo)
upstream.fetch()
diff --git a/tasks/update_embedded.py b/tasks/update_embedded.py
index 2f44531..3f159f0 100755
--- a/tasks/update_embedded.py
+++ b/tasks/update_embedded.py
@@ -1,5 +1,7 @@
"""Helper script to rebuild virtualenv.py from virtualenv_support"""
+from __future__ import annotations
+
import codecs
import os
import re
diff --git a/tasks/upgrade_wheels.py b/tasks/upgrade_wheels.py
index 76750da..beb2df7 100644
--- a/tasks/upgrade_wheels.py
+++ b/tasks/upgrade_wheels.py
@@ -2,6 +2,8 @@
Helper script to rebuild virtualenv_support. Downloads the wheel files using pip
"""
+from __future__ import annotations
+
import os
import shutil
import subprocess
@@ -15,7 +17,7 @@ from threading import Thread
STRICT = "UPGRADE_ADVISORY" not in os.environ
BUNDLED = ["pip", "setuptools", "wheel"]
-SUPPORT = list(reversed([(2, 7)] + [(3, i) for i in range(5, 13)]))
+SUPPORT = [(3, i) for i in range(7, 13)]
DEST = Path(__file__).resolve().parents[1] / "src" / "virtualenv" / "seed" / "wheels" / "embed"
@@ -81,7 +83,7 @@ def run():
lines.append("")
changelog = "\n".join(lines)
print(changelog)
- if len(lines) >= 3:
+ if len(lines) >= 4:
(Path(__file__).parents[1] / "docs" / "changelog" / "u.bugfix.rst").write_text(changelog, encoding="utf-8")
support_table = OrderedDict((".".join(str(j) for j in i), []) for i in SUPPORT)
for package in sorted(new_batch.keys()):
diff --git a/tests/conftest.py b/tests/conftest.py
index 68924dc..72db0d5 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import shutil
@@ -9,7 +11,6 @@ from pathlib import Path
import pytest
from virtualenv.app_data import AppDataDiskFolder
-from virtualenv.discovery.builtin import get_interpreter
from virtualenv.discovery.py_info import PythonInfo
from virtualenv.info import IS_WIN, fs_supports_symlink
from virtualenv.report import LOGGER
@@ -54,9 +55,9 @@ def has_symlink_support(tmp_path_factory): # noqa: U100
def link_folder(has_symlink_support):
if has_symlink_support:
return os.symlink
- elif sys.platform == "win32" and sys.version_info[0:2] > (3, 4):
+ elif sys.platform == "win32":
# on Windows junctions may be used instead
- import _winapi # Cpython3.5 has builtin implementation for junctions
+ import _winapi
return getattr(_winapi, "CreateJunction", None)
else:
@@ -358,18 +359,6 @@ def temp_app_data(monkeypatch, tmp_path):
@pytest.fixture(scope="session")
-def cross_python(is_inside_ci, session_app_data):
- spec = str(2 if sys.version_info[0] == 3 else 3)
- interpreter = get_interpreter(spec, [], session_app_data)
- if interpreter is None:
- msg = f"could not find {spec}"
- if is_inside_ci:
- raise RuntimeError(msg)
- pytest.skip(msg=msg)
- return interpreter
-
-
-@pytest.fixture(scope="session")
def for_py_version():
return f"{sys.version_info.major}.{sys.version_info.minor}"
diff --git a/tests/integration/test_run_int.py b/tests/integration/test_run_int.py
index 8ca310e..36aaf4f 100644
--- a/tests/integration/test_run_int.py
+++ b/tests/integration/test_run_int.py
@@ -1,4 +1,4 @@
-import sys
+from __future__ import annotations
import pytest
@@ -9,7 +9,7 @@ from virtualenv.util.subprocess import run_cmd
@pytest.mark.skipif(IS_PYPY, reason="setuptools distutils patching does not work")
def test_app_data_pinning(tmp_path):
- version = "19.1.1" if sys.version_info[0:2] == (3, 4) else "19.3.1"
+ version = "19.3.1"
result = cli_run([str(tmp_path), "--pip", version, "--activators", "", "--seeder", "app-data"])
code, out, _ = run_cmd([str(result.creator.script("pip")), "list", "--disable-pip-version-check"])
assert not code
diff --git a/tests/integration/test_zipapp.py b/tests/integration/test_zipapp.py
index 2472daa..b2f27a0 100644
--- a/tests/integration/test_zipapp.py
+++ b/tests/integration/test_zipapp.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import shutil
import subprocess
from pathlib import Path
diff --git a/tests/unit/activation/conftest.py b/tests/unit/activation/conftest.py
index 3a93b15..6a46934 100644
--- a/tests/unit/activation/conftest.py
+++ b/tests/unit/activation/conftest.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
import re
import subprocess
diff --git a/tests/unit/activation/test_activate_this.py b/tests/unit/activation/test_activate_this.py
deleted file mode 100644
index b7a4d60..0000000
--- a/tests/unit/activation/test_activate_this.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from virtualenv.activation import PythonActivator
-from virtualenv.config.cli.parser import VirtualEnvOptions
-from virtualenv.run import session_via_cli
-
-
-def test_python_activator_cross(session_app_data, cross_python, special_name_dir):
- options = VirtualEnvOptions()
- cli_args = [
- str(special_name_dir),
- "-p",
- str(cross_python.executable),
- "--app-data",
- str(session_app_data.lock.path),
- "--without-pip",
- "--activators",
- "",
- ]
- session = session_via_cli(cli_args, options)
- activator = PythonActivator(options)
- session.creator.bin_dir.mkdir(parents=True)
- results = activator.generate(session.creator)
- assert len(results) == 1
- result = results[0]
- content = result.read_text(encoding="utf-8")
- # check that the repr strings have been correctly stripped
- assert "\"'" not in content
diff --git a/tests/unit/activation/test_activation_support.py b/tests/unit/activation/test_activation_support.py
index 4bca363..e25fc96 100644
--- a/tests/unit/activation/test_activation_support.py
+++ b/tests/unit/activation/test_activation_support.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from argparse import Namespace
import pytest
diff --git a/tests/unit/activation/test_activator.py b/tests/unit/activation/test_activator.py
index c8e973a..9b15b0b 100644
--- a/tests/unit/activation/test_activator.py
+++ b/tests/unit/activation/test_activator.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from argparse import Namespace
from virtualenv.activation.activator import Activator
diff --git a/tests/unit/activation/test_bash.py b/tests/unit/activation/test_bash.py
index ae56896..4a36767 100644
--- a/tests/unit/activation/test_bash.py
+++ b/tests/unit/activation/test_bash.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import pytest
from virtualenv.activation import BashActivator
diff --git a/tests/unit/activation/test_batch.py b/tests/unit/activation/test_batch.py
index 9e6d6d6..458278f 100644
--- a/tests/unit/activation/test_batch.py
+++ b/tests/unit/activation/test_batch.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from shlex import quote
import pytest
diff --git a/tests/unit/activation/test_csh.py b/tests/unit/activation/test_csh.py
index afdb08f..e76b97b 100644
--- a/tests/unit/activation/test_csh.py
+++ b/tests/unit/activation/test_csh.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from virtualenv.activation import CShellActivator
diff --git a/tests/unit/activation/test_fish.py b/tests/unit/activation/test_fish.py
index 18a6b3c..2a82059 100644
--- a/tests/unit/activation/test_fish.py
+++ b/tests/unit/activation/test_fish.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import pytest
from virtualenv.activation import FishActivator
diff --git a/tests/unit/activation/test_nushell.py b/tests/unit/activation/test_nushell.py
index 513ebba..e3bd5a3 100644
--- a/tests/unit/activation/test_nushell.py
+++ b/tests/unit/activation/test_nushell.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from shutil import which
from virtualenv.activation import NushellActivator
diff --git a/tests/unit/activation/test_powershell.py b/tests/unit/activation/test_powershell.py
index 761237f..887b766 100644
--- a/tests/unit/activation/test_powershell.py
+++ b/tests/unit/activation/test_powershell.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
from shlex import quote
diff --git a/tests/unit/activation/test_python_activator.py b/tests/unit/activation/test_python_activator.py
index cd8997e..ee0d1eb 100644
--- a/tests/unit/activation/test_python_activator.py
+++ b/tests/unit/activation/test_python_activator.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
import sys
from ast import literal_eval
diff --git a/tests/unit/config/cli/test_parser.py b/tests/unit/config/cli/test_parser.py
index a12fb3f..cb656c3 100644
--- a/tests/unit/config/cli/test_parser.py
+++ b/tests/unit/config/cli/test_parser.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from contextlib import contextmanager
diff --git a/tests/unit/config/test___main__.py b/tests/unit/config/test___main__.py
index 62228c9..76c9dfa 100644
--- a/tests/unit/config/test___main__.py
+++ b/tests/unit/config/test___main__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import re
import sys
from subprocess import PIPE, Popen, check_output
diff --git a/tests/unit/config/test_env_var.py b/tests/unit/config/test_env_var.py
index 2fe6ef4..b8eb656 100644
--- a/tests/unit/config/test_env_var.py
+++ b/tests/unit/config/test_env_var.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from pathlib import Path
diff --git a/tests/unit/config/test_ini.py b/tests/unit/config/test_ini.py
index c7a601e..e7fde82 100644
--- a/tests/unit/config/test_ini.py
+++ b/tests/unit/config/test_ini.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from textwrap import dedent
import pytest
diff --git a/tests/unit/create/conftest.py b/tests/unit/create/conftest.py
index 1e028fb..5bf764e 100644
--- a/tests/unit/create/conftest.py
+++ b/tests/unit/create/conftest.py
@@ -7,16 +7,14 @@ It's possible to use multiple types of host pythons to create virtual environmen
- invoking from our own venv
"""
-import subprocess
+from __future__ import annotations
+
import sys
-from pathlib import Path
from subprocess import Popen
import pytest
from virtualenv.discovery.py_info import PythonInfo
-from virtualenv.info import IS_WIN
-from virtualenv.run import cli_run
CURRENT = PythonInfo.current_system()
@@ -29,7 +27,7 @@ def root(tmp_path_factory, session_app_data): # noqa: U100
def venv(tmp_path_factory, session_app_data):
if CURRENT.is_venv:
return sys.executable
- elif CURRENT.version_info.major == 3:
+ else:
root_python = root(tmp_path_factory, session_app_data)
dest = tmp_path_factory.mktemp("venv")
process = Popen([str(root_python), "-m", "venv", "--without-pip", str(dest)])
@@ -40,56 +38,9 @@ def venv(tmp_path_factory, session_app_data):
return exe_path
-def old_virtualenv(tmp_path_factory, session_app_data):
- if CURRENT.is_old_virtualenv:
- return CURRENT.executable
- else:
- env_for_old_virtualenv = tmp_path_factory.mktemp("env-for-old-virtualenv")
- result = cli_run(["--no-download", "--activators", "", str(env_for_old_virtualenv), "--no-periodic-update"])
- # noinspection PyBroadException
- try:
- process = Popen(
- [
- str(result.creator.script("pip")),
- "install",
- "--no-index",
- "--disable-pip-version-check",
- str(Path(__file__).resolve().parent / "virtualenv-16.7.9-py2.py3-none-any.whl"),
- "-v",
- ],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
- _, __ = process.communicate()
- assert not process.returncode
- except Exception:
- return RuntimeError("failed to install old virtualenv")
- # noinspection PyBroadException
- try:
- old_virtualenv_at = tmp_path_factory.mktemp("old-virtualenv")
- cmd = [
- str(result.creator.script("virtualenv")),
- str(old_virtualenv_at),
- "--no-pip",
- "--no-setuptools",
- "--no-wheel",
- ]
- process = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- _, __ = process.communicate()
- assert not process.returncode
- if result.creator.interpreter.implementation == "PyPy" and IS_WIN:
- # old virtualenv creates pypy paths wrong on windows, so have to hardcode it
- return str(old_virtualenv_at / "bin" / "pypy.exe")
- exe_path = CURRENT.discover_exe(session_app_data, prefix=str(old_virtualenv_at)).original_executable
- return exe_path
- except Exception as exception:
- return RuntimeError(f"failed to create old virtualenv {exception}")
-
-
PYTHON = {
"root": root,
"venv": venv,
- "old_virtualenv": old_virtualenv,
}
diff --git a/tests/unit/create/console_app/demo/__init__.py b/tests/unit/create/console_app/demo/__init__.py
index a7e1f5a..f68e2c7 100644
--- a/tests/unit/create/console_app/demo/__init__.py
+++ b/tests/unit/create/console_app/demo/__init__.py
@@ -1,3 +1,6 @@
+from __future__ import annotations
+
+
def run():
print("magic")
diff --git a/tests/unit/create/console_app/demo/__main__.py b/tests/unit/create/console_app/demo/__main__.py
index a7e1f5a..f68e2c7 100644
--- a/tests/unit/create/console_app/demo/__main__.py
+++ b/tests/unit/create/console_app/demo/__main__.py
@@ -1,3 +1,6 @@
+from __future__ import annotations
+
+
def run():
print("magic")
diff --git a/tests/unit/create/console_app/setup.py b/tests/unit/create/console_app/setup.py
index 6068493..a03590f 100644
--- a/tests/unit/create/console_app/setup.py
+++ b/tests/unit/create/console_app/setup.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from setuptools import setup
setup()
diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py
index ea61ed0..1f3750f 100644
--- a/tests/unit/create/test_creator.py
+++ b/tests/unit/create/test_creator.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import ast
import difflib
import gc
@@ -22,9 +24,7 @@ import pytest
from virtualenv.__main__ import run, run_with_catch
from virtualenv.create.creator import DEBUG_SCRIPT, Creator, get_env_debug_info
from virtualenv.create.pyenv_cfg import PyEnvCfg
-from virtualenv.create.via_global_ref.builtin.cpython.cpython2 import CPython2PosixBase
from virtualenv.create.via_global_ref.builtin.cpython.cpython3 import CPython3Posix
-from virtualenv.create.via_global_ref.builtin.python2.python2 import Python2
from virtualenv.discovery.py_info import PythonInfo
from virtualenv.info import IS_PYPY, IS_WIN, fs_is_case_sensitive
from virtualenv.run import cli_run, session_via_cli
@@ -101,29 +101,11 @@ for k, v in CURRENT.creators().key_to_meta.items():
CREATE_METHODS.append((k, "copies"))
if v.can_symlink:
CREATE_METHODS.append((k, "symlinks"))
-_VENV_BUG_ON = (
- IS_PYPY
- and CURRENT.version_info[0:3] == (3, 6, 9)
- and CURRENT.pypy_version_info[0:2] == [7, 3, 0]
- and CURRENT.platform == "linux"
-)
@pytest.mark.parametrize(
("creator", "isolated"),
- [
- pytest.param(
- *i,
- marks=pytest.mark.xfail(
- reason="https://bitbucket.org/pypy/pypy/issues/3159/pypy36-730-venv-fails-with-copies-on-linux",
- strict=True,
- ),
- )
- if _VENV_BUG_ON and i[0][0] == "venv" and i[0][1] == "copies"
- else i
- for i in product(CREATE_METHODS, ["isolated", "global"])
- ],
- ids=lambda i: "-".join(i) if isinstance(i, tuple) else i,
+ [pytest.param(*i, id=f"{'-'.join(i[0])}-{i[1]}") for i in product(CREATE_METHODS, ["isolated", "global"])],
)
def test_create_no_seed(python, creator, isolated, system, coverage_env, special_name_dir):
dest = special_name_dir
@@ -226,10 +208,6 @@ def test_create_no_seed(python, creator, isolated, system, coverage_env, special
).strip()
assert result == "None"
- if isinstance(creator, CPython2PosixBase):
- make_file = debug["makefile_filename"]
- assert os.path.exists(make_file)
-
git_ignore = (dest / ".gitignore").read_text(encoding="utf-8")
assert git_ignore.splitlines() == ["# created by virtualenv automatically", "*"]
@@ -340,32 +318,6 @@ def test_home_path_is_exe_parent(tmp_path, creator):
assert any(os.path.exists(os.path.join(cfg["home"], exe)) for exe in exes)
-@pytest.mark.slow()
-@pytest.mark.usefixtures("current_fastest")
-def test_cross_major(cross_python, coverage_env, tmp_path, session_app_data):
- cmd = [
- "-p",
- cross_python.executable,
- str(tmp_path),
- "--no-setuptools",
- "--no-wheel",
- "--activators",
- "",
- ]
- result = cli_run(cmd)
- pip_scripts = {i.name.replace(".exe", "") for i in result.creator.script_dir.iterdir() if i.name.startswith("pip")}
- major, minor = cross_python.version_info[0:2]
- assert pip_scripts == {
- "pip",
- f"pip{major}",
- f"pip-{major}.{minor}",
- f"pip{major}.{minor}",
- }
- coverage_env()
- env = PythonInfo.from_exe(str(result.creator.exe), session_app_data)
- assert env.version_info.major != CURRENT.version_info.major
-
-
@pytest.mark.usefixtures("temp_app_data")
def test_create_parallel(tmp_path):
def create(count):
@@ -659,34 +611,3 @@ def test_python_path(monkeypatch, tmp_path, python_path_on):
assert non_python_path == [i for i in base if i not in extra_as_python_path]
else:
assert base == extra_all
-
-
-@pytest.mark.parametrize(
- ("py", "pyc"),
- product(
- [True, False] if Python2.from_stdlib(Python2.mappings(CURRENT), "os.py")[2] else [False],
- [True, False] if Python2.from_stdlib(Python2.mappings(CURRENT), "os.pyc")[2] else [False],
- ),
-)
-@pytest.mark.usefixtures("session_app_data")
-def test_py_pyc_missing(tmp_path, mocker, py, pyc):
- """Ensure that creation can succeed if os.pyc exists (even if os.py has been deleted)"""
- previous = Python2.from_stdlib
-
- def from_stdlib(mappings, name):
- path, to, exists = previous(mappings, name)
- if name.endswith("py"):
- exists = py
- elif name.endswith("pyc"):
- exists = pyc
- return path, to, exists
-
- mocker.patch.object(Python2, "from_stdlib", side_effect=from_stdlib)
-
- result = cli_run([str(tmp_path), "--without-pip", "--activators", "", "-vv", "-p", "2"])
- py_at = Python2.from_stdlib(Python2.mappings(CURRENT), "os.py")[1](result.creator, Path("os.py"))
- py = pyc is False or py # if pyc is False we fallback to serve the py, which will exist (as we only mock the check)
- assert py_at.exists() is py
-
- pyc_at = Python2.from_stdlib(Python2.mappings(CURRENT), "osc.py")[1](result.creator, Path("os.pyc"))
- assert pyc_at.exists() is pyc
diff --git a/tests/unit/create/test_interpreters.py b/tests/unit/create/test_interpreters.py
index 5d36b23..b6b58df 100644
--- a/tests/unit/create/test_interpreters.py
+++ b/tests/unit/create/test_interpreters.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
from uuid import uuid4
diff --git a/tests/unit/create/via_global_ref/builtin/conftest.py b/tests/unit/create/via_global_ref/builtin/conftest.py
index 7119fbe..bb505db 100644
--- a/tests/unit/create/via_global_ref/builtin/conftest.py
+++ b/tests/unit/create/via_global_ref/builtin/conftest.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
from pathlib import Path
diff --git a/tests/unit/create/via_global_ref/builtin/cpython/test_cpython3_win.py b/tests/unit/create/via_global_ref/builtin/cpython/test_cpython3_win.py
index 90fdb38..f831de1 100644
--- a/tests/unit/create/via_global_ref/builtin/cpython/test_cpython3_win.py
+++ b/tests/unit/create/via_global_ref/builtin/cpython/test_cpython3_win.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import pytest
from testing.helpers import contains_exe, contains_ref
from testing.path import join as path
diff --git a/tests/unit/create/via_global_ref/builtin/pypy/test_pypy3.py b/tests/unit/create/via_global_ref/builtin/pypy/test_pypy3.py
index 4903801..3ae905f 100644
--- a/tests/unit/create/via_global_ref/builtin/pypy/test_pypy3.py
+++ b/tests/unit/create/via_global_ref/builtin/pypy/test_pypy3.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import pytest
from testing.helpers import contains_exe, contains_ref
from testing.path import join as path
diff --git a/tests/unit/create/via_global_ref/builtin/testing/helpers.py b/tests/unit/create/via_global_ref/builtin/testing/helpers.py
index 5ae1df8..e55c8d0 100644
--- a/tests/unit/create/via_global_ref/builtin/testing/helpers.py
+++ b/tests/unit/create/via_global_ref/builtin/testing/helpers.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from functools import reduce
from pathlib import Path
diff --git a/tests/unit/create/via_global_ref/builtin/testing/path.py b/tests/unit/create/via_global_ref/builtin/testing/path.py
index b2e1b85..96c5e3b 100644
--- a/tests/unit/create/via_global_ref/builtin/testing/path.py
+++ b/tests/unit/create/via_global_ref/builtin/testing/path.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABCMeta, abstractmethod
from itertools import chain
from operator import attrgetter as attr
diff --git a/tests/unit/create/via_global_ref/builtin/testing/py_info.py b/tests/unit/create/via_global_ref/builtin/testing/py_info.py
index d7909b2..f43b45d 100644
--- a/tests/unit/create/via_global_ref/builtin/testing/py_info.py
+++ b/tests/unit/create/via_global_ref/builtin/testing/py_info.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from pathlib import Path
from virtualenv.discovery.py_info import PythonInfo
diff --git a/tests/unit/create/via_global_ref/greet/setup.py b/tests/unit/create/via_global_ref/greet/setup.py
index 7206137..2965915 100644
--- a/tests/unit/create/via_global_ref/greet/setup.py
+++ b/tests/unit/create/via_global_ref/greet/setup.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
from setuptools import Extension, setup
diff --git a/tests/unit/create/via_global_ref/test_api.py b/tests/unit/create/via_global_ref/test_api.py
index ade64d4..a863b0e 100644
--- a/tests/unit/create/via_global_ref/test_api.py
+++ b/tests/unit/create/via_global_ref/test_api.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from virtualenv.create.via_global_ref import api
diff --git a/tests/unit/create/via_global_ref/test_build_c_ext.py b/tests/unit/create/via_global_ref/test_build_c_ext.py
index 0de14d5..a2442d1 100644
--- a/tests/unit/create/via_global_ref/test_build_c_ext.py
+++ b/tests/unit/create/via_global_ref/test_build_c_ext.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
import shutil
import subprocess
diff --git a/tests/unit/discovery/py_info/test_py_info.py b/tests/unit/discovery/py_info/test_py_info.py
index 24b129c..639fbaa 100644
--- a/tests/unit/discovery/py_info/test_py_info.py
+++ b/tests/unit/discovery/py_info/test_py_info.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import copy
import functools
import itertools
@@ -343,9 +345,6 @@ def test_custom_venv_install_scheme_is_prefered(mocker):
# define the prefix as sysconfig.get_preferred_scheme did before 3.11
sysconfig_install_schemes["nt" if os.name == "nt" else "posix_prefix"] = default_scheme
- if sys.version_info[0] == 2:
- sysconfig_install_schemes = _stringify_schemes_dict(sysconfig_install_schemes)
-
# On Python < 3.10, the distutils schemes are not derived from sysconfig schemes
# So we mock them as well to assert the custom "venv" install scheme has priority
distutils_scheme = {
@@ -360,9 +359,6 @@ def test_custom_venv_install_scheme_is_prefered(mocker):
"nt": distutils_scheme,
}
- if sys.version_info[0] == 2:
- distutils_schemes = _stringify_schemes_dict(distutils_schemes)
-
# We need to mock distutils first, so they don't see the mocked sysconfig,
# if imported for the first time.
# That can happen if the actual interpreter has the "venv" INSTALL_SCHEME
diff --git a/tests/unit/discovery/py_info/test_py_info_exe_based_of.py b/tests/unit/discovery/py_info/test_py_info_exe_based_of.py
index 2b025eb..562424e 100644
--- a/tests/unit/discovery/py_info/test_py_info_exe_based_of.py
+++ b/tests/unit/discovery/py_info/test_py_info_exe_based_of.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
from pathlib import Path
diff --git a/tests/unit/discovery/test_discovery.py b/tests/unit/discovery/test_discovery.py
index c4a2cc7..b8c820a 100644
--- a/tests/unit/discovery/test_discovery.py
+++ b/tests/unit/discovery/test_discovery.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
import sys
diff --git a/tests/unit/discovery/test_py_spec.py b/tests/unit/discovery/test_py_spec.py
index 641429e..7656866 100644
--- a/tests/unit/discovery/test_py_spec.py
+++ b/tests/unit/discovery/test_py_spec.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
from copy import copy
diff --git a/tests/unit/discovery/windows/conftest.py b/tests/unit/discovery/windows/conftest.py
index 58da626..21ed61b 100644
--- a/tests/unit/discovery/windows/conftest.py
+++ b/tests/unit/discovery/windows/conftest.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from contextlib import contextmanager
from pathlib import Path
diff --git a/tests/unit/discovery/windows/test_windows.py b/tests/unit/discovery/windows/test_windows.py
index 65ff9ca..38dd546 100644
--- a/tests/unit/discovery/windows/test_windows.py
+++ b/tests/unit/discovery/windows/test_windows.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
import pytest
diff --git a/tests/unit/discovery/windows/test_windows_pep514.py b/tests/unit/discovery/windows/test_windows_pep514.py
index c02db38..0b392d6 100644
--- a/tests/unit/discovery/windows/test_windows_pep514.py
+++ b/tests/unit/discovery/windows/test_windows_pep514.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import sys
import textwrap
diff --git a/tests/unit/discovery/windows/winreg-mock-values.py b/tests/unit/discovery/windows/winreg-mock-values.py
index 11ec0b4..da76c56 100644
--- a/tests/unit/discovery/windows/winreg-mock-values.py
+++ b/tests/unit/discovery/windows/winreg-mock-values.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import winreg
hive_open = {
diff --git a/tests/unit/seed/embed/test_base_embed.py b/tests/unit/seed/embed/test_base_embed.py
index 3344c74..e9d61f3 100644
--- a/tests/unit/seed/embed/test_base_embed.py
+++ b/tests/unit/seed/embed/test_base_embed.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import pytest
from virtualenv.run import session_via_cli
diff --git a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py
index 2c8c3e8..610aaa2 100644
--- a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py
+++ b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import contextlib
import os
import sys
@@ -113,9 +115,6 @@ def test_seed_link_via_app_data(tmp_path, coverage_env, current_fastest, copies)
post_run = set(site_package.iterdir()) - patch_files
assert not post_run, "\n".join(str(i) for i in post_run)
- if sys.version_info[0:2] == (3, 4) and os.environ.get("PIP_REQ_TRACKER"):
- os.environ.pop("PIP_REQ_TRACKER")
-
@contextlib.contextmanager
def read_only_dir(d):
diff --git a/tests/unit/seed/embed/test_pip_invoke.py b/tests/unit/seed/embed/test_pip_invoke.py
index f045886..9deda26 100644
--- a/tests/unit/seed/embed/test_pip_invoke.py
+++ b/tests/unit/seed/embed/test_pip_invoke.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import itertools
import sys
from shutil import copy2
@@ -23,7 +25,7 @@ def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, mocker, current_f
def _load_embed_wheel(app_data, distribution, for_py_version, version): # noqa: U100
return load_embed_wheel(app_data, distribution, old_ver, version)
- old_ver = "2.7"
+ old_ver = "3.7"
old = BUNDLE_SUPPORT[old_ver]
mocker.patch("virtualenv.seed.wheels.bundle.load_embed_wheel", side_effect=_load_embed_wheel)
diff --git a/tests/unit/seed/wheels/test_acquire.py b/tests/unit/seed/wheels/test_acquire.py
index d028239..7f88f6a 100644
--- a/tests/unit/seed/wheels/test_acquire.py
+++ b/tests/unit/seed/wheels/test_acquire.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
import sys
from datetime import datetime
diff --git a/tests/unit/seed/wheels/test_acquire_find_wheel.py b/tests/unit/seed/wheels/test_acquire_find_wheel.py
index 6ca1f22..7822849 100644
--- a/tests/unit/seed/wheels/test_acquire_find_wheel.py
+++ b/tests/unit/seed/wheels/test_acquire_find_wheel.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import pytest
from virtualenv.seed.wheels.acquire import find_compatible_in_house
@@ -22,13 +24,6 @@ def test_find_exact(for_py_version):
assert result.path == expected.path
-def test_find_less_than():
- latest = get_embed_wheel("setuptools", MAX)
- result = find_compatible_in_house("setuptools", f"<{latest.version}", MAX, BUNDLE_FOLDER)
- assert result is not None
- assert result.path != latest.path
-
-
def test_find_bad_spec():
with pytest.raises(ValueError, match="bad"):
find_compatible_in_house("setuptools", "bad", MAX, BUNDLE_FOLDER)
diff --git a/tests/unit/seed/wheels/test_bundle.py b/tests/unit/seed/wheels/test_bundle.py
index 38be96c..fbd34f9 100644
--- a/tests/unit/seed/wheels/test_bundle.py
+++ b/tests/unit/seed/wheels/test_bundle.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
from datetime import datetime
from pathlib import Path
diff --git a/tests/unit/seed/wheels/test_periodic_update.py b/tests/unit/seed/wheels/test_periodic_update.py
index e7794f5..82c86e3 100644
--- a/tests/unit/seed/wheels/test_periodic_update.py
+++ b/tests/unit/seed/wheels/test_periodic_update.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import json
import os
import subprocess
diff --git a/tests/unit/seed/wheels/test_wheels_util.py b/tests/unit/seed/wheels/test_wheels_util.py
index 7c3c4a9..00afa04 100644
--- a/tests/unit/seed/wheels/test_wheels_util.py
+++ b/tests/unit/seed/wheels/test_wheels_util.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import pytest
from virtualenv.seed.wheels.embed import MAX, get_embed_wheel
diff --git a/tests/unit/test_run.py b/tests/unit/test_run.py
index 41223e2..a048e60 100644
--- a/tests/unit/test_run.py
+++ b/tests/unit/test_run.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import pytest
diff --git a/tests/unit/test_util.py b/tests/unit/test_util.py
index 81f8ff7..1959c5f 100644
--- a/tests/unit/test_util.py
+++ b/tests/unit/test_util.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import concurrent.futures
import traceback