bczsalba / pytermgui

Python TUI framework with mouse support, modular widget system, customizable and rapid terminal markup language and more!
https://ptg.bczsalba.com
MIT License
2.21k stars 54 forks source link

[BUG] `getch` in `_get_pixel_size` hangs when terminal doesn't have the feature implemented #42

Closed meson800 closed 2 years ago

meson800 commented 2 years ago

Describe the bug Calling import pytermgui spawns a Terminal; on Windows terminals (tested: Windows Terminal, Powershell, and the built-in VS Code terminal), the Terminal constructor attempts to call _get_pixel_size after sending the (ignored) ANSI terminal command [14t, to which Windows terminals do not respond. The resulting getch call blocks until a key is pressed.

To Reproduce Steps to reproduce the behavior:

  1. On Windows, start any Python file containing import pytermgui, within Powershell or Windows Terminal.
  2. Further Python code does not run until you push any key, which causes the getch call to return (and set pixel size = (0,0) due to it not finding a ;).

Expected behavior On terminals that don't support ANSI terminal commands, don't hang trying to get pixel size.

Screenshots If applicable, add screenshots to help explain your problem.

System information

PyTermGUI v3.2.1

Python: 3.9.4
Platform: Windows-10-10.0.19041-SP0

Possible solution Is it sufficient to add an additional check to get_chars (line 135 in input.py) that checks msvcrt.kbhit() prior to any getch call, and returns an empty buffer if kbhit returns false?

jonnieey commented 2 years ago

Still getting this behavior arch linux.

ptg --version
PyTermGUI v4.3.0

Python: 3.10.4
Platform: Linux-5.16.14-arch1-1-x86_64-with-glibc2.35

even running ptg --version or python setup.py install it's blocked and you have to press a key for it to run.

bczsalba commented 2 years ago

No idea what might be going on there. Could you run something, and while it's waiting for a key interrupt (CTRL_C) the process?

Also, which terminal emulator are you using?

jonnieey commented 2 years ago

I'm using st (simple terminal from suckless) and this is the output after pressing CTRL_C

> ptg
Traceback (most recent call last):
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/input.py", line 362, in getch
    key = _getch()
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/input.py", line 105, in __call__
    buff = "".join(self.get_chars())
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/input.py", line 93, in get_chars
    yield self._read(1)
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/input.py", line 73, in _read
    char = os.read(sys.stdin.fileno(), 1)
KeyboardInterrupt

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/kamikaze/.virtualenvs/pytermgui/bin/ptg", line 33, in <module>
    sys.exit(load_entry_point('pytermgui==4.3.0', 'console_scripts', 'ptg')())
  File "/home/kamikaze/.virtualenvs/pytermgui/bin/ptg", line 25, in importlib_load_entry_point
    return next(matches).load()
  File "/usr/lib/python3.10/importlib/metadata/__init__.py", line 171, in load
    module = import_module(match.group('module'))
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/__init__.py", line 21, in <module>
    from .parser import *
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/parser.py", line 120, in <module>
    from .terminal import terminal
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/terminal.py", line 443, in <module>
    terminal = Terminal()
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/terminal.py", line 224, in __init__
    self.pixel_size: tuple[int, int] = self._get_pixel_size()
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/terminal.py", line 242, in _get_pixel_size
    output = getch()[4:-1]
  File "/home/kamikaze/.virtualenvs/pytermgui/lib/python3.10/site-packages/pytermgui-4.3.0-py3.10.egg/pytermgui/input.py", line 372, in getch
    raise KeyboardInterrupt("Unhandled interrupt") from error
KeyboardInterrupt: Unhandled interrupt
bczsalba commented 2 years ago

Hmm, interesting. Do other terminals also exhibit the behaviour?

jonnieey commented 2 years ago

urxvt and it works fine.

bczsalba commented 2 years ago

Odd. Could it maybe be an st issue then? I tried running it on both Gnome Terminal and Kitty on Linux and both ran just fine as well.

jonnieey commented 2 years ago

I also tried maui-kit station terminal and it seems to have the same issue. Other terminal that i've tried (urxvt and xterm) worked well. I think it could be a terminal issue.

bczsalba commented 2 years ago

I guess they might be missing the ability to report terminal pixel dimensions. I think I have a fix in mind for this, though it involves a feature introduced in the compositor branch, so I might need to port it over.

The new feature is the new getch_timeout function, which calls getch but applies some timeout under which a result has to come in. We could do a tiny timeout (enough for the terminal to respond, not enough for the user to notice), and just return a default size of some resolution.

bczsalba commented 2 years ago

It's also worth noting that AFAIK (or remember) this specific functionality is currently only used for SVG exports, and was originally implemented as a preparatory step for Image support. A feature which is still yet to come to fruition, since I decided on focusing on quality of life and stability instead of flashy things that ultimately suffer from a slow compositor.