Skip to content

IDLE displays ANSI sequences in tracebacks when sys.excepthook is customized #127060

Closed

Description

@vstinner

Error on Python 3.13 and newer.

Reproducer

  • Run IDLE
  • Set a custom sys.excepthook:
import sys
def hook(*args): return sys.__excepthook__(*args)
sys.excepthook=hook
  • Trigger an error which display a traceback, such as accessing a variable which doesn't exist.

Output

>>> os
Traceback (most recent call last):
  File �[35m"/home/vstinner/python/3.13/Lib/idlelib/run.py"�[0m, line �[35m590�[0m, in �[35mruncode�[0m
    �[31mexec�[0m�[1;31m(code, self.locals)�[0m
    �[31m~~~~�[0m�[1;31m^^^^^^^^^^^^^^^^^^^�[0m
  File �[35m"<pyshell#12>"�[0m, line �[35m1�[0m, in �[35m<module>�[0m
�[1;35mNameError�[0m: �[35mname 'os' is not defined. Did you forget to import 'os'?�[0m

ANSI sequences to colorize the output are unexpected and makes the output hard to read.

Expected output

>>> os
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    os
NameError: name 'os' is not defined. Did you forget to import 'os'?

Explanation

In the normal case:

  • IDLE replaces sys.stderr with io.StringIO() to call the "excepthook".
  • _colorize.can_colorize() returns False.
  • It works as expected.

If sys.excepthook is overridden:

  • IDLE replaces sys.stderr with a idlelib.run.StdOutputFile object at startup.
  • _colorize.can_colorize() returns True because StdOutputFile.isatty() always return True.

Linked PRs

Activity

  1. added a commit that references this issue on Nov 20, 2024
  2. changed the title [-][IDLE] IDLE displays ANSI sequences in tracebacks when sys.excepthook is customized[/-] [+]IDLE displays ANSI sequences in tracebacks when sys.excepthook is customized[/+] on Nov 20, 2024
  3. terryjreedy commented on Nov 20, 2024

    @terryjreedy
    Member

    On Windows, 3.14.0a1 install or fresh build, I do not see this when running from editor.

    Traceback (most recent call last):
      File "f:\dev\3x\Lib\idlelib\run.py", line 590, in runcode
        exec(code, self.locals)
        ~~~~^^^^^^^^^^^^^^^^^^^
      File "F:\dev\tem\tem.py", line 4, in <module>
        os
    NameError: name 'os' is not defined. Did you forget to import 'os'?

    After entering at prompt, the only differences are that the file is <pyshell#3> and os is missing. In CommandPrompt, the escape code highlighting (and the OS line) is present.

    I do see the code on macOS, so I presume you are using mac or linux.

    IDLE normally calls print_exception, which call a function to rid tracebacks of IDLE artifacts. When sys.excepthook is changed from sys.__excepthook__, the custom hook has to do this if desired. hook does not, hence the extra lines.

    The absence of interactive code lines, such as os was part of the default sys.__excepthook__ before 3.13. Python does not cache them. IDLE normally adds them and the new REPL does also.

    I have thought about converting ~/^ to highlights. Since those lines might eventually go away when duplicated by inline markup, I have recently also thought of using the latter instead. It would be disappointing if that were not available on Windows.

    IDLE always replaces the run process stderr with StdOutputfile. Normally, print_exception is called. After printing the traceback created by python while stderr is bound to an StdOutput file, it calls get_message_line to get SomeException: <message line>. For Attribute and Name errors, it temporarily replaces stderr to get the 'Did you mean' hints. (When hints are added for other exception classes, they should be added to the list.) This temporary replacement cannot affect the presence of color codes in the traceback itself.

    The sys.stdxxx bindings are visible to user code. Changing an attribute might break the intended behavior of existing code.

  4. added
    type-bugAn unexpected behavior, bug, or error
    stdlibStandard Library Python modules in the Lib/ directory
    on Nov 21, 2024
  5. vstinner commented on Nov 21, 2024

    @vstinner
    MemberAuthor

    I do see the code on macOS, so I presume you are using mac or linux.

    Right, I'm on Linux. I expected the behavior to be the same on Windows.

    On Fedora, the ABRT service installs a custom sys.excepthook using a PTH file (.pth) to catch Python unhandled exceptions and report them to Bugzilla bug tracker.

    So this IDLE bug is always reproduced on Fedora without having to install a custom excepthook manually, see: https://bugzilla.redhat.com/show_bug.cgi?id=2325502

  6. vstinner commented on Nov 21, 2024

    @vstinner
    MemberAuthor

    I expected the behavior to be the same on Windows.

    Oh, I forgot that on Windows Python doesn't use ANSI sequences, but control directly the console using the Windows API. So right, Windows is not affected by this issue.

  7. vstinner commented on Nov 25, 2024

    @vstinner
    MemberAuthor

    The sys.stdxxx bindings are visible to user code. Changing an attribute might break the intended behavior of existing code.

    What's the purpose of pretending that sys.stdout and sys.stderr are TTY, whereas they are not?

  8. vstinner commented on Nov 27, 2024

    @vstinner
    MemberAuthor
  9. vstinner commented on Dec 16, 2024

    @vstinner
    MemberAuthor

    @terryjreedy: So you don't like my simple #127061 approach? It does fix the issue for me. Do you have access to Linux or macOS to reproduce the issue?

  10. terryjreedy commented on Dec 17, 2024

    @terryjreedy
    Member

    I will try to test on my Mac tomorrow. And maybe get setup to do so on Ubuntu. (I have it on a partition on Windows, which my daughter used, but have not yet done anything with it myself.) I need to be able to create and download/run PRs on both other systems.

  11. terryjreedy commented on Dec 17, 2024

    @terryjreedy
    Member

    I am a bit worried that changing isatty could break something. I can grep idlelib to check locally, but 3rd party code might be accessing sys.stdxxx.isatty. As I said above, this seems like a public interface.

    Besides this, I would like to revise IDLE to recognize the code and add highlights. This would require switching back. Now that Hugh made it (supposedly, not yet tested) possible to request color codes on Windows, I will be more motivated to do so.

    A different temporary fix would by to filter out color codes. If I can get them on Windows, I can work on that immediately on my Windows machine. (This would be the first step in using them anyway.) Besides familiarily, my main Windows machine is by far the best ergonomically.

  12. terryjreedy commented on Dec 17, 2024

    @terryjreedy
    Member

    isatty()

    Return True if the stream is interactive (i.e., connected to a terminal/tty device).
    

    To me, this means that one can use s = input("Prompt: ") and expect someone to read the prompt and respond. This is true when connected to IDLE's shell, so I consider the current code to be correct, and hence prefer a different solution.

  13. terryjreedy commented on Dec 17, 2024

    @terryjreedy
    Member

    Since Hugo has started adding color codes to other output (unittest and something else so far), perhaps all stderr output should be filtered, not just Tracebacks. I would not want to filter stdout, as users might want to test sending ansi codes. It might be better to change the environment setting on startup, as long as this only affects IDLE and its subprocesses.

  14. serhiy-storchaka commented on Dec 17, 2024

    @serhiy-storchaka
    Member

    Why not simply set the TERM environment variable to "idle" or whatever? Not all terminals support ANSI sequences, IDLE is the one that does not support.

    Later we can implement support of ANSI sequences in IDLE.

  15. added 2 commits that reference this issue on Dec 17, 2024
  16. vstinner commented on Dec 17, 2024

    @vstinner
    MemberAuthor

    Why not simply set the TERM environment variable to "idle" or whatever?

    Good idea: I wrote PR gh-128028 to fix this issue.

  17. terryjreedy commented on Dec 18, 2024

    @terryjreedy
    Member

    TERM is set in pyshell line 427. Should move to init when do other cleanups. Can easily change if needed.

  18. moved this to In Progress in IDLE Issueson Dec 18, 2024
  19. added a commit that references this issue on Dec 18, 2024
  20. added a commit that references this issue on Dec 18, 2024
  21. added a commit that references this issue on Dec 18, 2024
  22. moved this from In Progress to Done in IDLE Issueson Dec 18, 2024
  23. added a commit that references this issue on Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13only security fixes3.14bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-IDLEtype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions