Restore but deprecate HTTPResponse.getheaders() and .getheader() methods
MODIFY
CHANGES.rst
CHANGES.rst
@@ -77,7 +77,6 @@ Changed
a default value. The new default will be cipher suites configured by the operating system (`#2168 <https://github.com/urllib3/urllib3/issues/2168>`__).
* Changed ``multipart/form-data`` header parameter formatting matches the WHATWG HTML Standard as of 2021-06-10. Control characters in filenames are no longer percent encoded (`#2257 <https://github.com/urllib3/urllib3/issues/2257>`__).
* Changed ``urllib3.HTTPConnection.getresponse`` to return an instance of ``urllib3.HTTPResponse`` instead of ``http.client.HTTPResponse`` (`#2648 <https://github.com/urllib3/urllib3/issues/2648>`__).
-* Changed return type of ``HTTPResponse.getheaders()`` method to return a list of key-value tuples to match CPython (`#1543 <https://github.com/urllib3/urllib3/issues/1543>`__).
* Changed the error raised when connecting via HTTPS when the ``ssl`` module isn't available from ``SSLError`` to ``ImportError`` (`#2589 <https://github.com/urllib3/urllib3/issues/2589>`__).
* Changed ``HTTPConnection.request()`` to always use lowercase chunk boundaries when sending requests with ``Transfer-Encoding: chunked`` (`#2515 <https://github.com/urllib3/urllib3/issues/2515>`__).
* Changed `enforce_content_length` default to True, preventing silent data loss when reading streamed responses (`#2514 <https://github.com/urllib3/urllib3/issues/2514>`__).
@@ -97,6 +96,7 @@ Changed
Deprecated
----------
+* Deprecated ``HTTPResponse.getheaders()`` and ``HTTPResponse.getheader()`` which will be removed in urllib3 v2.1.0. Instead use ``HTTPResponse.headers`` and ``HTTPResponse.headers.get(name, default)``. (`#1543 <https://github.com/urllib3/urllib3/issues/1543>`__, `#2814 <https://github.com/urllib3/urllib3/issues/2814>`__).
* Deprecated ``urllib3.contrib.pyopenssl`` module which will be removed in urllib3 v2.1.0 (`#2691 <https://github.com/urllib3/urllib3/issues/2691>`__).
* Deprecated ``urllib3.contrib.securetransport`` module which will be removed in urllib3 v2.1.0 (`#2692 <https://github.com/urllib3/urllib3/issues/2692>`__).
* Deprecated ``ssl_version`` option in favor of ``ssl_minimum_version``. ``ssl_version`` will be removed in urllib3 v2.1.0 (`#2110 <https://github.com/urllib3/urllib3/issues/2110>`__).

MODIFY
docs/v2-migration-guide.rst
docs/v2-migration-guide.rst
@@ -49,6 +49,8 @@ Here's a short summary of which changes in urllib3 v2.0 are most important:
- Removed the ``urllib3.contrib.ntlmpool`` module.
- Deprecated the ``urllib3.contrib.pyopenssl``, ``urllib3.contrib.securetransport`` modules, will be removed in v2.1.0.
- Deprecated the ``urllib3[secure]`` extra, will be removed in v2.1.0.
+- Deprecated the ``HTTPResponse.getheaders()`` method in favor of ``HTTPResponse.headers``, will be removed in v2.1.0.
+- Deprecated the ``HTTPResponse.getheader(name, default)`` method in favor of ``HTTPResponse.headers.get(name, default)``, will be removed in v2.1.0.
- Changed the default minimum TLS version to TLS 1.2 (previously was TLS 1.0).
- Removed support for verifying certificate hostnames via ``commonName``, now only ``subjectAltName`` is used.
- Removed the default set of TLS ciphers, instead now urllib3 uses the list of ciphers configured by the system.

MODIFY
src/urllib3/connectionpool.py
src/urllib3/connectionpool.py
@@ -926,7 +926,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
)
# Check if we should retry the HTTP response.
- has_retry_after = bool(response.getheader("Retry-After"))
+ has_retry_after = bool(response.headers.get("Retry-After"))
if retries.is_retry(method, response.status, has_retry_after):
try:
retries = retries.increment(method, url, response=response, _pool=self)

MODIFY
src/urllib3/response.py
src/urllib3/response.py
@@ -4,6 +4,7 @@ import json as _json
import logging
import re
import sys
+import warnings
import zlib
from contextlib import contextmanager
from http.client import HTTPMessage as _HttplibHTTPMessage
@@ -471,10 +472,22 @@ class BaseHTTPResponse(io.IOBase):
return len(temp)
# Compatibility methods for http.client.HTTPResponse
- def getheaders(self) -> List[Tuple[str, str]]:
- return list(self.headers.items())
+ def getheaders(self) -> HTTPHeaderDict:
+ warnings.warn(
+ "HTTPResponse.getheaders() is deprecated and will be removed "
+ "in urllib3 v2.1.0. Instead access HTTResponse.headers directly.",
+ category=DeprecationWarning,
+ stacklevel=2,
+ )
+ return self.headers
def getheader(self, name: str, default: Optional[str] = None) -> Optional[str]:
+ warnings.warn(
+ "HTTPResponse.getheader() is deprecated and will be removed "
+ "in urllib3 v2.1.0. Instead use HTTResponse.headers.get(name, default).",
+ category=DeprecationWarning,
+ stacklevel=2,
+ )
return self.headers.get(name, default)
# Compatibility method for http.cookiejar

MODIFY
src/urllib3/util/retry.py
src/urllib3/util/retry.py
@@ -318,7 +318,7 @@ class Retry:
def get_retry_after(self, response: "BaseHTTPResponse") -> Optional[float]:
"""Get the value of Retry-After in seconds."""
- retry_after = response.getheader("Retry-After")
+ retry_after = response.headers.get("Retry-After")
if retry_after is None:
return None

MODIFY
test/test_response.py
test/test_response.py
@@ -112,11 +112,19 @@ class TestLegacyResponse:
def test_getheaders(self) -> None:
headers = {"host": "example.com"}
r = HTTPResponse(headers=headers)
+ with pytest.warns(
+ DeprecationWarning,
+ match=r"HTTPResponse.getheaders\(\) is deprecated",
+ ):
assert r.getheaders() == [("host", "example.com")]
def test_getheader(self) -> None:
headers = {"host": "example.com"}
r = HTTPResponse(headers=headers)
+ with pytest.warns(
+ DeprecationWarning,
+ match=r"HTTPResponse.getheader\(\) is deprecated",
+ ):
assert r.getheader("host") == "example.com"

Restore but deprecate HTTPResponse.getheaders() and .getheader() methods