From aaa02956adae3fd102fcaf60e0d0f13cffb4ea21 Mon Sep 17 00:00:00 2001 From: Alexandr Mitin Date: Fri, 18 Apr 2025 10:41:17 +0600 Subject: [PATCH 1/7] Updated to the latest version --- Lib/test/test_urllib2.py | 2 +- Lib/urllib/request.py | 7 +++---- Misc/ACKS | 1 + 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 7d7f2fa00d35b62..798da7e7fa9cd33 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -300,7 +300,7 @@ def getheaders(self, name): class MockResponse(io.StringIO): def __init__(self, code, msg, headers, data, url=None): io.StringIO.__init__(self, data) - self.code, self.msg, self.headers, self.url = code, msg, headers, url + self.status, self.msg, self.headers, self.url = code, msg, headers, url def info(self): return self.headers diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 9a6b29a90a29682..ae3af488dee1e9a 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -210,7 +210,7 @@ def urlretrieve(url, filename=None, reporthook=None, data=None): url_type, path = _splittype(url) with contextlib.closing(urlopen(url, data)) as fp: - headers = fp.info() + headers = fp.headers # Just return the local path and the "headers" for file:// # URLs. No sense in performing a copy unless requested. @@ -594,7 +594,7 @@ class HTTPErrorProcessor(BaseHandler): handler_order = 1000 # after all other processing def http_response(self, request, response): - code, msg, hdrs = response.code, response.msg, response.info() + code, msg, hdrs = response.status, response.msg, response.headers # According to RFC 2616, "2xx" code indicates that the client's # request was successfully received, understood, and accepted. @@ -1338,8 +1338,7 @@ def do_open(self, http_class, req, **http_conn_args): # This line replaces the .msg attribute of the HTTPResponse # with .headers, because urllib clients expect the response to # have the reason in .msg. It would be good to mark this - # attribute is deprecated and get then to use info() or - # .headers. + # attribute is deprecated and get then to use .headers. r.msg = r.reason return r diff --git a/Misc/ACKS b/Misc/ACKS index 25542d01de695c7..713c3e12b2cd5a1 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1270,6 +1270,7 @@ Dustin J. Mitchell Gideon Mitchell Tim Mitchell Zubin Mithra +Alexandr Mitin Florian Mladitsch Kevin Modzelewski Doug Moen From f70ac9916900da8abcca8257f4d2bbf891051122 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 04:47:41 +0000 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst diff --git a/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst new file mode 100644 index 000000000000000..dbd7b8b3b474c43 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst @@ -0,0 +1 @@ +Deprecated attributes urllib.response.addinfourl.status and http.client.HTTPResponse.info() have been replaced with their modern equivalents (HTTPResponse.headers) while maintaining backwards-compatibility. From 32848afc6ed90fd2804c3c00ce6e0c5939374cd8 Mon Sep 17 00:00:00 2001 From: Alexandr Mitin <64941904+Alexandr153@users.noreply.github.com> Date: Fri, 18 Apr 2025 11:27:01 +0600 Subject: [PATCH 3/7] Update request.py --- Lib/urllib/request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index ae3af488dee1e9a..a51716915db2635 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1006,7 +1006,7 @@ def http_request(self, req): def http_response(self, req, response): if hasattr(self.passwd, 'is_authenticated'): - if 200 <= response.code < 300: + if 200 <= response.status < 300: self.passwd.update_authenticated(req.full_url, True) else: self.passwd.update_authenticated(req.full_url, False) From 23030bdc893fcf2ad4fcc4b6b6bb7fdca9b0df60 Mon Sep 17 00:00:00 2001 From: Alexandr Mitin <64941904+Alexandr153@users.noreply.github.com> Date: Fri, 18 Apr 2025 17:00:31 +0600 Subject: [PATCH 4/7] Update Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst index dbd7b8b3b474c43..05066dc621b1292 100644 --- a/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst +++ b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst @@ -1 +1,6 @@ -Deprecated attributes urllib.response.addinfourl.status and http.client.HTTPResponse.info() have been replaced with their modern equivalents (HTTPResponse.headers) while maintaining backwards-compatibility. +Subsitute internal usages of deprecated attributes :attr:`addinfourl.code +` and :meth:`HTTPResponse.info +` for their recommended equivalents +(:attr:`addinfourl.status ` and +:attr::`HTTPResponse.headers `), +while retaining backwards compatibility. From 31302e779f9d4febf468cb7f1ff0c492d05dab75 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 18 Apr 2025 14:30:02 +0300 Subject: [PATCH 5/7] Update 2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst --- .../next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst index 05066dc621b1292..44f0a60dc5bfdcf 100644 --- a/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst +++ b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst @@ -2,5 +2,5 @@ Subsitute internal usages of deprecated attributes :attr:`addinfourl.code ` and :meth:`HTTPResponse.info ` for their recommended equivalents (:attr:`addinfourl.status ` and -:attr::`HTTPResponse.headers `), +:attr:`HTTPResponse.headers `), while retaining backwards compatibility. From e77098513ba77ee46970e15c63775f39728e039b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 19 Apr 2025 01:55:20 +0200 Subject: [PATCH 6/7] Update Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst Co-authored-by: Martin Panter --- .../Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst index 44f0a60dc5bfdcf..46c06f009f4150a 100644 --- a/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst +++ b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst @@ -1,6 +1,6 @@ -Subsitute internal usages of deprecated attributes :attr:`addinfourl.code +Replace usages of deprecated attributes :attr:`addinfourl.code ` and :meth:`HTTPResponse.info -` for their recommended equivalents +` with their recommended equivalents (:attr:`addinfourl.status ` and :attr:`HTTPResponse.headers `), while retaining backwards compatibility. From 992437df688d9d670bf3611a529e72aa3b18f72b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 11 Aug 2026 16:36:48 +0300 Subject: [PATCH 7/7] Accept response objects which only provide the deprecated attributes --- Lib/test/test_urllib2.py | 23 +++++++++++++++++++++++ Lib/urllib/request.py | 26 +++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index e16b80f104e5b3f..b93408f20901f9f 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -309,6 +309,21 @@ def geturl(self): return self.url +class MockLegacyResponse(io.StringIO): + # A response object written before the status attribute and the headers + # attribute were added in 3.9 (gh-123503). + def __init__(self, code, msg, headers, data, url=None): + io.StringIO.__init__(self, data) + self.code, self.msg, self.url = code, msg, url + self._headers = headers + + def info(self): + return self._headers + + def geturl(self): + return self.url + + class MockCookieJar: def add_cookie_header(self, request): self.ach_req = request @@ -1230,6 +1245,14 @@ def test_fixpath_in_weirdurls(self): self.assertEqual(newreq.selector, '') def test_errors(self): + self._test_errors(MockResponse) + + def test_errors_legacy_response(self): + # A response object providing only the attributes deprecated in 3.9 + # is still accepted (gh-123503). + self._test_errors(MockLegacyResponse) + + def _test_errors(self, MockResponse): h = urllib.request.HTTPErrorProcessor() o = h.parent = MockOpener() diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 72aa07d14ee71f4..c88c958f1c9c31b 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -190,6 +190,24 @@ def install_opener(opener): global _opener _opener = opener +def _get_status(response): + # Handlers can return any response object, and one written before the + # status attribute was added in 3.9 only provides the deprecated code + # attribute (gh-123503). + try: + return response.status + except AttributeError: + return response.code + + +def _get_headers(response): + # Likewise, such a response only provides the deprecated info() method. + try: + return response.headers + except AttributeError: + return response.info() + + _url_tempfiles = [] def urlretrieve(url, filename=None, reporthook=None, data=None): """ @@ -210,7 +228,7 @@ def urlretrieve(url, filename=None, reporthook=None, data=None): url_type, path = _splittype(url) with contextlib.closing(urlopen(url, data)) as fp: - headers = fp.headers + headers = _get_headers(fp) # Just return the local path and the "headers" for file:// # URLs. No sense in performing a copy unless requested. @@ -596,7 +614,9 @@ class HTTPErrorProcessor(BaseHandler): handler_order = 1000 # after all other processing def http_response(self, request, response): - code, msg, hdrs = response.status, response.msg, response.headers + code = _get_status(response) + msg = response.msg + hdrs = _get_headers(response) # According to RFC 2616, "2xx" code indicates that the client's # request was successfully received, understood, and accepted. @@ -1008,7 +1028,7 @@ def http_request(self, req): def http_response(self, req, response): if hasattr(self.passwd, 'is_authenticated'): - if 200 <= response.status < 300: + if 200 <= _get_status(response) < 300: self.passwd.update_authenticated(req.full_url, True) else: self.passwd.update_authenticated(req.full_url, False)