diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index e6a272e97..e45a4e4eb 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -34,7 +34,6 @@ jobs: - pypy2 include: - { os: macos-latest, py: brew@py3 } - - { os: "ubuntu-18.04", py: 3.4.10 } steps: - name: Install OS dependencies run: | diff --git a/docs/changelog/2141.removal.rst b/docs/changelog/2141.removal.rst new file mode 100644 index 000000000..900864276 --- /dev/null +++ b/docs/changelog/2141.removal.rst @@ -0,0 +1 @@ +Drop python ``3.4`` support as it has been over 2 years since EOL - by :user:`gaborbernat`. diff --git a/docs/installation.rst b/docs/installation.rst index d3c44eba2..19a37dfe8 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -88,8 +88,8 @@ Python and OS Compatibility virtualenv works with the following Python interpreter implementations: -- `CPython `_ versions 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9 -- `PyPy `_ 2.7 and 3.4+. +- `CPython `_ versions 2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10 +- `PyPy `_ 2.7 and 3.5+. This means virtualenv works on the latest patch version of each of these minor versions. Previous patch versions are supported on a best effort approach. diff --git a/docs/user_guide.rst b/docs/user_guide.rst index ca33617b8..bb8ae48f0 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -106,7 +106,7 @@ at the moment has two types of virtual environments: - ``venv`` - this delegates the creation process towards the ``venv`` module, as described in `PEP 405 `_. This is only available on Python interpreters having version - ``3.4`` or later, and also has the downside that virtualenv **must** create a process to invoke that module (unless + ``3.5`` or later, and also has the downside that virtualenv **must** create a process to invoke that module (unless virtualenv is installed in the system python), which can be an expensive operation (especially true on Windows). - ``builtin`` - this means ``virtualenv`` is able to do the creation operation itself (by knowing exactly what files to diff --git a/setup.cfg b/setup.cfg index 5b845d565..4144e8ce3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,7 +21,6 @@ classifiers = Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 @@ -48,7 +47,7 @@ install_requires = importlib-metadata>=0.12;python_version<"3.8" importlib-resources>=1.0;python_version<"3.7" pathlib2>=2.3.3,<3;python_version < '3.4' and sys.platform != 'win32' -python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* package_dir = =src zip_safe = True diff --git a/src/virtualenv/discovery/cached_py_info.py b/src/virtualenv/discovery/cached_py_info.py index d16a8e298..31beff52f 100644 --- a/src/virtualenv/discovery/cached_py_info.py +++ b/src/virtualenv/discovery/cached_py_info.py @@ -37,7 +37,7 @@ def from_exe(cls, app_data, exe, env=None, raise_on_error=True, ignore_cache=Fal def _get_from_cache(cls, app_data, exe, env, ignore_cache=True): # note here we cannot resolve symlinks, as the symlink may trigger different prefix information if there's a - # pyenv.cfg somewhere alongside on python3.4+ + # pyenv.cfg somewhere alongside on python3.5+ exe_path = Path(exe) if not ignore_cache and exe_path in _CACHE: # check in the in-memory cache result = _CACHE[exe_path] diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py index 10615ea6c..f47c962c0 100644 --- a/src/virtualenv/seed/wheels/embed/__init__.py +++ b/src/virtualenv/seed/wheels/embed/__init__.py @@ -35,11 +35,6 @@ "setuptools": "setuptools-50.3.2-py3-none-any.whl", "wheel": "wheel-0.36.2-py2.py3-none-any.whl", }, - "3.4": { - "pip": "pip-19.1.1-py2.py3-none-any.whl", - "setuptools": "setuptools-43.0.0-py2.py3-none-any.whl", - "wheel": "wheel-0.33.6-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", diff --git a/src/virtualenv/seed/wheels/embed/pip-19.1.1-py2.py3-none-any.whl b/src/virtualenv/seed/wheels/embed/pip-19.1.1-py2.py3-none-any.whl deleted file mode 100644 index 8476c1193..000000000 Binary files a/src/virtualenv/seed/wheels/embed/pip-19.1.1-py2.py3-none-any.whl and /dev/null differ diff --git a/src/virtualenv/seed/wheels/embed/setuptools-43.0.0-py2.py3-none-any.whl b/src/virtualenv/seed/wheels/embed/setuptools-43.0.0-py2.py3-none-any.whl deleted file mode 100644 index 733faa6a5..000000000 Binary files a/src/virtualenv/seed/wheels/embed/setuptools-43.0.0-py2.py3-none-any.whl and /dev/null differ diff --git a/src/virtualenv/seed/wheels/embed/wheel-0.33.6-py2.py3-none-any.whl b/src/virtualenv/seed/wheels/embed/wheel-0.33.6-py2.py3-none-any.whl deleted file mode 100644 index 2a71896be..000000000 Binary files a/src/virtualenv/seed/wheels/embed/wheel-0.33.6-py2.py3-none-any.whl and /dev/null differ diff --git a/src/virtualenv/util/path/_pathlib/__init__.py b/src/virtualenv/util/path/_pathlib/__init__.py index 6bb045c2d..746c8aed2 100644 --- a/src/virtualenv/util/path/_pathlib/__init__.py +++ b/src/virtualenv/util/path/_pathlib/__init__.py @@ -6,52 +6,6 @@ if six.PY3: from pathlib import Path - - if sys.version_info[0:2] == (3, 4): - # no read/write text on python3.4 - BuiltinPath = Path - - class Path(type(BuiltinPath())): - def read_text(self, encoding=None, errors=None): - """ - Open the file in text mode, read it, and close the file. - """ - with self.open(mode="r", encoding=encoding, errors=errors) as f: - return f.read() - - def read_bytes(self): - """ - Open the file in bytes mode, read it, and close the file. - """ - with self.open(mode="rb") as f: - return f.read() - - def write_text(self, data, encoding=None, errors=None): - """ - Open the file in text mode, write to it, and close the file. - """ - if not isinstance(data, str): - raise TypeError("data must be str, not %s" % data.__class__.__name__) - with self.open(mode="w", encoding=encoding, errors=errors) as f: - return f.write(data) - - def write_bytes(self, data): - """ - Open the file in bytes mode, write to it, and close the file. - """ - # type-check for the buffer interface before truncating the file - view = memoryview(data) - with self.open(mode="wb") as f: - return f.write(view) - - def mkdir(self, mode=0o777, parents=False, exist_ok=False): - try: - super(type(BuiltinPath()), self).mkdir(mode, parents) - except FileExistsError as exception: - if not exist_ok: - raise exception - - else: if sys.platform == "win32": # workaround for https://github.com/mcmtroffaes/pathlib2/issues/56 diff --git a/tasks/make_zipapp.py b/tasks/make_zipapp.py index 7eceb50c1..aa6f62509 100644 --- a/tasks/make_zipapp.py +++ b/tasks/make_zipapp.py @@ -20,7 +20,7 @@ HERE = Path(__file__).parent.absolute() -VERSIONS = ["3.{}".format(i) for i in range(9, 3, -1)] + ["2.7"] +VERSIONS = ["3.{}".format(i) for i in range(10, 4, -1)] + ["2.7"] def main(): diff --git a/tasks/upgrade_wheels.py b/tasks/upgrade_wheels.py index fe0010ab8..78e5ffe28 100644 --- a/tasks/upgrade_wheels.py +++ b/tasks/upgrade_wheels.py @@ -16,7 +16,7 @@ STRICT = "UPGRADE_ADVISORY" not in os.environ BUNDLED = ["pip", "setuptools", "wheel"] -SUPPORT = list(reversed([(2, 7)] + [(3, i) for i in range(4, 11)])) +SUPPORT = list(reversed([(2, 7)] + [(3, i) for i in range(5, 11)])) DEST = Path(__file__).resolve().parents[1] / "src" / "virtualenv" / "seed" / "wheels" / "embed" diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py index e51833fc8..424a9b385 100644 --- a/tests/unit/create/test_creator.py +++ b/tests/unit/create/test_creator.py @@ -129,8 +129,6 @@ def system(session_app_data): ids=lambda i: "-".join(i) if isinstance(i, tuple) else i, ) def test_create_no_seed(python, creator, isolated, system, coverage_env, special_name_dir): - if creator[0] == "venv" and sys.version_info[0:2] == (3, 4): # venv on python3.4 only supports ascii chars - special_name_dir = special_name_dir.with_name(special_name_dir.name.encode("ascii", errors="ignore").decode()) dest = special_name_dir creator_key, method = creator cmd = [ diff --git a/tests/unit/seed/embed/test_pip_invoke.py b/tests/unit/seed/embed/test_pip_invoke.py index c033aa19d..f2e7a33ef 100644 --- a/tests/unit/seed/embed/test_pip_invoke.py +++ b/tests/unit/seed/embed/test_pip_invoke.py @@ -25,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): return load_embed_wheel(app_data, distribution, old_ver, version) - old_ver = "3.4" + old_ver = "2.7" old = BUNDLE_SUPPORT[old_ver] mocker.patch("virtualenv.seed.wheels.bundle.load_embed_wheel", side_effect=_load_embed_wheel) @@ -36,7 +36,9 @@ def _execute(cmd, env): continue if with_version == "embed": expected.add(BUNDLE_FOLDER) - elif old[dist] != new[dist]: + elif old[distribution] == new[distribution]: + expected.add(BUNDLE_FOLDER) + else: expected.add(extra_search_dir) expected_list = list( itertools.chain.from_iterable(["--find-links", str(e)] for e in sorted(expected, key=lambda x: str(x))), diff --git a/tests/unit/seed/wheels/test_periodic_update.py b/tests/unit/seed/wheels/test_periodic_update.py index 2ea473277..f308aee17 100644 --- a/tests/unit/seed/wheels/test_periodic_update.py +++ b/tests/unit/seed/wheels/test_periodic_update.py @@ -67,7 +67,7 @@ def _do_update(distribution, for_py_version, embed_filename, app_data, search_di def test_pick_periodic_update(tmp_path, session_app_data, mocker, for_py_version): - embed, current = get_embed_wheel("setuptools", "3.4"), get_embed_wheel("setuptools", for_py_version) + embed, current = get_embed_wheel("setuptools", "3.5"), get_embed_wheel("setuptools", for_py_version) mocker.patch("virtualenv.seed.wheels.bundle.load_embed_wheel", return_value=embed) completed = datetime.now() - timedelta(days=29) u_log = UpdateLog( diff --git a/tox.ini b/tox.ini index f7cbd3869..e50a0d232 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,6 @@ envlist = py37 py36 py35 - py34 py27 pypy3 pypy2 @@ -30,21 +29,22 @@ setenv = COVERAGE_PROCESS_START = {toxinidir}/.coveragerc PYTHONIOENCODING = utf-8 _COVERAGE_SRC = {envsitepackagesdir}/virtualenv - {py34,py27,pypy2, upgrade}: PYTHONWARNINGS = ignore:DEPRECATION::pip._internal.cli.base_command + {py27,pypy2, upgrade}: PYTHONWARNINGS = ignore:DEPRECATION::pip._internal.cli.base_command extras = testing commands = python -m coverage erase - python -m coverage run -m pytest \ + python -m coverage run -m pytest {tty:--color=yes} \ --junitxml {toxworkdir}/junit.{envname}.xml \ {posargs:tests --int --timeout 600} python -m coverage combine python -m coverage report --skip-covered --show-missing python -m coverage xml -o {toxworkdir}/coverage.{envname}.xml - python -m coverage html -d {envtmpdir}/htmlcov \ - !py34: --show-contexts \ + python -m coverage html -d {envtmpdir}/htmlcov --show-contexts \ --title virtualenv-{envname}-coverage install_command = python -m pip install {opts} {packages} --disable-pip-version-check +package = wheel +wheel_build_env = .pkg [testenv:fix_lint] description = format the code base to adhere to our styles, and complain about what we cannot do automatically @@ -83,7 +83,6 @@ depends = py37 py36 py35 - py34 py27 pypy pypy3