]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-141570: can_colorize: Expect fileno() to raise OSError, as documented (#141716)
authorMiro Hrončok <miro@hroncok.cz>
Wed, 19 Nov 2025 14:02:52 +0000 (15:02 +0100)
committerGitHub <noreply@github.com>
Wed, 19 Nov 2025 14:02:52 +0000 (15:02 +0100)
In Fedora, we've been given a slightly incomplete reproducer for a problematic
Python 3.14 color-related change in argparse that leads to an exception when
Python is used from mod_wsgi: https://bugzilla.redhat.com/2414940

mod_wsgi replaces sys.stdout with a custom object that raises OSError on .fileno():

https://github.com/GrahamDumpleton/mod_wsgi/blob/8460dbfcd5c7108892b3cde9fab7cbc1caa27886/src/server/wsgi_logger.c#L434-L440

This should be supported, as the documentation of fileno explicitly says:

> An OSError is raised if the IO object does not use a file descriptor.

https://docs.python.org/3.14/library/io.html#io.IOBase.fileno

The previously expected exception inherits from OSError,
so it is still expected.

Fixes https://github.com/python/cpython/issues/141570

Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
Lib/_colorize.py
Lib/test/test__colorize.py
Misc/NEWS.d/next/Library/2025-11-18-14-39-31.gh-issue-141570.q3n984.rst [new file with mode: 0644]

index 57b712bc068d4e18e23a08039b15c8608acd0b01..7d573274328826853494a3cf50cba69610c0e7bf 100644 (file)
@@ -1,4 +1,3 @@
-import io
 import os
 import sys
 
@@ -330,7 +329,7 @@ def can_colorize(*, file: IO[str] | IO[bytes] | None = None) -> bool:
 
     try:
         return os.isatty(file.fileno())
-    except io.UnsupportedOperation:
+    except OSError:
         return hasattr(file, "isatty") and file.isatty()
 
 
index 25012466840f18f73c571b76faf36d238cc6d7a0..67e0595943d35695aea14b302504e0bfefdbb5dd 100644 (file)
@@ -166,6 +166,17 @@ class TestColorizeFunction(unittest.TestCase):
                 file.isatty.return_value = False
                 self.assertEqual(_colorize.can_colorize(file=file), False)
 
+            # The documentation for file.fileno says:
+            # > An OSError is raised if the IO object does not use a file descriptor.
+            # gh-141570: Check OSError is caught and handled
+            with unittest.mock.patch("os.isatty", side_effect=ZeroDivisionError):
+                file = unittest.mock.MagicMock()
+                file.fileno.side_effect = OSError
+                file.isatty.return_value = True
+                self.assertEqual(_colorize.can_colorize(file=file), True)
+                file.isatty.return_value = False
+                self.assertEqual(_colorize.can_colorize(file=file), False)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2025-11-18-14-39-31.gh-issue-141570.q3n984.rst b/Misc/NEWS.d/next/Library/2025-11-18-14-39-31.gh-issue-141570.q3n984.rst
new file mode 100644 (file)
index 0000000..8f4641c
--- /dev/null
@@ -0,0 +1,2 @@
+Support :term:`file-like object` raising :exc:`OSError` from :meth:`~io.IOBase.fileno` in color
+detection (``_colorize.can_colorize()``). This can occur when ``sys.stdout`` is redirected.