How to detect that stdio was redirected to nul?
Question:
I’m developing a package to fix several issues with Unicode in Python run in standard Windows console environment: https://github.com/Drekin/win-unicode-console. The key operation is to replace the standard stream objects when needed. For this I need to detect whether the standard streams were redirected or not. Python method isatty()
works OK with one exception: If a stream was redirected to nul
, then isatty()
returns True
.
My question is how to detect whether a Windows handle leads to a console or to nul
? Is there a WinAPI function for that?
Answers:
The C runtime’s _isatty
function returns true for files that access character devices, i.e. files for which GetFileType
returns FILE_TYPE_CHAR
. To detect a console handle in particular you can call GetConsoleMode
. This call fails for a non-console handle. To get the underlying Windows handle to pass to this function, call msvcrt.get_osfhandle
. For example:
import ctypes
import msvcrt
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
ERROR_INVALID_HANDLE = 6
def is_console(file_descriptor):
handle = msvcrt.get_osfhandle(file_descriptor)
if kernel32.GetConsoleMode(handle, ctypes.byref(ctypes.c_uint())):
return True
last_error = ctypes.get_last_error()
if last_error != ERROR_INVALID_HANDLE:
raise ctypes.WinError(last_error)
return False
I’m developing a package to fix several issues with Unicode in Python run in standard Windows console environment: https://github.com/Drekin/win-unicode-console. The key operation is to replace the standard stream objects when needed. For this I need to detect whether the standard streams were redirected or not. Python method isatty()
works OK with one exception: If a stream was redirected to nul
, then isatty()
returns True
.
My question is how to detect whether a Windows handle leads to a console or to nul
? Is there a WinAPI function for that?
The C runtime’s _isatty
function returns true for files that access character devices, i.e. files for which GetFileType
returns FILE_TYPE_CHAR
. To detect a console handle in particular you can call GetConsoleMode
. This call fails for a non-console handle. To get the underlying Windows handle to pass to this function, call msvcrt.get_osfhandle
. For example:
import ctypes
import msvcrt
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
ERROR_INVALID_HANDLE = 6
def is_console(file_descriptor):
handle = msvcrt.get_osfhandle(file_descriptor)
if kernel32.GetConsoleMode(handle, ctypes.byref(ctypes.c_uint())):
return True
last_error = ctypes.get_last_error()
if last_error != ERROR_INVALID_HANDLE:
raise ctypes.WinError(last_error)
return False