-
Notifications
You must be signed in to change notification settings - Fork 2
chore(deps): bump urllib3 from 2.6.2 to 2.6.3 #164
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
Conversation
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.6.2 to 2.6.3. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](urllib3/urllib3@2.6.2...2.6.3) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.6.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
|
[puLL-Merge] - urllib3/urllib3@2.6.2..2.6.3 Diffdiff --git .github/SECURITY.md .github/SECURITY.md
index ab04cb3c47..4d81060e5d 100644
--- .github/SECURITY.md
+++ .github/SECURITY.md
@@ -28,6 +28,22 @@ When reporting a potential vulnerability, confirm that it reproduces against
the latest 2.x version.
+## Out of Scope Experimental Features
+
+urllib3 contains two experimental modules: `emscripten` and `http2`.
+
+- **http2**: Issues in the HTTP/2 module are not considered security
+ vulnerabilities and should be opened as public GitHub issues after
+ checking missing features tracked in issue
+ https://github.com/urllib3/urllib3/issues/3000.
+- **emscripten**: Potential security issues in the `emscripten` module should
+ be reported privately. Project maintainers will decide if they qualify as
+ security issues to be handled through the standard flow or if they should be
+ considered simple bugs and fixed publicly. Issues that would be considered
+ security vulnerabilities in the core package may not qualify as such for the
+ `emscripten` module.
+
+
## Our Process
We follow the [Tidelift security process](https://support.tidelift.com/hc/en-us/articles/4406287910036-Security-process)
diff --git .github/workflows/ci.yml .github/workflows/ci.yml
index a82f616c38..11785fa585 100644
--- .github/workflows/ci.yml
+++ .github/workflows/ci.yml
@@ -136,12 +136,12 @@ jobs:
uses: browser-actions/setup-firefox@5914774dda97099441f02628f8d46411fcfbd208 # v1.7.0
if: ${{ matrix.nox-session == 'emscripten(firefox)' }}
- name: "Install node.js"
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
if: ${{ matrix.nox-session == 'emscripten(node)' }}
with:
node-version: 22
- name: Cache pyodide downloads in nox cache
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
+ uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
if: ${{ startsWith(matrix.nox-session, 'emscripten') }}
with:
path: .nox/.cache
@@ -156,7 +156,7 @@ jobs:
NOX_SESSION: ${{ matrix.nox-session != '' && matrix.nox-session || format('test-{0}', matrix.python-version) }}
- name: "Upload coverage data"
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: coverage-data-${{ matrix.python-version }}-${{ matrix.os }}-${{ matrix.experimental }}-${{ matrix.nox-session }}
path: ".coverage.*"
@@ -189,7 +189,7 @@ jobs:
run: uv sync --dev --frozen
- name: "Download coverage data"
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
+ uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
pattern: coverage-data-*
merge-multiple: true
@@ -203,7 +203,7 @@ jobs:
- if: ${{ failure() }}
name: "Upload report if check failed"
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: coverage-report
path: htmlcov
diff --git .github/workflows/publish.yml .github/workflows/publish.yml
index c5b9991cc6..eaeb29af29 100644
--- .github/workflows/publish.yml
+++ .github/workflows/publish.yml
@@ -45,7 +45,7 @@ jobs:
cd dist && echo "hashes=$(sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT
- name: "Upload dists"
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
id: upload-artifact
with:
name: "dist"
@@ -66,7 +66,7 @@ jobs:
steps:
- name: "Download dists"
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
+ uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
artifact-ids: ${{ needs.build.outputs.artifact-id }}
path: "dist/"
@@ -99,7 +99,7 @@ jobs:
steps:
- name: "Download dists"
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
+ uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
artifact-ids: ${{ needs.build.outputs.artifact-id }}
path: "dist/"
diff --git CHANGES.rst CHANGES.rst
index 2de9f01637..36d7ed5dd6 100644
--- CHANGES.rst
+++ CHANGES.rst
@@ -1,3 +1,15 @@
+2.6.3 (2026-01-07)
+==================
+
+- Fixed a high-severity security issue where decompression-bomb safeguards of
+ the streaming API were bypassed when HTTP redirects were followed.
+ (`GHSA-38jv-5279-wg99 <https://github.com/urllib3/urllib3/security/advisories/GHSA-38jv-5279-wg99>`__)
+- Started treating ``Retry-After`` times greater than 6 hours as 6 hours by
+ default. (`#3743 <https://github.com/urllib3/urllib3/issues/3743>`__)
+- Fixed ``urllib3.connection.VerifiedHTTPSConnection`` on Emscripten.
+ (`#3752 <https://github.com/urllib3/urllib3/issues/3752>`__)
+
+
2.6.2 (2025-12-11)
==================
diff --git README.md README.md
index 355cb0ff85..96dfa2f91f 100644
--- README.md
+++ README.md
@@ -16,8 +16,7 @@
<a href="https://bestpractices.coreinfrastructure.org/projects/6227"><img alt="CII Best Practices" src="https://bestpractices.coreinfrastructure.org/projects/6227/badge" /></a>
</p>
-urllib3 is a powerful, *user-friendly* HTTP client for Python. Much of the
-Python ecosystem already uses urllib3 and you should too.
+urllib3 is a powerful, *user-friendly* HTTP client for Python.
urllib3 brings many critical features that are missing from the Python
standard libraries:
@@ -30,16 +29,13 @@ standard libraries:
- Proxy support for HTTP and SOCKS.
- 100% test coverage.
-urllib3 is powerful and easy to use:
+... and many more features, but most importantly: Our maintainers have a 15+
+year track record of maintaining urllib3 with the highest code standards and
+attention to security and safety.
+
+[Much of the Python ecosystem already uses urllib3](https://urllib3.readthedocs.io/en/stable/#who-uses)
+and you should too.
-```python3
->>> import urllib3
->>> resp = urllib3.request("GET", "http://httpbin.org/robots.txt")
->>> resp.status
-200
->>> resp.data
-b"User-agent: *\nDisallow: /deny\n"
-```
## Installing
@@ -57,8 +53,18 @@ $ cd urllib3
$ pip install .
```
+## Getting Started
-## Documentation
+urllib3 is easy to use:
+
+```python3
+>>> import urllib3
+>>> resp = urllib3.request("GET", "http://httpbin.org/robots.txt")
+>>> resp.status
+200
+>>> resp.data
+b"User-agent: *\nDisallow: /deny\n"
+```
urllib3 has usage and reference documentation at [urllib3.readthedocs.io](https://urllib3.readthedocs.io).
@@ -85,7 +91,9 @@ Tidelift will coordinate the fix and disclosure with maintainers.
## Maintainers
-- Lead: [@illia-v](https://github.com/illia-v) (Illia Volochii)
+Meet our maintainers since 2008:
+
+- Current Lead: [@illia-v](https://github.com/illia-v) (Illia Volochii)
- [@sethmlarson](https://github.com/sethmlarson) (Seth M. Larson)
- [@pquentin](https://github.com/pquentin) (Quentin Pradet)
- [@theacodes](https://github.com/theacodes) (Thea Flowers)
@@ -106,7 +114,7 @@ development](https://urllib3.readthedocs.io/en/latest/sponsors.html).
## For Enterprise
Professional support for urllib3 is available as part of the [Tidelift
-Subscription][1]. Tidelift gives software development teams a single source for
+Subscription][1]. Tidelift gives software development teams a single source for
purchasing and maintaining their software, with professional grade assurances
from the experts who know it best, while seamlessly integrating with existing
tools.
diff --git docs/index.rst docs/index.rst
index 1407431a5c..445bc7e9ec 100644
--- docs/index.rst
+++ docs/index.rst
@@ -7,13 +7,13 @@ urllib3
For Enterprise <https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=docs>
Community Discord <https://discord.gg/urllib3>
- v2-migration-guide
sponsors
user-guide
advanced-usage
reference/index
contributing
changelog
+ v2-migration-guide
urllib3 is a powerful, *user-friendly* HTTP client for Python.
:ref:`Much of the Python ecosystem already uses <who-uses>` urllib3 and you should too.
diff --git docs/v2-migration-guide.rst docs/v2-migration-guide.rst
index 39b1292fa4..7011caabe6 100644
--- docs/v2-migration-guide.rst
+++ docs/v2-migration-guide.rst
@@ -1,4 +1,4 @@
-v2.0 Migration Guide
+v2 Migration Guide
====================
**urllib3 2.x is now available!** Read below for how to get started and what is contained in the new major release.
@@ -61,7 +61,7 @@ ssl module is compiled with OpenSSL 1.0.2.k-fips
.. code-block:: text
- ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips 26 Jan 2017'.
+ ImportError: urllib3 v2 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips 26 Jan 2017'.
See: https://github.com/urllib3/urllib3/issues/2168
Remediation depends on your system:
@@ -178,7 +178,7 @@ ensure your package allows for both urllib3 1.26.x and 2.x to be used:
"urllib3>=1.26,<3"
]
-Next you should try installing urllib3 v2.0 locally and run your test suite.
+Next you should try installing urllib3 v2.x locally and run your test suite.
.. code-block:: bash
@@ -335,7 +335,7 @@ to support to ensure high security for data traveling
over the wire.
If you still need to use TLS 1.0 or 1.1 in your application
-you can still upgrade to v2.0, you'll only need to set
+you can still upgrade to v2.x, you'll only need to set
``ssl_minimum_version`` to the proper value to continue using
legacy TLS versions.
diff --git dummyserver/app.py dummyserver/app.py
index 0eeb93f739..5b82e9329d 100644
--- dummyserver/app.py
+++ dummyserver/app.py
@@ -233,10 +233,16 @@ async def redirect() -> ResponseReturnValue:
values = await request.values
target = values.get("target", "/")
status = values.get("status", "303 See Other")
+ compressed = values.get("compressed") == "true"
status_code = status.split(" ")[0]
headers = [("Location", target)]
- return await make_response("", status_code, headers)
+ if compressed:
+ headers.append(("Content-Encoding", "gzip"))
+ data = gzip.compress(b"foo")
+ else:
+ data = b""
+ return await make_response(data, status_code, headers)
@hypercorn_app.route("/redirect_after")
diff --git a/osv-scanner.toml b/osv-scanner.toml
new file mode 100644
index 0000000000..8ea10d80ec
--- /dev/null
+++ osv-scanner.toml
@@ -0,0 +1,4 @@
+# https://google.github.io/osv-scanner/configuration/#override-packages
+[[PackageOverrides]]
+vulnerability.ignore = true
+reason = "Vulnerabilities in dev dependencies should not affect our OpenSSF score."
diff --git src/urllib3/contrib/emscripten/__init__.py src/urllib3/contrib/emscripten/__init__.py
index 8a3c5bebdc..e5b62b25e9 100644
--- src/urllib3/contrib/emscripten/__init__.py
+++ src/urllib3/contrib/emscripten/__init__.py
@@ -14,3 +14,4 @@ def inject_into_urllib3() -> None:
HTTPSConnectionPool.ConnectionCls = EmscriptenHTTPSConnection
urllib3.connection.HTTPConnection = EmscriptenHTTPConnection # type: ignore[misc,assignment]
urllib3.connection.HTTPSConnection = EmscriptenHTTPSConnection # type: ignore[misc,assignment]
+ urllib3.connection.VerifiedHTTPSConnection = EmscriptenHTTPSConnection # type: ignore[assignment]
diff --git src/urllib3/contrib/emscripten/connection.py src/urllib3/contrib/emscripten/connection.py
index a5a353f8e8..63f79dd3be 100644
--- src/urllib3/contrib/emscripten/connection.py
+++ src/urllib3/contrib/emscripten/connection.py
@@ -40,6 +40,7 @@ class EmscriptenHTTPConnection:
is_verified: bool = False
proxy_is_verified: bool | None = None
+ response_class: type[BaseHTTPResponse] = EmscriptenHttpResponseWrapper
_response: EmscriptenResponse | None
def __init__(
diff --git src/urllib3/http2/connection.py src/urllib3/http2/connection.py
index 7534b770a8..0a026da0a8 100644
--- src/urllib3/http2/connection.py
+++ src/urllib3/http2/connection.py
@@ -6,9 +6,9 @@
import types
import typing
-import h2.config # type: ignore[import-untyped]
-import h2.connection # type: ignore[import-untyped]
-import h2.events # type: ignore[import-untyped]
+import h2.config
+import h2.connection
+import h2.events
from .._base_connection import _TYPE_BODY
from .._collections import HTTPHeaderDict
diff --git src/urllib3/response.py src/urllib3/response.py
index f6266f1a93..ff6d1f4911 100644
--- src/urllib3/response.py
+++ src/urllib3/response.py
@@ -797,7 +797,11 @@ def drain_conn(self) -> None:
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
"""
try:
- self.read()
+ self.read(
+ # Do not spend resources decoding the content unless
+ # decoding has already been initiated.
+ decode_content=self._has_decoded_content,
+ )
except (HTTPError, OSError, BaseSSLError, HTTPException):
pass
diff --git src/urllib3/util/retry.py src/urllib3/util/retry.py
index 0456cceba4..b21b4b64eb 100644
--- src/urllib3/util/retry.py
+++ src/urllib3/util/retry.py
@@ -178,6 +178,11 @@ class Retry:
Sequence of headers to remove from the request when a response
indicating a redirect is returned before firing off the redirected
request.
+
+ :param int retry_after_max: Number of seconds to allow as the maximum for
+ Retry-After headers. Defaults to :attr:`Retry.DEFAULT_RETRY_AFTER_MAX`.
+ Any Retry-After headers larger than this value will be limited to this
+ value.
"""
#: Default methods to be used for ``allowed_methods``
@@ -196,6 +201,10 @@ class Retry:
#: Default maximum backoff time.
DEFAULT_BACKOFF_MAX = 120
+ # This is undocumented in the RFC. Setting to 6 hours matches other popular libraries.
+ #: Default maximum allowed value for Retry-After headers in seconds
+ DEFAULT_RETRY_AFTER_MAX: typing.Final[int] = 21600
+
# Backward compatibility; assigned outside of the class.
DEFAULT: typing.ClassVar[Retry]
@@ -219,6 +228,7 @@ def __init__(
str
] = DEFAULT_REMOVE_HEADERS_ON_REDIRECT,
backoff_jitter: float = 0.0,
+ retry_after_max: int = DEFAULT_RETRY_AFTER_MAX,
) -> None:
self.total = total
self.connect = connect
@@ -235,6 +245,7 @@ def __init__(
self.allowed_methods = allowed_methods
self.backoff_factor = backoff_factor
self.backoff_max = backoff_max
+ self.retry_after_max = retry_after_max
self.raise_on_redirect = raise_on_redirect
self.raise_on_status = raise_on_status
self.history = history or ()
@@ -256,6 +267,7 @@ def new(self, **kw: typing.Any) -> Self:
status_forcelist=self.status_forcelist,
backoff_factor=self.backoff_factor,
backoff_max=self.backoff_max,
+ retry_after_max=self.retry_after_max,
raise_on_redirect=self.raise_on_redirect,
raise_on_status=self.raise_on_status,
history=self.history,
@@ -320,6 +332,10 @@ def parse_retry_after(self, retry_after: str) -> float:
seconds = max(seconds, 0)
+ # Check the seconds do not exceed the specified maximum
+ if seconds > self.retry_after_max:
+ seconds = self.retry_after_max
+
return seconds
def get_retry_after(self, response: BaseHTTPResponse) -> float | None:
diff --git test/contrib/emscripten/test_emscripten.py test/contrib/emscripten/test_emscripten.py
index b4d8b213ce..5e5e7dd4b0 100644
--- test/contrib/emscripten/test_emscripten.py
+++ test/contrib/emscripten/test_emscripten.py
@@ -302,15 +302,20 @@ def test_timeout_in_worker_streaming(
run_from_server.run_webworker(worker_code)
+@pytest.mark.parametrize(
+ "connection_cls", ["HTTPSConnection", "VerifiedHTTPSConnection"]
+)
def test_index_https(
- selenium_coverage: typing.Any, testserver_http: PyodideServerInfo
+ selenium_coverage: typing.Any,
+ testserver_http: PyodideServerInfo,
+ connection_cls: str,
) -> None:
@run_in_pyodide # type: ignore[misc]
- def pyodide_test(selenium_coverage, host: str, port: int) -> None: # type: ignore[no-untyped-def]
- from urllib3.connection import HTTPSConnection
+ def pyodide_test(selenium_coverage, host: str, port: int, connection_cls: str) -> None: # type: ignore[no-untyped-def]
+ from urllib3 import connection
from urllib3.response import BaseHTTPResponse
- conn = HTTPSConnection(host, port)
+ conn = getattr(connection, connection_cls)(host, port)
conn.request("GET", f"https://{host}:{port}/")
response = conn.getresponse()
assert isinstance(response, BaseHTTPResponse)
@@ -318,7 +323,10 @@ def pyodide_test(selenium_coverage, host: str, port: int) -> None: # type: igno
assert data.decode("utf-8") == "Dummy server!"
pyodide_test(
- selenium_coverage, testserver_http.http_host, testserver_http.https_port
+ selenium_coverage,
+ testserver_http.http_host,
+ testserver_http.https_port,
+ connection_cls,
)
diff --git test/test_http2_connection.py test/test_http2_connection.py
index 52c754ee83..9723dfdf3c 100644
--- test/test_http2_connection.py
+++ test/test_http2_connection.py
@@ -121,9 +121,9 @@ def test_send_bytes(self) -> None:
conn.sock = mock.MagicMock(
sendall=mock.Mock(return_value=None),
)
- conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"bar")
- conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
+ conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"bar") # type: ignore[method-assign]
+ conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
conn.putrequest("GET", "/")
conn.endheaders()
@@ -138,9 +138,9 @@ def test_send_str(self) -> None:
conn.sock = mock.MagicMock(
sendall=mock.Mock(return_value=None),
)
- conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"bar")
- conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
+ conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"bar") # type: ignore[method-assign]
+ conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
conn.putrequest("GET", "/")
conn.endheaders(message_body=b"foo")
@@ -155,10 +155,10 @@ def test_send_iter(self) -> None:
conn.sock = mock.MagicMock(
sendall=mock.Mock(return_value=None),
)
- conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"baz")
- conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
- conn._h2_conn._obj.end_stream = mock.Mock(return_value=None)
+ conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"baz") # type: ignore[method-assign]
+ conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
+ conn._h2_conn._obj.end_stream = mock.Mock(return_value=None) # type: ignore[method-assign]
conn.putrequest("GET", "/")
conn.endheaders(message_body=[b"foo", b"bar"])
@@ -191,10 +191,10 @@ def test_send_file_str(self) -> None:
conn.sock = mock.MagicMock(
sendall=mock.Mock(return_value=None),
)
- conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo")
- conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
- conn._h2_conn._obj.end_stream = mock.Mock(return_value=None)
+ conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo") # type: ignore[method-assign]
+ conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
+ conn._h2_conn._obj.end_stream = mock.Mock(return_value=None) # type: ignore[method-assign]
with open("foo") as body:
conn.putrequest("GET", "/")
@@ -215,10 +215,10 @@ def test_send_file_bytes(self) -> None:
conn.sock = mock.MagicMock(
sendall=mock.Mock(return_value=None),
)
- conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo")
- conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
- conn._h2_conn._obj.end_stream = mock.Mock(return_value=None)
+ conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo") # type: ignore[method-assign]
+ conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
+ conn._h2_conn._obj.end_stream = mock.Mock(return_value=None) # type: ignore[method-assign]
body = open("foo", "rb")
conn.putrequest("GET", "/")
@@ -244,11 +244,11 @@ def test_request_GET(self) -> None:
sendall=mock.Mock(return_value=None),
)
sendall = conn.sock.sendall
- data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo")
- send_headers = conn._h2_conn._obj.send_headers = mock.Mock(return_value=None)
- conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
- close_connection = conn._h2_conn._obj.close_connection = mock.Mock(
+ data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo") # type: ignore[method-assign]
+ send_headers = conn._h2_conn._obj.send_headers = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
+ close_connection = conn._h2_conn._obj.close_connection = mock.Mock( # type: ignore[method-assign]
return_value=None
)
@@ -277,11 +277,11 @@ def test_request_POST(self) -> None:
sendall=mock.Mock(return_value=None),
)
sendall = conn.sock.sendall
- data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo")
- send_headers = conn._h2_conn._obj.send_headers = mock.Mock(return_value=None)
- send_data = conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
- close_connection = conn._h2_conn._obj.close_connection = mock.Mock(
+ data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo") # type: ignore[method-assign]
+ send_headers = conn._h2_conn._obj.send_headers = mock.Mock(return_value=None) # type: ignore[method-assign]
+ send_data = conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
+ close_connection = conn._h2_conn._obj.close_connection = mock.Mock( # type: ignore[method-assign]
return_value=None
)
@@ -310,8 +310,8 @@ def test_close(self) -> None:
sendall=mock.Mock(side_effect=Exception("foo")),
)
sendall = conn.sock.sendall
- data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo")
- close_connection = conn._h2_conn._obj.close_connection = mock.Mock(
+ data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo") # type: ignore[method-assign]
+ close_connection = conn._h2_conn._obj.close_connection = mock.Mock( # type: ignore[method-assign]
return_value=None
)
@@ -332,11 +332,11 @@ def test_request_ignore_chunked(self) -> None:
sendall=mock.Mock(return_value=None),
)
sendall = conn.sock.sendall
- data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo")
- send_headers = conn._h2_conn._obj.send_headers = mock.Mock(return_value=None)
- conn._h2_conn._obj.send_data = mock.Mock(return_value=None)
- conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1)
- close_connection = conn._h2_conn._obj.close_connection = mock.Mock(
+ data_to_send = conn._h2_conn._obj.data_to_send = mock.Mock(return_value=b"foo") # type: ignore[method-assign]
+ send_headers = conn._h2_conn._obj.send_headers = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.send_data = mock.Mock(return_value=None) # type: ignore[method-assign]
+ conn._h2_conn._obj.get_next_available_stream_id = mock.Mock(return_value=1) # type: ignore[method-assign]
+ close_connection = conn._h2_conn._obj.close_connection = mock.Mock( # type: ignore[method-assign]
return_value=None
)
diff --git test/test_retry.py test/test_retry.py
index 85206b90ca..c46bcc0bb0 100644
--- test/test_retry.py
+++ test/test_retry.py
@@ -181,6 +181,18 @@ def test_configurable_backoff_max(self) -> None:
retry = retry.increment(method="GET")
assert retry.get_backoff_time() == max_backoff
+ def test_configurable_retry_after_max(self) -> None:
+ """Configurable retry after is computed correctly"""
+ max_retry_after = Retry.DEFAULT_RETRY_AFTER_MAX
+
+ retry = Retry()
+ assert retry.parse_retry_after(str(max_retry_after)) == max_retry_after
+ assert retry.parse_retry_after(str(max_retry_after + 1)) == max_retry_after
+
+ retry = Retry(retry_after_max=1)
+ assert retry.parse_retry_after(str(1)) == 1
+ assert retry.parse_retry_after(str(2)) == 1
+
def test_backoff_jitter(self) -> None:
"""Backoff with jitter is computed correctly"""
max_backoff = 1
diff --git test/with_dummyserver/test_connectionpool.py test/with_dummyserver/test_connectionpool.py
index ce165e24a1..8d6107aea0 100644
--- test/with_dummyserver/test_connectionpool.py
+++ test/with_dummyserver/test_connectionpool.py
@@ -508,6 +508,25 @@ def test_redirect(self) -> None:
assert r.status == 200
assert r.data == b"Dummy server!"
+ @mock.patch("urllib3.response.GzipDecoder.decompress")
+ def test_no_decoding_with_redirect_when_preload_disabled(
+ self, gzip_decompress: mock.MagicMock
+ ) -> None:
+ """
+ Test that urllib3 does not attempt to decode a gzipped redirect
+ response when `preload_content` is set to `False`.
+ """
+ with HTTPConnectionPool(self.host, self.port) as pool:
+ # Three requests are expected: two redirects and one final / 200 OK.
+ response = pool.request(
+ "GET",
+ "/redirect",
+ fields={"target": "/redirect?compressed=true", "compressed": "true"},
+ preload_content=False,
+ )
+ assert response.status == 200
+ gzip_decompress.assert_not_called()
+
def test_303_redirect_makes_request_lose_body(self) -> None:
with HTTPConnectionPool(self.host, self.port) as pool:
response = pool.request(
diff --git uv.lock uv.lock
index c414705882..8f0c88065e 100644
--- uv.lock
+++ uv.lock
@@ -2,7 +2,8 @@ version = 1
revision = 3
requires-python = ">=3.9"
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
"python_full_version < '3.10'",
]
@@ -45,7 +46,8 @@ name = "alabaster"
version = "1.0.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" }
@@ -573,7 +575,8 @@ name = "click"
version = "8.3.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
dependencies = [
@@ -724,7 +727,8 @@ name = "coverage"
version = "7.11.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/1c/38/ee22495420457259d2f3390309505ea98f98a5eed40901cf62196abad006/coverage-7.11.0.tar.gz", hash = "sha256:167bd504ac1ca2af7ff3b81d245dfea0292c5032ebef9d66cc08a7d28c1b8050", size = 811905, upload-time = "2025-10-15T15:15:08.542Z" }
@@ -944,15 +948,16 @@ wheels = [
[[package]]
name = "filelock"
-version = "3.20.0"
+version = "3.20.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
-sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/c1/e0/a75dbe4bca1e7d41307323dad5ea2efdd95408f74ab2de8bd7dba9b51a1a/filelock-3.20.2.tar.gz", hash = "sha256:a2241ff4ddde2a7cebddf78e39832509cb045d18ec1a09d7248d6bfc6bfbbe64", size = 19510, upload-time = "2026-01-02T15:33:32.582Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697, upload-time = "2026-01-02T15:33:31.133Z" },
]
[[package]]
@@ -1006,6 +1011,8 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7f/91/ae2eb6b7979e2f9b035a9f612cf70f1bf54aad4e1d125129bef1eae96f19/greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d", size = 584358, upload-time = "2025-08-07T13:18:23.708Z" },
{ url = "https://files.pythonhosted.org/packages/f7/85/433de0c9c0252b22b16d413c9407e6cb3b41df7389afc366ca204dbc1393/greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5", size = 1113550, upload-time = "2025-08-07T13:42:37.467Z" },
{ url = "https://files.pythonhosted.org/packages/a1/8d/88f3ebd2bc96bf7747093696f4335a0a8a4c5acfcf1b757717c0d2474ba3/greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f", size = 1137126, upload-time = "2025-08-07T13:18:20.239Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/29/74242b7d72385e29bcc5563fba67dad94943d7cd03552bac320d597f29b2/greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7", size = 1544904, upload-time = "2025-11-04T12:42:04.763Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/e2/1572b8eeab0f77df5f6729d6ab6b141e4a84ee8eb9bc8c1e7918f94eda6d/greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8", size = 1611228, upload-time = "2025-11-04T12:42:08.423Z" },
{ url = "https://files.pythonhosted.org/packages/d6/6f/b60b0291d9623c496638c582297ead61f43c4b72eef5e9c926ef4565ec13/greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c", size = 298654, upload-time = "2025-08-07T13:50:00.469Z" },
{ url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" },
{ url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" },
@@ -1015,6 +1022,8 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" },
{ url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" },
{ url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" },
+ { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385, upload-time = "2025-11-04T12:42:11.067Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329, upload-time = "2025-11-04T12:42:12.928Z" },
{ url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" },
{ url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" },
{ url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" },
@@ -1024,6 +1033,8 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" },
{ url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" },
{ url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" },
+ { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" },
+ { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" },
{ url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" },
{ url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" },
{ url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" },
@@ -1033,6 +1044,8 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" },
{ url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" },
{ url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" },
+ { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" },
{ url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" },
{ url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" },
{ url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" },
@@ -1040,6 +1053,8 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" },
{ url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" },
{ url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" },
+ { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" },
{ url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" },
{ url = "https://files.pythonhosted.org/packages/f7/c0/93885c4106d2626bf51fdec377d6aef740dfa5c4877461889a7cf8e565cc/greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c", size = 269859, upload-time = "2025-08-07T13:16:16.003Z" },
{ url = "https://files.pythonhosted.org/packages/4d/f5/33f05dc3ba10a02dedb1485870cf81c109227d3d3aa280f0e48486cac248/greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d", size = 627610, upload-time = "2025-08-07T13:43:01.345Z" },
@@ -1049,6 +1064,8 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6b/4c/f3de2a8de0e840ecb0253ad0dc7e2bb3747348e798ec7e397d783a3cb380/greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df", size = 582817, upload-time = "2025-08-07T13:18:35.48Z" },
{ url = "https://files.pythonhosted.org/packages/89/80/7332915adc766035c8980b161c2e5d50b2f941f453af232c164cff5e0aeb/greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594", size = 1111985, upload-time = "2025-08-07T13:42:42.425Z" },
{ url = "https://files.pythonhosted.org/packages/66/71/1928e2c80197353bcb9b50aa19c4d8e26ee6d7a900c564907665cf4b9a41/greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98", size = 1136137, upload-time = "2025-08-07T13:18:26.168Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/bf/7bd33643e48ed45dcc0e22572f650767832bd4e1287f97434943cc402148/greenlet-3.2.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:28a3c6b7cd72a96f61b0e4b2a36f681025b60ae4779cc73c1535eb5f29560b10", size = 1542941, upload-time = "2025-11-04T12:42:27.427Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/74/4bc433f91d0d09a1c22954a371f9df928cb85e72640870158853a83415e5/greenlet-3.2.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:52206cd642670b0b320a1fd1cbfd95bca0e043179c1d8a045f2c6109dfe973be", size = 1609685, upload-time = "2025-11-04T12:42:29.242Z" },
{ url = "https://files.pythonhosted.org/packages/89/48/a5dc74dde38aeb2b15d418cec76ed50e1dd3d620ccda84d8199703248968/greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b", size = 281400, upload-time = "2025-08-07T14:02:20.263Z" },
{ url = "https://files.pythonhosted.org/packages/e5/44/342c4591db50db1076b8bda86ed0ad59240e3e1da17806a4cf10a6d0e447/greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb", size = 298533, upload-time = "2025-08-07T13:56:34.168Z" },
]
@@ -1064,15 +1081,15 @@ wheels = [
[[package]]
name = "h2"
-version = "4.1.0"
+version = "4.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "hpack" },
{ name = "hyperframe" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/2a/32/fec683ddd10629ea4ea46d206752a95a2d8a48c22521edd70b142488efe1/h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb", size = 2145593, upload-time = "2021-10-05T18:27:47.18Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/2a/e5/db6d438da759efbb488c4f3fbdab7764492ff3c3f953132efa6b9f0e9e53/h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d", size = 57488, upload-time = "2021-10-05T18:27:39.977Z" },
+ { url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" },
]
[[package]]
@@ -1129,7 +1146,8 @@ name = "humanize"
version = "4.14.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/b6/43/50033d25ad96a7f3845f40999b4778f753c3901a11808a584fed7c00d9f5/humanize-4.14.0.tar.gz", hash = "sha256:2fa092705ea640d605c435b1ca82b2866a1b601cdf96f076d70b79a855eba90d", size = 82939, upload-time = "2025-10-15T13:04:51.214Z" }
@@ -1202,7 +1220,7 @@ name = "importlib-metadata"
version = "8.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "zipp" },
+ { name = "zipp", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" }
wheels = [
@@ -1291,7 +1309,8 @@ name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
dependencies = [
@@ -1426,7 +1445,8 @@ name = "mdit-py-plugins"
version = "0.5.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
dependencies = [
@@ -1640,7 +1660,8 @@ name = "platformdirs"
version = "4.5.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
"python_full_version == '3.10.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" }
@@ -2039,7 +2060,8 @@ name = "sphinx"
version = "8.2.3"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.11'",
+ "python_full_version >= '3.13'",
+ "python_full_version >= '3.11' and python_full_version < '3.13'",
]
dependencies = [
{ name = "alabaster", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
@@ -2166,8 +2188,8 @@ name = "taskgroup"
version = "0.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "exceptiongroup" },
- { name = "typing-extensions" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f0/8d/e218e0160cc1b692e6e0e5ba34e8865dbb171efeb5fc9a704544b3020605/taskgroup-0.2.2.tar.gz", hash = "sha256:078483ac3e78f2e3f973e2edbf6941374fbea81b9c5d0a96f51d297717f4752d", size = 11504, upload-time = "2025-01-03T09:24:13.761Z" }
wheels = [
@@ -2484,7 +2506,7 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
{ name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "filelock", version = "3.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "filelock", version = "3.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
@@ -2505,14 +2527,14 @@ wheels = [
[[package]]
name = "werkzeug"
-version = "3.1.3"
+version = "3.1.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687, upload-time = "2025-11-29T02:15:22.841Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960, upload-time = "2025-11-29T02:15:21.13Z" },
]
[[package]]
DescriptionThis pull request introduces several important changes to the urllib3 project. The primary changes are:
Possible Issues
Security Hotspots
Privacy HotspotsThere are no noteworthy privacy risks introduced by this PR. ChangesChangesDocumentation Changes
Workflow Changes
Code Changes
sequenceDiagram
participant User
participant GitHubActions
participant TestServer
User->>GitHubActions: Create PR with changes
GitHubActions-->>TestServer: Run updated CI
Note right of GitHubActions: Upgrades to actions versions
GitHubActions-->>User: Provide feedback on test results
User->>TestServer: Implement and verify code changes
TestServer-->>User: Confirm implementation
|
Bumps urllib3 from 2.6.2 to 2.6.3.
Release notes
Sourced from urllib3's releases.
Changelog
Sourced from urllib3's changelog.
Commits
0248277Release 2.6.38864ac4Merge commit from fork70cecb2Fix Scorecard issues related to vulnerable dev dependencies (#3755)41f249aMove "v2.0 Migration Guide" to the end of the table of contents (#3747)fd4dffdPatchVerifiedHTTPSConnectionfor Emscripten (#3752)13f0bfdHandle massive values in Retry-After when calculating time to sleep for (#3743)8c480bfBump actions/upload-artifact from 5.0.0 to 6.0.0 (#3748)4b40616Bump actions/cache from 4.3.0 to 5.0.1 (#3750)82b8479Bump actions/download-artifact from 6.0.0 to 7.0.0 (#3749)34284cbMention experimental features in the security policy (#3746)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot mergewill merge this PR after your CI passes on it@dependabot squash and mergewill squash and merge this PR after your CI passes on it@dependabot cancel mergewill cancel a previously requested merge and block automerging@dependabot reopenwill reopen this PR if it is closed@dependabot closewill close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)You can disable automated security fix PRs for this repo from the Security Alerts page.