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

Windows pyinstaller EXE - _curses.error: lost sys.stdout #25

Open
C0rn3j opened this issue Dec 27, 2024 · 8 comments
Open

Windows pyinstaller EXE - _curses.error: lost sys.stdout #25

C0rn3j opened this issue Dec 27, 2024 · 8 comments

Comments

@C0rn3j
Copy link

C0rn3j commented Dec 27, 2024

Attempting to import the library within Windows EXE opened by double clicking, created by pyinstaller, I get the following:

Traceback (most recent call last):
  File "tauon/t_modules/t_main.py", line 348, in <module>
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "PyInstaller/loader/pyimod02_importers.py", line 384, in exec_module
  File "colored_traceback/always/__init__.py", line 2, in <module>
  File "colored_traceback/colored_traceback.py", line 78, in add_hook
  File "colored_traceback/colored_traceback.py", line 64, in __init__
  File "colored_traceback/colored_traceback.py", line 38, in _determine_formatter
  File "colored_traceback/colored_traceback.py", line 34, in _get_term_color_support
_curses.error: lost sys.stdout

Seems to me this function could use a sys.platform check instead?

def _get_term_color_support():
try:
import curses
except ImportError:
# Probably Windows, which doesn't have great curses support
return 16
curses.setupterm()
return curses.tigetnum('colors')

The app in question is Tauon and current commits at the time - Taiko2k/Tauon@c2420e2 - has a prebuilt Windows binary with the issue.

I also previously managed to land on this but no clue how to repro at the moment, so that could just be some pyinstaller issue or an issue on my end:

(t_main.py:351)
Traceback (most recent call last):
  File "C:/msys64/home/Yeet/Tauon/.venv/lib/python3.12/site-packages/tauon/t_modules/t_main.py", line 346, in <module>
    import colored_traceback.always
  File "C:/msys64/home/Yeet/Tauon/.venv/lib/python3.12/site-packages/colored_traceback/always/__init__.py", line 2, in <module>
    add_hook(always=True)
  File "C:/msys64/home/Yeet/Tauon/.venv/lib/python3.12/site-packages/colored_traceback/colored_traceback.py", line 78, in add_hook
    colorizer = Colorizer(style, colors, debug)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:/msys64/home/Yeet/Tauon/.venv/lib/python3.12/site-packages/colored_traceback/colored_traceback.py", line 64, in __init__
    self.formatter = _determine_formatter(style, colors, debug)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:/msys64/home/Yeet/Tauon/.venv/lib/python3.12/site-packages/colored_traceback/colored_traceback.py", line 38, in _determine_formatter
    colors = colors or _get_term_color_support()
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:/msys64/home/Yeet/Tauon/.venv/lib/python3.12/site-packages/colored_traceback/colored_traceback.py", line 34, in _get_term_color_support
    curses.setupterm()
_curses.error: setupterm: could not find terminfo database
@staticshock
Copy link
Owner

Hm, "lost sys.stdout" sounds vaguely like the stream got closed by whatever process owned it? What interface is even rendering your stdout in that case? Is it something terminal-like, or is it a windows installer output window?

As far as the second error, does this reproduce it: C:/msys64/home/Yeet/Tauon/.venv/Scripts/python.exe -c 'import curses; curses.setupterm()'

@C0rn3j
Copy link
Author

C0rn3j commented Dec 27, 2024

What interface is even rendering your stdout in that case?

I have no idea, I just doubleclick the EXE there

@C0rn3j
Copy link
Author

C0rn3j commented Jan 5, 2025

As for stdout, it seems to be caused by not checking whether stdout exists before trying to use it.

https://pyinstaller.org/en/stable/common-issues-and-pitfalls.html#sys-stdin-sys-stdout-and-sys-stderr-in-noconsole-windowed-applications-windows-only

@staticshock
Copy link
Owner

Adding a platform check seems bad. I'd rather test for specific functionality, if possible. I see two main issues here that are worth addressing:

  1. This package uses stderr throughout, but curses defaults to probing stdout under the hood. That's an unhealthy mismatch, fixable via curses.setupterm(fd=sys.stderr.fileno()).
  2. stdout as well as stderr are likely auto-closed immediately when you double-click on a PyInstaller file. Here's a reproduction of your error in a sterile environment:
$ python -c 'import sys; sys.stderr.close(); print(sys.stderr.fileno())'
object address  : 0x104372800
object refcount : 2
object type     : 0x104a49bc8
object type name: ValueError
object repr     : ValueError('I/O operation on closed file')
lost sys.stderr

Also reproducible via the test script:

$ python -c 'import sys; sys.stderr.close(); import test'
object address  : 0x100b09600
object refcount : 2
object type     : 0x100fd9bc8
object type name: ValueError
object repr     : ValueError('I/O operation on closed file')
lost sys.stderr

@C0rn3j
Copy link
Author

C0rn3j commented Jan 6, 2025

The docs suggest to check if stderr and stdout are available, not to do a platform check:

if sys.stdout is None:
    ...
if sys.stderr is None:
    ...

Though it does look like it would be only necessary to check on Windows.

@staticshock
Copy link
Owner

Which docs is this from?

@C0rn3j
Copy link
Author

C0rn3j commented Jan 6, 2025

The one I linked in the comment you replied to - #25 (comment)

image

@staticshock
Copy link
Owner

Haha, ok, yeah, so I guess the code should check for both a closed stream and a nulled out stream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants