diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index d2fd111f6d9de02..b93408f20901f9f 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 @@ -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 660301fef612588..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.info() + 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.code, response.msg, response.info() + 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.code < 300: + if 200 <= _get_status(response) < 300: self.passwd.update_authenticated(req.full_url, True) else: self.passwd.update_authenticated(req.full_url, False) @@ -1339,8 +1359,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 fec00c1b272f4ea..c26fb064d4a4244 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1301,6 +1301,7 @@ Dustin J. Mitchell Gideon Mitchell Tim Mitchell Zubin Mithra +Alexandr Mitin Florian Mladitsch Kevin Modzelewski Doug Moen 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..46c06f009f4150a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-18-04-47-39.gh-issue-123503.mfg0wD.rst @@ -0,0 +1,6 @@ +Replace usages of deprecated attributes :attr:`addinfourl.code +` and :meth:`HTTPResponse.info +` with their recommended equivalents +(:attr:`addinfourl.status ` and +:attr:`HTTPResponse.headers `), +while retaining backwards compatibility.