mirror of https://github.com/pypa/pip
Drop support for soon-EOL Python 3.6
This commit is contained in:
parent
d81c65ace1
commit
0252c04a16
|
@ -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:
|
||||
|
|
|
@ -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 | | |
|
||||
+-----------+----------+-------+---------------+-----------------+
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Drop support for Python 3.6.
|
|
@ -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():
|
||||
|
|
3
setup.py
3
setup.py
|
@ -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",
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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))
|
Loading…
Reference in New Issue