Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for EOL Python 3.7 #11944

Merged
merged 12 commits into from Feb 18, 2024
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Expand Up @@ -104,7 +104,6 @@ jobs:
matrix:
os: [Ubuntu, MacOS]
python:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
Expand Down Expand Up @@ -155,9 +154,8 @@ jobs:
matrix:
os: [Windows]
python:
- "3.7"
- "3.8"
# Commented out, since Windows tests are expensively slow.
# - "3.8"
# - "3.9"
# - "3.10"
- "3.11"
Expand Down
25 changes: 6 additions & 19 deletions docs/html/development/ci.rst
Expand Up @@ -18,7 +18,6 @@ Supported interpreters

pip support a variety of Python interpreters:

- CPython 3.7
- CPython 3.8
- CPython 3.9
- CPython 3.10
Expand Down Expand Up @@ -90,9 +89,7 @@ Actual testing
+------------------------------+---------------+-----------------+
| **interpreter** | **unit** | **integration** |
+-----------+----------+-------+---------------+-----------------+
| | x86 | CP3.7 | | |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
| | x86 | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | +-------+---------------+-----------------+
Expand All @@ -104,9 +101,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| Windows +----------+-------+---------------+-----------------+
| | x64 | CP3.7 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
| | x64 | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | +-------+---------------+-----------------+
Expand All @@ -118,9 +113,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
+-----------+----------+-------+---------------+-----------------+
| | x86 | CP3.7 | | |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
| | x86 | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | +-------+---------------+-----------------+
Expand All @@ -132,9 +125,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| Linux +----------+-------+---------------+-----------------+
| | x64 | CP3.7 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.8 | GitHub | GitHub |
| | x64 | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
Expand All @@ -146,9 +137,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
+-----------+----------+-------+---------------+-----------------+
| | arm64 | CP3.7 | | |
| | +-------+---------------+-----------------+
| | | CP3.8 | | |
| | arm64 | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | +-------+---------------+-----------------+
Expand All @@ -160,9 +149,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| macOS +----------+-------+---------------+-----------------+
| | x64 | CP3.7 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.8 | GitHub | GitHub |
| | x64 | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
Expand Down
4 changes: 2 additions & 2 deletions docs/html/installation.md
Expand Up @@ -102,8 +102,8 @@ $ pip install --upgrade pip

The current version of pip works on:

- Windows, Linux and MacOS.
- CPython 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, and latest PyPy3.
- Windows, Linux and macOS.
- CPython 3.8, 3.9, 3.10, 3.11, 3.12, 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
Expand Down
1 change: 1 addition & 0 deletions news/11934.removal.rst
@@ -0,0 +1 @@
Drop support for EOL Python 3.7.
2 changes: 1 addition & 1 deletion noxfile.py
Expand Up @@ -67,7 +67,7 @@ def should_update_common_wheels() -> bool:
# -----------------------------------------------------------------------------
# Development Commands
# -----------------------------------------------------------------------------
@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy3"])
@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12", "pypy3"])
def test(session: nox.Session) -> None:
# Get the common wheels.
if should_update_common_wheels():
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Expand Up @@ -13,7 +13,6 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -28,7 +27,7 @@ authors = [

# NOTE: requires-python is duplicated in __pip-runner__.py.
# When changing this value, please change the other copy as well.
requires-python = ">=3.7"
requires-python = ">=3.8"

[project.urls]
Homepage = "https://pip.pypa.io/"
Expand Down Expand Up @@ -139,7 +138,7 @@ webencodings = "https://github.com/SimonSapin/python-webencodings/raw/master/LIC

[tool.ruff]
src = ["src"]
target-version = "py37"
target-version = "py38"
line-length = 88
extend-exclude = [
"_vendor",
Expand Down
4 changes: 2 additions & 2 deletions src/pip/__pip-runner__.py
Expand Up @@ -8,8 +8,8 @@

import sys

# Copied from setup.py
PYTHON_REQUIRES = (3, 7)
# Copied from pyproject.toml
PYTHON_REQUIRES = (3, 8)


def version_str(version): # type: ignore
Expand Down
3 changes: 1 addition & 2 deletions src/pip/_internal/commands/search.py
Expand Up @@ -5,7 +5,7 @@
import xmlrpc.client
from collections import OrderedDict
from optparse import Values
from typing import TYPE_CHECKING, Dict, List, Optional
from typing import TYPE_CHECKING, Dict, List, Optional, TypedDict

from pip._vendor.packaging.version import parse as parse_version

Expand All @@ -20,7 +20,6 @@
from pip._internal.utils.misc import write_output

if TYPE_CHECKING:
from typing import TypedDict

class TransformedHit(TypedDict):
name: str
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_internal/distributions/sdist.py
Expand Up @@ -117,7 +117,7 @@ def _install_build_reqs(self, finder: PackageFinder) -> None:
if (
self.req.editable
and self.req.permit_editable_wheels
and self.req.supports_pyproject_editable()
and self.req.supports_pyproject_editable
):
build_reqs = self._get_build_requires_editable()
else:
Expand Down
3 changes: 1 addition & 2 deletions src/pip/_internal/exceptions.py
Expand Up @@ -13,7 +13,7 @@
import re
import sys
from itertools import chain, groupby, repeat
from typing import TYPE_CHECKING, Dict, Iterator, List, Optional, Union
from typing import TYPE_CHECKING, Dict, Iterator, List, Literal, Optional, Union

from pip._vendor.requests.models import Request, Response
from pip._vendor.rich.console import Console, ConsoleOptions, RenderResult
Expand All @@ -22,7 +22,6 @@

if TYPE_CHECKING:
from hashlib import _Hash
from typing import Literal

from pip._internal.metadata import BaseDistribution
from pip._internal.req.req_install import InstallRequirement
Expand Down
7 changes: 1 addition & 6 deletions src/pip/_internal/index/collector.py
Expand Up @@ -14,14 +14,14 @@
from html.parser import HTMLParser
from optparse import Values
from typing import (
TYPE_CHECKING,
Callable,
Dict,
Iterable,
List,
MutableMapping,
NamedTuple,
Optional,
Protocol,
Sequence,
Tuple,
Union,
Expand All @@ -42,11 +42,6 @@

from .sources import CandidatesFromPage, LinkSource, build_source

if TYPE_CHECKING:
from typing import Protocol
else:
Protocol = object

logger = logging.getLogger(__name__)

ResponseHeaders = MutableMapping[str, str]
Expand Down
11 changes: 0 additions & 11 deletions src/pip/_internal/locations/__init__.py
Expand Up @@ -336,17 +336,6 @@ def get_scheme(
if skip_linux_system_special_case:
continue

# On Python 3.7 and earlier, sysconfig does not include sys.abiflags in
# the "pythonX.Y" part of the path, but distutils does.
skip_sysconfig_abiflag_bug = (
sys.version_info < (3, 8)
and not WINDOWS
and k in ("headers", "platlib", "purelib")
and tuple(_fix_abiflags(old_v.parts)) == new_v.parts
)
if skip_sysconfig_abiflag_bug:
continue

# MSYS2 MINGW's sysconfig patch does not include the "site-packages"
# part of the path. This is incorrect and will be fixed in MSYS.
skip_msys2_mingw_bug = (
Expand Down
21 changes: 5 additions & 16 deletions src/pip/_internal/metadata/base.py
Expand Up @@ -8,7 +8,6 @@
import zipfile
from typing import (
IO,
TYPE_CHECKING,
Any,
Collection,
Container,
Expand All @@ -18,6 +17,7 @@
List,
NamedTuple,
Optional,
Protocol,
Tuple,
Union,
)
Expand All @@ -41,11 +41,6 @@

from ._json import msg_to_json

if TYPE_CHECKING:
from typing import Protocol
else:
Protocol = object

DistributionVersion = Union[LegacyVersion, Version]

InfoPath = Union[str, pathlib.PurePath]
Expand Down Expand Up @@ -385,15 +380,7 @@ def iter_entry_points(self) -> Iterable[BaseEntryPoint]:
def _metadata_impl(self) -> email.message.Message:
raise NotImplementedError()

@functools.lru_cache(maxsize=1)
def _metadata_cached(self) -> email.message.Message:
# When we drop python 3.7 support, move this to the metadata property and use
# functools.cached_property instead of lru_cache.
metadata = self._metadata_impl()
self._add_egg_info_requires(metadata)
return metadata

@property
@functools.cached_property
def metadata(self) -> email.message.Message:
"""Metadata of distribution parsed from e.g. METADATA or PKG-INFO.

Expand All @@ -402,7 +389,9 @@ def metadata(self) -> email.message.Message:
:raises NoneMetadataError: If the metadata file is available, but does
not contain valid metadata.
"""
return self._metadata_cached()
metadata = self._metadata_impl()
self._add_egg_info_requires(metadata)
return metadata

@property
def metadata_dict(self) -> Dict[str, Any]:
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_internal/network/auth.py
Expand Up @@ -151,7 +151,7 @@ def _set_password(self, service_name: str, username: str, password: str) -> None
env["PYTHONIOENCODING"] = "utf-8"
subprocess.run(
[self.keyring, "set", service_name, username],
input=f"{password}{os.linesep}".encode("utf-8"),
input=f"{password}{os.linesep}".encode(),
env=env,
check=True,
)
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_internal/network/session.py
Expand Up @@ -230,7 +230,7 @@ def send(
# to return a better error message:
resp.status_code = 404
resp.reason = type(exc).__name__
resp.raw = io.BytesIO(f"{resp.reason}: {exc}".encode("utf8"))
resp.raw = io.BytesIO(f"{resp.reason}: {exc}".encode())
else:
modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
content_type = mimetypes.guess_type(pathname)[0] or "text/plain"
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_internal/operations/build/build_tracker.py
Expand Up @@ -99,7 +99,7 @@ def add(self, req: InstallRequirement, key: TrackerId) -> None:
except FileNotFoundError:
pass
else:
message = "{} is already being built: {}".format(req.link, contents)
message = f"{req.link} is already being built: {contents}"
raise LookupError(message)

# If we're here, req should really not be building already.
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_internal/operations/build/metadata_legacy.py
Expand Up @@ -27,7 +27,7 @@ def _find_egg_info(directory: str) -> str:

if len(filenames) > 1:
raise InstallationError(
"More than one .egg-info directory found in {}".format(directory)
f"More than one .egg-info directory found in {directory}"
)

return os.path.join(directory, filenames[0])
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_internal/operations/install/wheel.py
Expand Up @@ -28,6 +28,7 @@
List,
NewType,
Optional,
Protocol,
Sequence,
Set,
Tuple,
Expand Down Expand Up @@ -60,7 +61,6 @@
from pip._internal.utils.wheel import parse_wheel

if TYPE_CHECKING:
from typing import Protocol

class File(Protocol):
src_record_path: "RecordPath"
Expand Down
5 changes: 1 addition & 4 deletions src/pip/_internal/req/req_file.py
Expand Up @@ -17,6 +17,7 @@
Generator,
Iterable,
List,
NoReturn,
Optional,
Tuple,
)
Expand All @@ -30,10 +31,6 @@
from pip._internal.utils.urls import get_url_scheme

if TYPE_CHECKING:
# NoReturn introduced in 3.6.2; imported only for type checking to maintain
# pip compatibility with older patch versions of Python 3.6
from typing import NoReturn

from pip._internal.index.package_finder import PackageFinder

__all__ = ["parse_requirements"]
Expand Down
6 changes: 3 additions & 3 deletions src/pip/_internal/req/req_install.py
Expand Up @@ -244,7 +244,7 @@ def name(self) -> Optional[str]:
return None
return self.req.name

@functools.lru_cache() # use cached_property in python 3.8+
@functools.cached_property
def supports_pyproject_editable(self) -> bool:
if not self.use_pep517:
return False
Expand Down Expand Up @@ -542,7 +542,7 @@ def isolated_editable_sanity_check(self) -> None:
if (
self.editable
and self.use_pep517
and not self.supports_pyproject_editable()
and not self.supports_pyproject_editable
and not os.path.isfile(self.setup_py_path)
and not os.path.isfile(self.setup_cfg_path)
):
Expand All @@ -568,7 +568,7 @@ def prepare_metadata(self) -> None:
if (
self.editable
and self.permit_editable_wheels
and self.supports_pyproject_editable()
and self.supports_pyproject_editable
):
self.metadata_directory = generate_editable_metadata(
build_env=self.build_env,
Expand Down