Drop support for soon-EOL Python 3.6

This commit is contained in:
Hugo van Kemenade 2021-11-07 13:41:02 +02:00
parent d81c65ace1
commit 0252c04a16
12 changed files with 40 additions and 228 deletions

View File

@ -102,11 +102,10 @@ jobs:
matrix:
os: [Ubuntu, MacOS]
python:
- 3.6
- 3.7
- 3.8
- 3.9
- "3.10.0-alpha - 3.10"
- "3.10"
steps:
- uses: actions/checkout@v2
@ -151,12 +150,11 @@ jobs:
matrix:
os: [Windows]
python:
- 3.6
- 3.7
# Commented out, since Windows tests are expensively slow.
# - 3.7
# - 3.8
- 3.9
- "3.10.0-alpha - 3.10"
- "3.10"
group: [1, 2]
steps:

View File

@ -18,17 +18,17 @@ Supported interpreters
pip support a variety of Python interpreters:
- CPython 3.6
- CPython 3.7
- CPython 3.8
- CPython 3.9
- CPython 3.10
- Latest PyPy3
on different operating systems:
- Linux
- Windows
- MacOS
- macOS
and on different architectures:
@ -77,9 +77,9 @@ Developer tasks
======== =============== ================ ================== =============
OS docs lint vendoring packaging
======== =============== ================ ================== =============
Linux Github Github Github Github
Windows Github Github Github Github
MacOS Github Github Github Github
Linux GitHub GitHub GitHub GitHub
Windows GitHub GitHub GitHub GitHub
macOS GitHub GitHub GitHub GitHub
======== =============== ================ ================== =============
Actual testing
@ -88,28 +88,26 @@ Actual testing
+------------------------------+---------------+-----------------+
| **interpreter** | **unit** | **integration** |
+-----------+----------+-------+---------------+-----------------+
| | | CP3.6 | | |
| | +-------+---------------+-----------------+
| | x86 | CP3.7 | | |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | +-------+---------------+-----------------+
| | | CP3.10| | |
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| Windows +----------+-------+---------------+-----------------+
| | | CP3.6 | Github | Github |
| | +-------+---------------+-----------------+
| | x64 | CP3.7 | | |
| | x64 | CP3.7 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | Github | Github |
| | | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.10| GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
+-----------+----------+-------+---------------+-----------------+
| | | CP3.6 | | |
| | +-------+---------------+-----------------+
| | x86 | CP3.7 | | |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
@ -118,33 +116,33 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| Linux +----------+-------+---------------+-----------------+
| | | CP3.6 | Github | Github |
| | x64 | CP3.7 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | x64 | CP3.7 | Github | Github |
| | | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.8 | Github | Github |
| | | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | Github | Github |
| | | CP3.10| GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
+-----------+----------+-------+---------------+-----------------+
| | | CP3.6 | | |
| | +-------+---------------+-----------------+
| | x86 | CP3.7 | | |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | +-------+---------------+-----------------+
| | | CP3.10| | |
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| MacOS +----------+-------+---------------+-----------------+
| | | CP3.6 | Github | Github |
| macOS +----------+-------+---------------+-----------------+
| | x64 | CP3.7 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | x64 | CP3.7 | Github | Github |
| | | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.8 | Github | Github |
| | | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | Github | Github |
| | | CP3.10| GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
+-----------+----------+-------+---------------+-----------------+

View File

@ -70,15 +70,15 @@ To run tests:
.. code-block:: console
$ tox -e py36 -- -n auto
$ tox -e py310 -- -n auto
To run tests without parallelization, run:
.. code-block:: console
$ tox -e py36
$ tox -e py310
The example above runs tests against Python 3.6. You can also use other
The example above runs tests against Python 3.10. You can also use other
versions like ``py39`` and ``pypy3``.
``tox`` has been configured to forward any additional arguments it is given to
@ -88,11 +88,11 @@ can select tests using the various ways that pytest provides:
.. code-block:: console
$ # Using file name
$ tox -e py36 -- tests/functional/test_install.py
$ tox -e py310 -- tests/functional/test_install.py
$ # Using markers
$ tox -e py36 -- -m unit
$ tox -e py310 -- -m unit
$ # Using keywords
$ tox -e py36 -- -k "install and not wheel"
$ tox -e py310 -- -k "install and not wheel"
Running pip's entire test suite requires supported version control tools
(subversion, bazaar, git, and mercurial) to be installed. If you are missing
@ -101,8 +101,8 @@ explicitly tell pytest to skip those tests:
.. code-block:: console
$ tox -e py36 -- -k "not svn"
$ tox -e py36 -- -k "not (svn or git)"
$ tox -e py310 -- -k "not svn"
$ tox -e py310 -- -k "not (svn or git)"
Running Linters

View File

@ -75,7 +75,7 @@ $ pip install --upgrade pip
The current version of pip works on:
- Windows, Linux and MacOS.
- CPython 3.6, 3.7, 3.8, 3.9, 3.10 and latest PyPy3.
- CPython 3.7, 3.8, 3.9, 3.10 and latest PyPy3.
pip is tested to work on the latest patch version of the Python interpreter,
for each of the minor versions listed above. Previous patch versions are

1
news/10641.removal.rst Normal file
View File

@ -0,0 +1 @@
Drop support for Python 3.6.

View File

@ -69,7 +69,7 @@ def should_update_common_wheels() -> bool:
# completely to nox for all our automation. Contributors should prefer using
# `tox -e ...` until this note is removed.
# -----------------------------------------------------------------------------
@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "pypy3"])
@nox.session(python=["3.7", "3.8", "3.9", "3.10", "pypy3"])
def test(session: nox.Session) -> None:
# Get the common wheels.
if should_update_common_wheels():

View File

@ -37,7 +37,6 @@ setup(
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
@ -81,5 +80,5 @@ setup(
],
},
zip_safe=False,
python_requires=">=3.6",
python_requires=">=3.7",
)

View File

@ -197,14 +197,7 @@ class BuildEnvironment:
if not requirements:
return
with contextlib.ExitStack() as ctx:
# TODO: Remove this block when dropping 3.6 support. Python 3.6
# lacks importlib.resources and pep517 has issues loading files in
# a zip, so we fallback to the "old" method by adding the current
# pip directory to the child process's sys.path.
if sys.version_info < (3, 7):
pip_runnable = os.path.dirname(pip_location)
else:
pip_runnable = ctx.enter_context(_create_standalone_pip())
pip_runnable = ctx.enter_context(_create_standalone_pip())
self._install_requirements(
pip_runnable,
finder,

View File

@ -16,7 +16,6 @@ from pip._internal.models.selection_prefs import SelectionPreferences
from pip._internal.network.session import PipSession
from pip._internal.utils.compat import stdlib_pkgs
from pip._internal.utils.misc import tabulate, write_output
from pip._internal.utils.parallel import map_multithread
if TYPE_CHECKING:
from pip._internal.metadata.base import DistributionVersion
@ -254,7 +253,7 @@ class ListCommand(IndexGroupCommand):
dist.latest_filetype = typ
return dist
for dist in map_multithread(latest_info, packages):
for dist in map(latest_info, packages):
if dist is not None:
yield dist

View File

@ -1,103 +0,0 @@
"""Convenient parallelization of higher order functions.
This module provides two helper functions, with appropriate fallbacks on
Python 2 and on systems lacking support for synchronization mechanisms:
- map_multiprocess
- map_multithread
These helpers work like Python 3's map, with two differences:
- They don't guarantee the order of processing of
the elements of the iterable.
- The underlying process/thread pools chop the iterable into
a number of chunks, so that for very long iterables using
a large value for chunksize can make the job complete much faster
than using the default value of 1.
"""
__all__ = ["map_multiprocess", "map_multithread"]
from contextlib import contextmanager
from multiprocessing import Pool as ProcessPool
from multiprocessing import pool
from multiprocessing.dummy import Pool as ThreadPool
from typing import Callable, Iterable, Iterator, TypeVar, Union
from pip._vendor.requests.adapters import DEFAULT_POOLSIZE
Pool = Union[pool.Pool, pool.ThreadPool]
S = TypeVar("S")
T = TypeVar("T")
# On platforms without sem_open, multiprocessing[.dummy] Pool
# cannot be created.
try:
import multiprocessing.synchronize # noqa
except ImportError:
LACK_SEM_OPEN = True
else:
LACK_SEM_OPEN = False
# Incredibly large timeout to work around bpo-8296 on Python 2.
TIMEOUT = 2000000
@contextmanager
def closing(pool: Pool) -> Iterator[Pool]:
"""Return a context manager making sure the pool closes properly."""
try:
yield pool
finally:
# For Pool.imap*, close and join are needed
# for the returned iterator to begin yielding.
pool.close()
pool.join()
pool.terminate()
def _map_fallback(
func: Callable[[S], T], iterable: Iterable[S], chunksize: int = 1
) -> Iterator[T]:
"""Make an iterator applying func to each element in iterable.
This function is the sequential fallback either on Python 2
where Pool.imap* doesn't react to KeyboardInterrupt
or when sem_open is unavailable.
"""
return map(func, iterable)
def _map_multiprocess(
func: Callable[[S], T], iterable: Iterable[S], chunksize: int = 1
) -> Iterator[T]:
"""Chop iterable into chunks and submit them to a process pool.
For very long iterables using a large value for chunksize can make
the job complete much faster than using the default value of 1.
Return an unordered iterator of the results.
"""
with closing(ProcessPool()) as pool:
return pool.imap_unordered(func, iterable, chunksize)
def _map_multithread(
func: Callable[[S], T], iterable: Iterable[S], chunksize: int = 1
) -> Iterator[T]:
"""Chop iterable into chunks and submit them to a thread pool.
For very long iterables using a large value for chunksize can make
the job complete much faster than using the default value of 1.
Return an unordered iterator of the results.
"""
with closing(ThreadPool(DEFAULT_POOLSIZE)) as pool:
return pool.imap_unordered(func, iterable, chunksize)
if LACK_SEM_OPEN:
map_multiprocess = map_multithread = _map_fallback
else:
map_multiprocess = _map_multiprocess
map_multithread = _map_multithread

View File

@ -1,73 +0,0 @@
"""Test multiprocessing/multithreading higher-order functions."""
from contextlib import contextmanager
from importlib import import_module
from math import factorial
from sys import modules
from typing import Any, Iterator
import pytest
DUNDER_IMPORT = "builtins.__import__"
FUNC, ITERABLE = factorial, range(42)
MAPS = "map_multiprocess", "map_multithread"
_import = __import__
def unload_parallel() -> None:
try:
del modules["pip._internal.utils.parallel"]
except KeyError:
pass
@contextmanager
def tmp_import_parallel() -> Iterator[Any]:
unload_parallel()
try:
yield import_module("pip._internal.utils.parallel")
finally:
unload_parallel()
def lack_sem_open(name: str, *args: Any, **kwargs: Any) -> Any:
"""Raise ImportError on import of multiprocessing.synchronize."""
if name.endswith("synchronize"):
raise ImportError
return _import(name, *args, **kwargs)
def have_sem_open(name: str, *args: Any, **kwargs: Any) -> Any:
"""Make sure multiprocessing.synchronize import is successful."""
# We don't care about the return value
# since we don't use the pool with this import.
if name.endswith("synchronize"):
return None
return _import(name, *args, **kwargs)
@pytest.mark.parametrize("name", MAPS)
def test_lack_sem_open(name: str, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test fallback when sem_open is not available.
If so, multiprocessing[.dummy].Pool will fail to be created and
map_async should fallback to map.
"""
monkeypatch.setattr(DUNDER_IMPORT, lack_sem_open)
with tmp_import_parallel() as parallel:
assert getattr(parallel, name) is parallel._map_fallback
@pytest.mark.parametrize("name", MAPS)
def test_have_sem_open(name: str, monkeypatch: pytest.MonkeyPatch) -> None:
"""Test fallback when sem_open is available."""
monkeypatch.setattr(DUNDER_IMPORT, have_sem_open)
with tmp_import_parallel() as parallel:
assert getattr(parallel, name) is getattr(parallel, f"_{name}")
@pytest.mark.parametrize("name", MAPS)
def test_map(name: str) -> None:
"""Test correctness of result of asynchronous maps."""
map_async = getattr(import_module("pip._internal.utils.parallel"), name)
assert set(map_async(FUNC, ITERABLE)) == set(map(FUNC, ITERABLE))

View File

@ -2,7 +2,7 @@
minversion = 3.4.0
envlist =
docs, packaging, lint, vendoring,
py36, py37, py38, py39, py310, pypy3
py37, py38, py39, py310, pypy3
[helpers]
# Wrapper for calls to pip that make sure the version being used is the