Skip to content

Remove support for Python 3.8 #13190

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

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -34,3 +34,5 @@ c7ee560e00b85f7486b452c14ff49e4737996eda # Blacken tools/
94999255d5ede440c37137d210666fdf64302e75 # Reformat the codebase, with black
585037a80a1177f1fa92e159a7079855782e543e # Cleanup implicit string concatenation
8a6f6ac19b80a6dc35900a47016c851d9fcd2ee2 # Blacken src/pip/_internal/resolution directory
c71318918ebc683ab1bf770514c25979a1306871 # pyupgrade --py39-plus src/pip/_internal/**.py
9adbfcecbb2ba83e06a8efaa6fc5918d969c07af # pyupgrade --py39-plus everything else
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -114,7 +114,6 @@ jobs:
matrix:
os: [ubuntu-22.04, macos-13, macos-latest]
python:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
@@ -172,10 +171,9 @@ jobs:
matrix:
os: [Windows]
python:
- "3.8"
- "3.9"
# Commented out, since Windows tests are expensively slow,
# only test the oldest and newest Python supported by pip
# - "3.9"
# - "3.10"
# - "3.11"
# - "3.12"
3 changes: 1 addition & 2 deletions docs/html/conf.py
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@
import pathlib
import re
import sys
from typing import List, Tuple

# Add the docs/ directory to sys.path, because pip_sphinxext.py is there.
docs_dir = os.path.dirname(os.path.dirname(__file__))
@@ -91,7 +90,7 @@


# List of manual pages generated
def determine_man_pages() -> List[Tuple[str, str, str, str, int]]:
def determine_man_pages() -> list[tuple[str, str, str, str, int]]:
"""Determine which man pages need to be generated."""

def to_document_name(path: str, base_dir: str) -> str:
27 changes: 7 additions & 20 deletions docs/html/development/ci.rst
Original file line number Diff line number Diff line change
@@ -18,7 +18,6 @@ Supported interpreters

pip support a variety of Python interpreters:

- CPython 3.8
- CPython 3.9
- CPython 3.10
- CPython 3.11
@@ -38,7 +37,7 @@ and on different architectures:
- x86
- arm64 (macOS only)

so 49 hypothetical interpreters.
so 42 hypothetical interpreters.


Checks
@@ -91,9 +90,7 @@ Actual testing
+------------------------------+---------------+-----------------+
| **interpreter** | **unit** | **integration** |
+-----------+----------+-------+---------------+-----------------+
| | x86 | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | x86 | CP3.9 | | |
| | +-------+---------------+-----------------+
| | | CP3.10| | |
| | +-------+---------------+-----------------+
@@ -105,9 +102,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| Windows +----------+-------+---------------+-----------------+
| | x64 | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | x64 | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.10| | |
| | +-------+---------------+-----------------+
@@ -119,9 +114,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
+-----------+----------+-------+---------------+-----------------+
| | x86 | CP3.8 | | |
| | +-------+---------------+-----------------+
| | | CP3.9 | | |
| | x86 | CP3.9 | | |
| | +-------+---------------+-----------------+
| | | CP3.10| | |
| | +-------+---------------+-----------------+
@@ -133,9 +126,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| Linux +----------+-------+---------------+-----------------+
| | x64 | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | GitHub | GitHub |
| | x64 | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.10| GitHub | GitHub |
| | +-------+---------------+-----------------+
@@ -147,9 +138,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
+-----------+----------+-------+---------------+-----------------+
| | arm64 | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | GitHub | GitHub |
| | arm64 | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.10| GitHub | GitHub |
| | +-------+---------------+-----------------+
@@ -161,9 +150,7 @@ Actual testing
| | +-------+---------------+-----------------+
| | | PyPy3 | | |
| macOS +----------+-------+---------------+-----------------+
| | x64 | CP3.8 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.9 | GitHub | GitHub |
| | x64 | CP3.9 | GitHub | GitHub |
| | +-------+---------------+-----------------+
| | | CP3.10| GitHub | GitHub |
| | +-------+---------------+-----------------+
2 changes: 1 addition & 1 deletion docs/html/installation.md
Original file line number Diff line number Diff line change
@@ -126,7 +126,7 @@ $ pip install --upgrade pip
The current version of pip works on:

- Windows, Linux and macOS.
- CPython 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, and latest PyPy3.
- CPython 3.9, 3.10, 3.11, 3.12, 3.13, 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
19 changes: 10 additions & 9 deletions docs/pip_sphinxext.py
Original file line number Diff line number Diff line change
@@ -4,8 +4,9 @@
import pathlib
import re
import sys
from collections.abc import Iterable, Iterator
from textwrap import dedent
from typing import Dict, Iterable, Iterator, List, Optional, Union
from typing import Optional, Union

from docutils import nodes, statemachine
from docutils.parsers import rst
@@ -24,7 +25,7 @@ def convert_cli_option_to_envvar(opt_name: str) -> str:
return f"PIP_{normalized_opt_name}"


def convert_cli_opt_names_to_envvars(original_cli_opt_names: List[str]) -> List[str]:
def convert_cli_opt_names_to_envvars(original_cli_opt_names: list[str]) -> list[str]:
return [
convert_cli_option_to_envvar(opt_name) for opt_name in original_cli_opt_names
]
@@ -69,7 +70,7 @@ def _iter_lines_with_refs(self, lines: Iterable[str]) -> Iterator[str]:
if prev is not None:
yield prev

def run(self) -> List[nodes.Node]:
def run(self) -> list[nodes.Node]:
source = self.state_machine.input_lines.source(
self.lineno - self.state_machine.input_offset - 1,
)
@@ -90,7 +91,7 @@ class PipCommandUsage(rst.Directive):
required_arguments = 1
optional_arguments = 3

def run(self) -> List[nodes.Node]:
def run(self) -> list[nodes.Node]:
cmd = create_command(self.arguments[0])
cmd_prefix = "python -m pip"
if len(self.arguments) > 1:
@@ -105,7 +106,7 @@ def run(self) -> List[nodes.Node]:
class PipCommandDescription(rst.Directive):
required_arguments = 1

def run(self) -> List[nodes.Node]:
def run(self) -> list[nodes.Node]:
node = nodes.paragraph()
node.document = self.state.document
desc = ViewList()
@@ -121,7 +122,7 @@ def run(self) -> List[nodes.Node]:
class PipOptions(rst.Directive):
def _format_option(
self, option: optparse.Option, cmd_name: Optional[str] = None
) -> List[str]:
) -> list[str]:
bookmark_line = (
f".. _`{cmd_name}_{option._long_opts[0]}`:"
if cmd_name
@@ -165,7 +166,7 @@ def _format_options(
for line in self._format_option(option, cmd_name):
self.view_list.append(line, "")

def run(self) -> List[nodes.Node]:
def run(self) -> list[nodes.Node]:
node = nodes.paragraph()
node.document = self.state.document
self.view_list = ViewList()
@@ -242,7 +243,7 @@ class PipCLIDirective(rst.Directive):
has_content = True
optional_arguments = 1

def run(self) -> List[nodes.Node]:
def run(self) -> list[nodes.Node]:
node = nodes.paragraph()
node.document = self.state.document

@@ -310,7 +311,7 @@ def run(self) -> List[nodes.Node]:
return [node]


def setup(app: Sphinx) -> Dict[str, Union[bool, str]]:
def setup(app: Sphinx) -> dict[str, Union[bool, str]]:
app.add_directive("pip-command-usage", PipCommandUsage)
app.add_directive("pip-command-description", PipCommandDescription)
app.add_directive("pip-command-options", PipCommandOptions)
1 change: 1 addition & 0 deletions news/12989.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Drop support for EOL Python 3.8.
10 changes: 5 additions & 5 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@
import os
import shutil
import sys
from collections.abc import Iterator
from pathlib import Path
from typing import Iterator, List, Tuple

import nox

@@ -70,7 +70,7 @@ def should_update_common_wheels() -> bool:
# -----------------------------------------------------------------------------
# Development Commands
# -----------------------------------------------------------------------------
@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3"])
@nox.session(python=["3.9", "3.10", "3.11", "3.12", "3.13", "pypy3"])
def test(session: nox.Session) -> None:
# Get the common wheels.
if should_update_common_wheels():
@@ -137,7 +137,7 @@ def test(session: nox.Session) -> None:
def docs(session: nox.Session) -> None:
session.install("-r", REQUIREMENTS["docs"])

def get_sphinx_build_command(kind: str) -> List[str]:
def get_sphinx_build_command(kind: str) -> list[str]:
# Having the conf.py in the docs/html is weird but needed because we
# can not use a different configuration directory vs source directory
# on RTD currently. So, we'll pass "-c docs/html" here.
@@ -214,7 +214,7 @@ def vendoring(session: nox.Session) -> None:
session.run("vendoring", "sync", "-v")
return

def pinned_requirements(path: Path) -> Iterator[Tuple[str, str]]:
def pinned_requirements(path: Path) -> Iterator[tuple[str, str]]:
for line in path.read_text().splitlines(keepends=False):
one, sep, two = line.partition("==")
if not sep:
@@ -357,7 +357,7 @@ def build_release(session: nox.Session) -> None:
shutil.copy(dist, final)


def build_dists(session: nox.Session) -> List[str]:
def build_dists(session: nox.Session) -> list[str]:
"""Return dists with valid metadata."""
session.log(
"# Check if there's any Git-untracked files before building the wheel",
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
@@ -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.8"
requires-python = ">=3.9"

[project.scripts]
pip = "pip._internal.cli.main:main"
4 changes: 2 additions & 2 deletions src/pip/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import List, Optional
from typing import Optional

__version__ = "25.1.dev0"


def main(args: Optional[List[str]] = None) -> int:
def main(args: Optional[list[str]] = None) -> int:
"""This is an internal API only meant for use by pip's own console scripts.

For additional details, see https://github.com/pypa/pip/issues/7498.
2 changes: 1 addition & 1 deletion src/pip/__pip-runner__.py
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
import sys

# Copied from pyproject.toml
PYTHON_REQUIRES = (3, 8)
PYTHON_REQUIRES = (3, 9)


def version_str(version): # type: ignore
4 changes: 2 additions & 2 deletions src/pip/_internal/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List, Optional
from typing import Optional

from pip._internal.utils import _log

@@ -7,7 +7,7 @@
_log.init_logging()


def main(args: Optional[List[str]] = None) -> int:
def main(args: Optional[list[str]] = None) -> int:
"""This is preserved for old console scripts that may still be referencing
it.

19 changes: 10 additions & 9 deletions src/pip/_internal/build_env.py
Original file line number Diff line number Diff line change
@@ -8,8 +8,9 @@
import sys
import textwrap
from collections import OrderedDict
from collections.abc import Iterable
from types import TracebackType
from typing import TYPE_CHECKING, Iterable, List, Optional, Set, Tuple, Type, Union
from typing import TYPE_CHECKING, Optional, Union

from pip._vendor.certifi import where
from pip._vendor.packaging.version import Version
@@ -29,7 +30,7 @@
logger = logging.getLogger(__name__)


def _dedup(a: str, b: str) -> Union[Tuple[str], Tuple[str, str]]:
def _dedup(a: str, b: str) -> Union[tuple[str], tuple[str, str]]:
return (a, b) if a != b else (a,)


@@ -58,7 +59,7 @@ def get_runnable_pip() -> str:
return os.fsdecode(source / "__pip-runner__.py")


def _get_system_sitepackages() -> Set[str]:
def _get_system_sitepackages() -> set[str]:
"""Get system site packages

Usually from site.getsitepackages,
@@ -89,8 +90,8 @@ def __init__(self) -> None:
for name in ("normal", "overlay")
)

self._bin_dirs: List[str] = []
self._lib_dirs: List[str] = []
self._bin_dirs: list[str] = []
self._lib_dirs: list[str] = []
for prefix in reversed(list(self._prefixes.values())):
self._bin_dirs.append(prefix.bin_dir)
self._lib_dirs.extend(prefix.lib_dirs)
@@ -158,7 +159,7 @@ def __enter__(self) -> None:

def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_type: Optional[type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
) -> None:
@@ -170,7 +171,7 @@ def __exit__(

def check_requirements(
self, reqs: Iterable[str]
) -> Tuple[Set[Tuple[str, str]], Set[str]]:
) -> tuple[set[tuple[str, str]], set[str]]:
"""Return 2 sets:
- conflicting requirements: set of (installed, wanted) reqs tuples
- missing requirements: set of reqs
@@ -232,7 +233,7 @@ def _install_requirements(
*,
kind: str,
) -> None:
args: List[str] = [
args: list[str] = [
sys.executable,
pip_runnable,
"install",
@@ -303,7 +304,7 @@ def __enter__(self) -> None:

def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_type: Optional[type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
) -> None:
Loading