python / cpython

The Python programming language
https://www.python.org
Other
63.73k stars 30.53k forks source link

Windows: Python not using ANSI compatible console #73245

Closed bcbc7f46-9bda-4dee-9991-9ca4a02bafe9 closed 7 years ago

bcbc7f46-9bda-4dee-9991-9ca4a02bafe9 commented 7 years ago
BPO 29059
Nosy @terryjreedy, @pfmoore, @tjguk, @methane, @zware, @eryksun, @zooba, @jhasapp
Files
  • issue29059.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields: ```python assignee = None closed_at = created_at = labels = ['type-feature', '3.7', 'OS-windows'] title = 'Windows: Python not using ANSI compatible console' updated_at = user = 'https://github.com/jhasapp' ``` bugs.python.org fields: ```python activity = actor = 'terry.reedy' assignee = 'none' closed = True closed_date = closer = 'steve.dower' components = ['Windows'] creation = creator = 'joseph.hackman' dependencies = [] files = ['46060'] hgrepos = [] issue_num = 29059 keywords = ['patch'] message_count = 13.0 messages = ['283913', '283979', '283982', '283998', '283999', '284153', '284178', '284220', '284363', '284365', '284369', '284459', '292084'] nosy_count = 9.0 nosy_names = ['terry.reedy', 'paul.moore', 'tim.golden', 'v+python', 'methane', 'zach.ware', 'eryksun', 'steve.dower', 'joseph.hackman'] pr_nums = [] priority = 'normal' resolution = 'rejected' stage = 'resolved' status = 'closed' superseder = None type = 'enhancement' url = 'https://bugs.python.org/issue29059' versions = ['Python 3.7'] ```

    bcbc7f46-9bda-4dee-9991-9ca4a02bafe9 commented 7 years ago

    On windows, Python does not request that Windows enable VT100 for console output for Python.

    That is to say that ANSI codes such as \033[91m will function on Mac and Linux Pythons, but not Windows.

    As there is no good interface in core Python to the kernel32 console operations (and there probably shouldn't be, it would be better to be consistent), I suggest just flipping the bit at startup on Windows.

    I would be happy to submit a patch, but seek guidance on the best location for addition of code to 'at startup iff a tty is attached'.

    The following code solves the issue: import platform if platform.system().lower() == 'windows': from ctypes import windll, c_int, byref stdout_handle = windll.kernel32.GetStdHandle(c_int(-11)) mode = c_int(0) windll.kernel32.GetConsoleMode(c_int(stdout_handle), byref(mode)) mode = c_int(mode.value | 4) windll.kernel32.SetConsoleMode(c_int(stdout_handle), mode)

    Please see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx (Search for ENABLE_VIRTUAL_TERMINAL_PROCESSING) https://msdn.microsoft.com/en-us/library/windows/desktop/ms683231(v=vs.85).aspx (As for why stdout is -11 on Windows)

    methane commented 7 years ago

    Is it a global state, or application specific state? In other words, if Python enables VT100, doesn't it remain after os._exit(1)?

    If it is global state of console, why Python should change it? Shouldn't user who want to use VT100 enable it before starting Python?

    bcbc7f46-9bda-4dee-9991-9ca4a02bafe9 commented 7 years ago

    The flag is application specific. I.e. a python program that writes to console using ansi codes, when used on windows, will just display the codes. If the Output is redireced to file and then the file is printed to console using a console tool, the colors will show instead.

    zooba commented 7 years ago

    Great suggestion. If someone is willing to contribute the work then we can consider it for 3.7.

    If you need this functionality sooner, either ctypes or colorama should allow you to use it on existing releases.

    zooba commented 7 years ago

    Oh, and it should go in the WinConsoleIO class, needs to be written in C, and probably needs a short PEP explaining why it has to be on by default and can't be turned on by programs that need it. I'm sure the discussion will lead to other ideas as well (perhaps posting on python-ideas is a good start? Though there may not be a lot of discussion for a Windows-centric suggestion like this.)

    bcbc7f46-9bda-4dee-9991-9ca4a02bafe9 commented 7 years ago

    Thanks for the tip! If you hadn't said that, I probably would have written it into the init scripts.

    I'll try to write something for python-ideas / PEP tomorrow, but have attached a quick patch here so I can link to this issue for an example implementation.

    zooba commented 7 years ago

    Sounds good. Don't focus on ease of implementation, BTW. The post and eventual PEP need to cover the benefits, risks and alternatives more than anything else.

    eryksun commented 7 years ago

    As there is no good interface in core Python to the kernel32 console operations (and there probably shouldn't be, it would be better to be consistent), I suggest just flipping the bit at startup on Windows.

    I don't follow your statement about consistency. Python could adopt a built-in wincon module to partially support the console API, just like winreg partially supports the registry API.

    When _WindowsConsoleIO was being developed, I mentioned the idea of enabling VT mode a couple of times, but there was no interest that I could see. I don't think Windows devs really care much about this feature, especially since it's only available in Windows 10. colorama has been the popular way to get cross-platform support for supporting text color in terminals and the Windows console. There's also pyreadline, which supports VT escapes and much more. Enabling the console's VT mode won't simplify the implementation of colorama or pyreadline so long as Windows 7 and 8 are supported, which will be for several more years.

    One problem with enabling VT mode at startup is that it could cause compatibility problems with child processes. cmd faced this problem and has since resolved it 1 by reverting to the original console mode before executing a program. If Python enables VT mode at startup, there should be a sys variable (based on a C global) that has the original mode value. Applications would be able to restore the original mode to either opt out entirely or before executing a child process. Py_FinalizeEx would also have to be modified to restore the original mode before shutting down the interpreter.

    b5a9ce10-d67f-478f-ab78-b08d099eb753 commented 7 years ago

    Nice idea, but not by default. An easy way to switch back and forth, and to be sure the original mode is restored on process exit would be a win.

    Most windows users want a real GUI, not curses, but compatibility with VT escape codes for cross-platform semi-GUI stuff could be useful... and could enable the stdlib curses to be included in Python for windows also? I'm not sure why it isn't, and "ANSI" a.k.a. VT escape codes have been available in Windows for a long time... but until Python 3.6.0 (thanks again Steve, and others), Windows console handling in Python has been extremely limited.

    Also note that UniCurses and Pygcurse exist and provide similar capabilities.

    zooba commented 7 years ago

    I suspect curses could be updated to fully support Windows, even without the VT100 mode (all the functionality has existed for years, just through a different interface). It really just needs someone to take on the project, and there are already better options out there (I forget the name, but the IPython team are very happy with whatever library they're using these days), so possibly it's more of an awareness problem that doesn't need to be solved in the core distro.

    b5a9ce10-d67f-478f-ab78-b08d099eb753 commented 7 years ago

    Re: curses... maybe that becomes a DOCS issue, to mention the available packages. But it would be easier, no doubt to port curses to a known existing escape sequence control set, than to use a bunch arcane, foreign-to-the-Unix-porter-that-wants-curses obscure and seldom discussed Windows APIs.

    IIRC, ANSI is somewhat incompatible with sending random binary gibberish to the screen, as people accidentally do with TYPE sometimes :) But the random binary gibberish may contain ANSI control sequences... That's why I'm negative on making it a default.

    zooba commented 7 years ago

    IIRC, ANSI is somewhat incompatible with sending random binary gibberish to the screen, as people accidentally do with TYPE sometimes :) But the random binary gibberish may contain ANSI control sequences... That's why I'm negative on making it a default.

    I don't actually know how big a deal this would be. I seem to get identical results from "print(''.join(chr(x) for x in range(32)))" both with and without the VT100 flag set, though of course "print('\033[91m')" behaves differently.

    But given "on by default" isn't popular, and "off by default" implies adding new public API that is already available either as a short ctypes snippet or a number of 3rd-party libraries, I think we should consider this rejected.

    For future reference, the python-ideas thread starts with https://mail.python.org/pipermail/python-ideas/2016-December/044033.html

    terryjreedy commented 7 years ago

    In bpo-30075, Tithen Firion reports that "subprocess.call('', shell=True)" leaves the console in ANSI mode. In Eryk Sun says that this is likely a bug in cmd.exe and gives improved code for putting the console in VT mode, when this is possible. I closed that issue as a duplicate of this.