diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3cbd4a8a..4ceb8c69 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,7 +14,7 @@ jobs: name: deploy steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - uses: "actions/setup-python@v4" with: python-version: 3.8 diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index eb1cc7e2..c3ad08f1 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -14,13 +14,14 @@ jobs: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - uses: "actions/setup-python@v4" with: python-version: "${{ matrix.python-version }}" + allow-prereleases: true - name: "Install dependencies" run: "scripts/install" - name: "Run linting checks" diff --git a/CHANGELOG.md b/CHANGELOG.md index 4842dfff..73b99c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +### Added + +* Add support for Python 3.12. (#2854) + ### Fixed * Raise `ValueError` on `Response.encoding` being set after `Response.text` has been accessed. (#2852) diff --git a/docs/compatibility.md b/docs/compatibility.md index b2092477..3e8bf9b9 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -201,6 +201,10 @@ Besides, `httpx.Request()` does not support the `auth`, `timeout`, `follow_redir If you need to mock HTTPX the same way that test utilities like `responses` and `requests-mock` does for `requests`, see [RESPX](https://github.com/lundberg/respx). +## Caching + +If you use `cachecontrol` or `requests-cache` to add HTTP Caching support to the `requests` library, you can use [Hishel](https://hishel.com) for HTTPX. + ## Networking layer `requests` defers most of its HTTP networking code to the excellent [`urllib3` library](https://urllib3.readthedocs.io/en/latest/). diff --git a/httpx/_compat.py b/httpx/_compat.py index a271c6b8..493e6210 100644 --- a/httpx/_compat.py +++ b/httpx/_compat.py @@ -16,9 +16,7 @@ except ImportError: # pragma: no cover except ImportError: brotli = None -if sys.version_info >= (3, 10) or ( - sys.version_info >= (3, 8) and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0, 7) -): +if sys.version_info >= (3, 10) or ssl.OPENSSL_VERSION_INFO >= (1, 1, 0, 7): def set_minimum_tls_version_1_2(context: ssl.SSLContext) -> None: # The OP_NO_SSL* and OP_NO_TLS* become deprecated in favor of diff --git a/httpx/_config.py b/httpx/_config.py index 39d81a20..45ed29ed 100644 --- a/httpx/_config.py +++ b/httpx/_config.py @@ -1,7 +1,6 @@ import logging import os import ssl -import sys import typing from pathlib import Path @@ -128,11 +127,10 @@ class SSLConfig: # Signal to server support for PHA in TLS 1.3. Raises an # AttributeError if only read-only access is implemented. - if sys.version_info >= (3, 8): # pragma: no cover - try: - context.post_handshake_auth = True - except AttributeError: # pragma: no cover - pass + try: + context.post_handshake_auth = True + except AttributeError: # pragma: no cover + pass # Disable using 'commonName' for SSLContext.check_hostname # when the 'subjectAltName' extension isn't available. @@ -168,10 +166,9 @@ class SSLConfig: alpn_idents = ["http/1.1", "h2"] if self.http2 else ["http/1.1"] context.set_alpn_protocols(alpn_idents) - if sys.version_info >= (3, 8): # pragma: no cover - keylogfile = os.environ.get("SSLKEYLOGFILE") - if keylogfile and self.trust_env: - context.keylog_filename = keylogfile + keylogfile = os.environ.get("SSLKEYLOGFILE") + if keylogfile and self.trust_env: + context.keylog_filename = keylogfile return context diff --git a/httpx/_urlparse.py b/httpx/_urlparse.py index e1ba8dcd..8e060424 100644 --- a/httpx/_urlparse.py +++ b/httpx/_urlparse.py @@ -87,7 +87,7 @@ COMPONENT_REGEX = { # We use these simple regexs as a first pass before handing off to # the stdlib 'ipaddress' module for IP address validation. -IPv4_STYLE_HOSTNAME = re.compile(r"^[0-9]+.[0-9]+.[0-9]+.[0-9]+$") +IPv4_STYLE_HOSTNAME = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") IPv6_STYLE_HOSTNAME = re.compile(r"^\[.*\]$") diff --git a/pyproject.toml b/pyproject.toml index 7daaeddc..353a3973 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Internet :: WWW/HTTP", ] dependencies = [ diff --git a/requirements.txt b/requirements.txt index 1503d820..d1065ee3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,22 +10,22 @@ chardet==5.2.0 types-chardet==5.0.4.5 # Documentation -mkdocs==1.5.2 +mkdocs==1.5.3 mkautodoc==0.2.0 -mkdocs-material==9.2.6 +mkdocs-material==9.4.2 # Packaging build==0.10.0 twine==4.0.2 # Tests & Linting -black==23.7.0 +black==23.9.1 coverage[toml]==7.3.0 -cryptography==41.0.3 +cryptography==41.0.4 mypy==1.5.1 types-certifi==2021.10.8.2 -pytest==7.4.0 -ruff==0.0.286 +pytest==7.4.2 +ruff==0.0.291 trio-typing==0.8.0 trustme==1.1.0 uvicorn==0.22.0 diff --git a/tests/test_urlparse.py b/tests/test_urlparse.py index 3ae9b04c..b03291b4 100644 --- a/tests/test_urlparse.py +++ b/tests/test_urlparse.py @@ -45,6 +45,12 @@ def test_urlparse_normalized_host(): assert url.host == "example.com" +def test_urlparse_ipv4_like_host(): + """rare host names used to quality as IPv4""" + url = httpx.URL("https://023b76x43144/") + assert url.host == "023b76x43144" + + def test_urlparse_valid_ipv4(): url = httpx.URL("https://1.2.3.4/") assert url.host == "1.2.3.4"