Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide pass-through ANSI on Windows 10 powershell #133

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 40 additions & 2 deletions colorama/ansitowin32.py
Expand Up @@ -21,6 +21,35 @@ def is_a_tty(stream):
return hasattr(stream, 'isatty') and stream.isatty()


def check_windows_ansi_support():
try:
import winreg
except ImportError:
try:
import _winreg # on Python 2
except ImportError:
return False
else:
winreg = _winreg

# Check the registry for release ID
key = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion"
val = r"ReleaseID"
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use try finally (It is a context manager since 2.6 but I think colorama still declares compatibility with Python 2.5).

releaseId = int(winreg.QueryValueEx(key,val)[0])
winreg.CloseKey(key)

# Windows 10 supports ANSI cmd since release 1511
if releaseId >= 1511:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably need to check that this is Windows 10 too, I'm not sure ReleaseID isn't used in previous versions of Windows. l Windows since 8.1 has a nasty habit of lying about it's version though. I think platform.win32_ver() does work around that but be sure to check (sys.getwindowsversion doesn't workaround this at least on Python 2.7.13 so you get the version of Windows 8).

# but only on powershell
import psutil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this isn't really related to powershell but to the ENABLE_VIRTUAL_TERMINAL_PROCESSING flag. colorama should enable this flag when supported and restore it's previous value on exit.

I think we can simply try to SetConsoleMode(h, GetConsoleMode(h) | ENABLE_VIRTUAL_TERMINAL_PROCESSING) to check for support of this (Need to be sure the stream is a tty/console before calling {Get,Set}ConsoleMode). I think it fails with INVALID_ARGUMENT when unsupported. But this needs some testing.

See: #133 (comment) & https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx

python_pid = psutil.Process(os.getpid())
shell_pid = psutil.Process(python_pid.ppid())
return shell_pid.name() == 'powershell.exe'
else:
return False


class StreamWrapper(object):
'''
Wraps a stream (such as stdout), acting as a transparent proxy for all
Expand Down Expand Up @@ -69,14 +98,23 @@ def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
# to support the ANSI codes.
conversion_supported = on_windows and winapi_test()

# Does this version of Win 10 support ANSI?
windows_ansi_support = on_windows and check_windows_ansi_support()

# should we strip ANSI sequences from our output?
if strip is None:
strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped))
if windows_ansi_support:
strip = False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need to check that the stream isn't closed and is a tty otherwise we will skip stripping ansi codes with redirected output. Be careful, all those boolean conditions are quite confusing.

else:
strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped))
self.strip = strip

# should we should convert ANSI sequences into win32 calls?
if convert is None:
convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped)
if windows_ansi_support:
convert = False
else:
convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped)
self.convert = convert

# dict of ansi codes to win32 functions and parameters
Expand Down
5 changes: 4 additions & 1 deletion setup.py
Expand Up @@ -64,6 +64,9 @@ def get_version(path):
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Terminals',
]
],
extras_require={
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation is messed up.

':sys_platform=="win32"': ['psutil'],
},
)