https://github.com/python/cpython/commit/0fd00ee1bccde5161b96b2a3cf5a5f14afbe86c4
commit: 0fd00ee1bccde5161b96b2a3cf5a5f14afbe86c4
branch: main
author: Vasiliy Kiryanov <[email protected]>
committer: orsenthil <[email protected]>
date: 2026-11-01T15:04:21Z
summary:

gh-50720: Copy winerror to URLError on Windows (#161047)

files:
M Doc/library/urllib.error.rst
M Lib/test/test_urllib2.py
M Lib/urllib/error.py
M Misc/NEWS.d/next/Library/2026-10-29-20-52-57.gh-issue-50720.Kd1VMR.rst

diff --git a/Doc/library/urllib.error.rst b/Doc/library/urllib.error.rst
index 6a71d4a2ebb6845..0079699e06ca27d 100644
--- a/Doc/library/urllib.error.rst
+++ b/Doc/library/urllib.error.rst
@@ -29,7 +29,8 @@ The following exceptions are raised by :mod:`!urllib.error` 
as appropriate:
 
    .. versionchanged:: 3.16
       The :attr:`~OSError.errno` and :attr:`~OSError.strerror` attributes are
-      now set from :attr:`reason` when it is an :exc:`OSError`.
+      now set from :attr:`reason` when it is an :exc:`OSError`. On Windows,
+      :attr:`~OSError.winerror` is set as well.
 
 
 .. exception:: HTTPError(url, code, msg, hdrs, fp)
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
index 1efc4f5a6280e43..52f77eaf85e589b 100644
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -104,6 +104,16 @@ def request(self, *args, **kwargs):
         self.assertEqual(err.errno, -2)
         self.assertEqual(err.strerror, 'Name or service not known')
 
+    @unittest.skipUnless(sys.platform == "win32", "Windows-specific test")
+    def test_URLError_OSError_attributes_winerror(self):
+        # gh-50720: OSError(errno, strerror, filename, winerror):
+        # on Windows the constructor derives errno from winerror.
+        os_error = OSError(0, "The system cannot find the path specified", 
None, 3)
+
+        err = urllib.error.URLError(os_error)
+        self.assertEqual(err.winerror, 3)
+        self.assertEqual(err.strerror, os_error.strerror)
+
 
 class RequestHdrsTests(unittest.TestCase):
 
diff --git a/Lib/urllib/error.py b/Lib/urllib/error.py
index 5020a60f1ef9bd0..cc9a9254d760f7f 100644
--- a/Lib/urllib/error.py
+++ b/Lib/urllib/error.py
@@ -11,6 +11,7 @@
 response.
 """
 import io
+import sys
 import urllib.response
 
 __all__ = ['URLError', 'HTTPError', 'ContentTooShortError']
@@ -32,6 +33,8 @@ def __init__(self, reason, filename=None):
             # it would have set from the wrapped error (gh-50720).
             self.errno = reason.errno
             self.strerror = reason.strerror
+            if sys.platform == 'win32':
+                self.winerror = reason.winerror
 
     def __str__(self):
         return '<urlopen error %s>' % self.reason
diff --git 
a/Misc/NEWS.d/next/Library/2026-10-29-20-52-57.gh-issue-50720.Kd1VMR.rst 
b/Misc/NEWS.d/next/Library/2026-10-29-20-52-57.gh-issue-50720.Kd1VMR.rst
index ddb4377c3c25987..263b7ac89585769 100644
--- a/Misc/NEWS.d/next/Library/2026-10-29-20-52-57.gh-issue-50720.Kd1VMR.rst
+++ b/Misc/NEWS.d/next/Library/2026-10-29-20-52-57.gh-issue-50720.Kd1VMR.rst
@@ -1,3 +1,4 @@
 :exc:`urllib.error.URLError` now sets the :attr:`~OSError.errno` and
 :attr:`~OSError.strerror` attributes from
-:attr:`~urllib.error.URLError.reason` when it is an :exc:`OSError`.
+:attr:`~urllib.error.URLError.reason` when it is an :exc:`OSError`.  On
+Windows, :attr:`~OSError.winerror` is set as well.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to