Skip to content

Commit

Permalink
Detect a Windows console handle correctly using GetConsoleMode
Browse files Browse the repository at this point in the history
isatty returns True for the NUL device on Windows. So use GetConsoleMode instead to detect
a console handle.

See https://bugs.python.org/issue28654

Fixes #1065
  • Loading branch information
segevfiner authored and davidism committed Feb 16, 2020
1 parent b919ce7 commit 3f49ec2
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 7 deletions.
11 changes: 6 additions & 5 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,25 @@ Version 7.1
Unreleased

- Fix PyPI package name, "click" is lowercase again.
- Add ``no_args_is_help`` option to ``click.Command``, defaults to
False :pr:`1167`
- Fix link in ``unicode_literals`` error message. :pr:`1151`
- Add support for colored output on UNIX Jupyter notebooks.
:issue:`1185`
- Remove unused compat shim for ``bytes``. :pr:`1195`
- Expand testing around termui, especially getchar on Windows.
:issue:`1116`
- Fix output on Windows Python 2.7 built with MSVC 14. :pr:`1342`
- Always return one of the passed choices for ``click.Choice``
:issue:`1277`, :pr:`1318`
- Fix ``OSError`` when running in MSYS2. :issue:`1338`
- Fix ``OSError`` when redirecting to ``NUL`` stream on Windows.
:issue:`1065`
- Fix error in new AppEngine environments. :issue:`1462`
- Always return one of the passed choices for ``click.Choice``
:issue:`1277`, :pr:`1318`
- Add ``no_args_is_help`` option to ``click.Command``, defaults to
False :pr:`1167`
- Add ``show_defaults`` parameter to ``Context`` to enable showing
defaults globally. :issue:`1018`



Version 7.0
-----------

Expand Down
18 changes: 16 additions & 2 deletions click/_winconsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
PyBuffer_Release = pythonapi.PyBuffer_Release
except ImportError:
pythonapi = None
from ctypes.wintypes import LPWSTR, LPCWSTR, HANDLE
from ctypes.wintypes import DWORD, LPWSTR, LPCWSTR, HANDLE


c_ssize_p = POINTER(c_ssize_t)
Expand All @@ -33,6 +33,7 @@
GetStdHandle = kernel32.GetStdHandle
ReadConsoleW = kernel32.ReadConsoleW
WriteConsoleW = kernel32.WriteConsoleW
GetConsoleMode = kernel32.GetConsoleMode
GetLastError = kernel32.GetLastError
GetCommandLineW = WINFUNCTYPE(LPWSTR)(
('GetCommandLineW', windll.kernel32))
Expand Down Expand Up @@ -287,11 +288,24 @@ def _get_windows_argv():
}


def _is_console(f):
if not hasattr(f, 'fileno'):
return False

try:
fileno = f.fileno()
except OSError:
return False

handle = msvcrt.get_osfhandle(fileno)
return bool(GetConsoleMode(handle, byref(DWORD())))


def _get_windows_console_stream(f, encoding, errors):
if get_buffer is not None and \
encoding in ('utf-16-le', None) \
and errors in ('strict', None) and \
hasattr(f, 'isatty') and f.isatty():
_is_console(f):
func = _stream_factories.get(f.fileno())
if func is not None:
if not PY2:
Expand Down

0 comments on commit 3f49ec2

Please sign in to comment.