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 Python 3.7 #3143

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 1 addition & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
os:
- macos-11
- windows-latest
Expand All @@ -43,10 +43,6 @@ jobs:
nox-session: ['']
include:
- experimental: false
- python-version: "pypy-3.7"
os: ubuntu-latest
experimental: false
nox-session: test-pypy
- python-version: "pypy-3.8"
os: ubuntu-latest
experimental: false
Expand All @@ -73,8 +69,6 @@ jobs:
exclude:
# Ubuntu 22.04 comes with OpenSSL 3.0, so only CPython 3.9+ is compatible with it
# https://github.com/python/cpython/issues/83001
- python-version: "3.7"
os: ubuntu-22.04
- python-version: "3.8"
os: ubuntu-22.04
# Testing with non-final CPython on macOS is too slow for CI.
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ repos:
rev: v3.3.1
hooks:
- id: pyupgrade
args: ["--py37-plus"]
args: ["--py38-plus"]

- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
args: ["--target-version", "py37"]
args: ["--target-version", "py38"]

- repo: https://github.com/PyCQA/isort
rev: 5.12.0
Expand Down
1 change: 1 addition & 0 deletions changelog/3143.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed support for Python 3.7.
15 changes: 6 additions & 9 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
coverage==7.0.4
tornado==6.2
coverage==7.3.2
tornado==6.3.3
PySocks==1.7.1
pytest==7.4.0
pytest==7.4.2
pytest-timeout==2.1.0
trustme==0.9.0
# We have to install at most cryptography 39.0.2 for PyPy<7.3.10
# versions of Python 3.7, 3.8, and 3.9.
cryptography==39.0.2;implementation_name=="pypy" and implementation_version<"7.3.10"
cryptography==41.0.4;implementation_name!="pypy" or implementation_version>="7.3.10"
trustme==1.1.0
cryptography==41.0.4
backports.zoneinfo==0.2.1;python_version<"3.9"
towncrier==23.6.0
pytest-memray==1.4.0;python_version>="3.8" and python_version<"3.12" and sys_platform!="win32" and implementation_name=="cpython"
pytest-memray==1.5.0;sys_platform!="win32" and implementation_name=="cpython"
9 changes: 5 additions & 4 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ We use some external dependencies, multiple interpreters and code coverage
analysis while running test suite. Our ``noxfile.py`` handles much of this for
you::

$ nox --reuse-existing-virtualenvs --sessions test-3.7 test-3.9
$ nox --reuse-existing-virtualenvs --sessions test-3.8 test-3.9
[ Nox will create virtualenv if needed, install the specified dependencies, and run the commands in order.]
nox > Running session test-3.7
nox > Running session test-3.8
.......
.......
nox > Session test-3.7 was successful.
nox > Session test-3.8 was successful.
.......
.......
nox > Running session test-3.9
Expand All @@ -63,10 +63,11 @@ suite::
[ Nox will create virtualenv if needed, install the specified dependencies, and run the commands in order.]
.......
.......
nox > Session test-3.7 was successful.
nox > Session test-3.8 was successful.
nox > Session test-3.9 was successful.
nox > Session test-3.10 was successful.
nox > Session test-3.11 was successful.
nox > Session test-3.12 was successful.
nox > Session test-pypy was successful.

Our test suite `runs continuously on GitHub Actions
Expand Down
8 changes: 2 additions & 6 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@ def tests_impl(
session.run("python", "-m", "OpenSSL.debug")

memray_supported = True
if (
sys.implementation.name != "cpython"
or sys.version_info < (3, 8)
or sys.version_info.releaselevel != "final"
):
if sys.implementation.name != "cpython" or sys.version_info.releaselevel != "final":
memray_supported = False # pytest-memray requires CPython 3.8+
elif sys.platform == "win32":
memray_supported = False
Expand Down Expand Up @@ -58,7 +54,7 @@ def tests_impl(
)


@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy"])
@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12", "pypy"])
def test(session: nox.Session) -> None:
tests_impl(session)

Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -35,7 +34,7 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development :: Libraries",
]
requires-python = ">=3.7"
requires-python = ">=3.8"
dynamic = ["version"]

[project.optional-dependencies]
Expand Down
3 changes: 1 addition & 2 deletions src/urllib3/_base_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ class _ResponseOptions(typing.NamedTuple):

if typing.TYPE_CHECKING:
import ssl

from typing_extensions import Literal, Protocol
from typing import Literal, Protocol

from .response import BaseHTTPResponse

Expand Down
4 changes: 2 additions & 2 deletions src/urllib3/_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
if typing.TYPE_CHECKING:
# We can only import Protocol if TYPE_CHECKING because it's a development
# dependency, and is not available at runtime.
from typing_extensions import Protocol
from typing import Protocol

class HasGettableStringKeys(Protocol):
def keys(self) -> typing.Iterator[str]:
Expand Down Expand Up @@ -239,7 +239,7 @@ class HTTPHeaderDict(typing.MutableMapping[str, str]):

def __init__(self, headers: ValidHTTPHeaderSource | None = None, **kwargs: str):
super().__init__()
self._container = {} # 'dict' is insert-ordered in Python 3.7+
self._container = {} # 'dict' is insert-ordered
if headers is not None:
if isinstance(headers, HTTPHeaderDict):
self._copy_from(headers)
Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from socket import timeout as SocketTimeout

if typing.TYPE_CHECKING:
from typing_extensions import Literal
from typing import Literal

from .response import HTTPResponse
from .util.ssl_ import _TYPE_PEER_CERT_RET_DICT
Expand Down
3 changes: 1 addition & 2 deletions src/urllib3/connectionpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@

if typing.TYPE_CHECKING:
import ssl

from typing_extensions import Literal
from typing import Literal

from ._base_connection import BaseHTTPConnection, BaseHTTPSConnection

Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/contrib/securetransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
)

if typing.TYPE_CHECKING:
from typing_extensions import Literal
from typing import Literal

__all__ = ["inject_into_urllib3", "extract_from_urllib3"]

Expand Down
23 changes: 10 additions & 13 deletions src/urllib3/contrib/socks.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,16 @@
except ImportError:
ssl = None # type: ignore[assignment]

try:
from typing import TypedDict

class _TYPE_SOCKS_OPTIONS(TypedDict):
socks_version: int
proxy_host: str | None
proxy_port: str | None
username: str | None
password: str | None
rdns: bool

except ImportError: # Python 3.7
_TYPE_SOCKS_OPTIONS = typing.Dict[str, typing.Any] # type: ignore[misc, assignment]
from typing import TypedDict


class _TYPE_SOCKS_OPTIONS(TypedDict):
socks_version: int
proxy_host: str | None
proxy_port: str | None
username: str | None
password: str | None
rdns: bool


class SOCKSConnection(HTTPConnection):
Expand Down
3 changes: 1 addition & 2 deletions src/urllib3/poolmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@

if typing.TYPE_CHECKING:
import ssl

from typing_extensions import Literal
from typing import Literal

__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"]

Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
from .util.retry import Retry

if typing.TYPE_CHECKING:
from typing_extensions import Literal
from typing import Literal

from .connectionpool import HTTPConnectionPool

Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/util/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .util import to_bytes

if typing.TYPE_CHECKING:
from typing_extensions import Final
from typing import Final

# Pass as a value within ``headers`` to skip
# emitting some HTTP headers that are added automatically.
Expand Down
16 changes: 8 additions & 8 deletions src/urllib3/util/ssl_.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def _is_bpo_43522_fixed(
"""
if implementation_name == "pypy":
# https://foss.heptapod.net/pypy/pypy/-/issues/3129
return pypy_version_info >= (7, 3, 8) and version_info >= (3, 8) # type: ignore[operator]
return pypy_version_info >= (7, 3, 8) # type: ignore[operator]
elif implementation_name == "cpython":
major_minor = version_info[:2]
micro = version_info[2]
Expand Down Expand Up @@ -79,8 +79,7 @@ def _is_has_never_check_common_name_reliable(

if typing.TYPE_CHECKING:
from ssl import VerifyMode

from typing_extensions import Literal, TypedDict
from typing import Literal, TypedDict

from .ssltransport import SSLTransport as SSLTransportType

Expand Down Expand Up @@ -322,12 +321,13 @@ def create_urllib3_context(
# Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is
# necessary for conditional client cert authentication with TLS 1.3.
# The attribute is None for OpenSSL <= 1.1.0 or does not exist in older
# versions of Python. We only enable on Python 3.7.4+ or if certificate
# verification is enabled to work around Python issue #37428
# versions of Python. We only enable if certificate verification is enabled to work
# around Python issue #37428
# See: https://bugs.python.org/issue37428
if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr(
context, "post_handshake_auth", None
) is not None:
if (
cert_reqs == ssl.CERT_REQUIRED
and getattr(context, "post_handshake_auth", None) is not None
):
context.post_handshake_auth = True

# The order of the below lines setting verify_mode and check_hostname
Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/util/ssltransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from ..exceptions import ProxySchemeUnsupported

if typing.TYPE_CHECKING:
from typing_extensions import Literal
from typing import Literal

from .ssl_ import _TYPE_PEER_CERT_RET, _TYPE_PEER_CERT_RET_DICT

Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/util/timeout.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from ..exceptions import TimeoutStateError

if typing.TYPE_CHECKING:
from typing_extensions import Final
from typing import Final


class _TYPE_DEFAULT(Enum):
Expand Down
3 changes: 1 addition & 2 deletions test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@

if typing.TYPE_CHECKING:
import ssl

from typing_extensions import Literal
from typing import Literal


_RT = typing.TypeVar("_RT") # return type
Expand Down
4 changes: 0 additions & 4 deletions test/test_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import http.client as httplib
import socket
import ssl
import sys
import typing
import zlib
from base64 import b64decode
Expand Down Expand Up @@ -74,9 +73,6 @@ def test_multiple_chunks(self) -> None:
assert buffer.get(4) == b"rbaz"
assert len(buffer) == 0

@pytest.mark.skipif(
sys.version_info < (3, 8), reason="pytest-memray requires Python 3.8+"
)
@pytest.mark.limit_memory("12.5 MB") # assert that we're not doubling memory usage
def test_memory_usage(self) -> None:
# Allocate 10 1MiB chunks
Expand Down
2 changes: 1 addition & 1 deletion test/test_ssltransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from urllib3.util.ssltransport import SSLTransport

if typing.TYPE_CHECKING:
from typing_extensions import Literal
from typing import Literal

# consume_socket can iterate forever, we add timeouts to prevent halting.
PER_TEST_TIMEOUT = 60
Expand Down
5 changes: 2 additions & 3 deletions test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from . import clear_warnings

if typing.TYPE_CHECKING:
from typing_extensions import Literal
from typing import Literal

# This number represents a time in seconds, it doesn't mean anything in
# isolation. Setting to a high-ish value to avoid conflicts with the smaller
Expand Down Expand Up @@ -1075,8 +1075,7 @@ def test_ssl_wrap_socket_sni_none_no_warn(self) -> None:
# Python OK -> reliable
("OpenSSL 1.1.1", 0x10101000, "cpython", (3, 9, 3), None, True),
# PyPy: depends on the version
("OpenSSL 1.1.1", 0x10101000, "pypy", (3, 6, 9), (7, 3, 7), False),
("OpenSSL 1.1.1", 0x10101000, "pypy", (3, 7, 13), (7, 3, 9), False),
("OpenSSL 1.1.1", 0x10101000, "pypy", (3, 9, 9), (7, 3, 7), False),
("OpenSSL 1.1.1", 0x101010CF, "pypy", (3, 8, 12), (7, 3, 8), True),
# OpenSSL OK -> reliable
("OpenSSL 1.1.1", 0x101010CF, "cpython", (3, 9, 2), None, True),
Expand Down
2 changes: 0 additions & 2 deletions test/with_dummyserver/test_https.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import os.path
import shutil
import ssl
import sys
import tempfile
import warnings
from pathlib import Path
Expand Down Expand Up @@ -913,7 +912,6 @@ def test_tls_version_maximum_and_minimum(self) -> None:
finally:
conn.close()

@pytest.mark.skipif(sys.version_info < (3, 8), reason="requires python 3.8+")
def test_sslkeylogfile(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
Expand Down