PySimpleGUI / PySimpleGUI

Python GUIs for Humans! PySimpleGUI is the top-rated Python application development environment. Launched in 2018 and actively developed, maintained, and supported in 2024. Transforms tkinter, Qt, WxPython, and Remi into a simple, intuitive, and fun experience for both hobbyists and expert users.

Home Page:https://www.PySimpleGUI.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[ Bug ] print() to stdout with reroute_stdout=True, echo_stdout_stderr=True and reroute_stdout_to_here() hangs PySimpleGUI

wrwetzel opened this issue · comments

Type of Issue (Enhancement, Error, Bug, Question)

Bug


Operating System

Linux Paganini 5.17.3-arch1-1 #1 SMP PREEMPT Thu, 14 Apr 2022 01:18:36 +0000 x86_64 GNU/Linux

PySimpleGUI Port (tkinter, Qt, Wx, Web)

Tkinter


Versions

Python version: 3.10.4 (main, Mar 23 2022, 23:05:40) [GCC 11.2.0]
port: tkinter
tkinter version: 8.6.12
PySimpleGUI version: 4.60.0
PySimpleGUI filename: /usr/lib/python3.10/site-packages/PySimpleGUI/PySimpleGUI.py

Version information can be obtained by calling sg.main_get_debug_data()
Or you can print each version shown in ()

Python version (sg.sys.version)

PySimpleGUI Version (sg.__version__)

GUI Version (tkinter (sg.tclversion_detailed), PySide2, WxPython, Remi)


Your Experience In Months or Years (optional)

55+ years

Years Python programming experience
12+ years

Years Programming experience overall
55+ years

Have used another Python GUI Framework? (tkinter, Qt, etc) (yes/no is fine)
tkinter, Qt

Anything else you think would be helpful?


Troubleshooting

These items may solve your problem. Please check those you've done by changing - [ ] to - [X]

  • [x ] Searched main docs for your problem www.PySimpleGUI.org
  • Looked for Demo Programs that are similar to your goal Demos.PySimpleGUI.org
  • If not tkinter - looked for Demo Programs for specific port
  • For non tkinter - Looked at readme for your specific port if not PySimpleGUI (Qt, WX, Remi)
  • [x ] Run your program outside of your debugger (from a command line)
  • [x ] Searched through Issues (open and closed) to see if already reported Issues.PySimpleGUI.org
  • Tried using the PySimpleGUI.py file on GitHub. Your problem may have already been fixed but not released

Detailed Description

Through an error in the structure of my program, which I freely acknowledge is of my own doing, under certain circumstances I called reroute_stdout_to_here() on a Multiline() element when I had already enabled (set True) 'reroute_stdout' and 'echo_stdout_stderr' in the Multiline() options.

Under those conditions a print() causes PySimpleGUI to hang, which can only be resolved by killing the test program process.
If any of those conditions is absent the program works fine, as expected.

I strongly suggest (as this took me over a day to isolate) that PySimpleGui should not hang. Instead it should either post a nastygram or just ignore the condition.

This appears to be a situation that changed between 4.57 and 4.60 as the hang only appeared when I upgraded to 4.60 (at least as best as I can recall).

Code To Duplicate

A short program that isolates and demonstrates the problem (Do not paste your massive program, but instead 10-20 lines that clearly show the problem)

This pre-formatted code block is all set for you to paste in your bit of code:

#!/usr/bin/python
# ----------------------------------------------------------------
#   WRW 18 May 2022 - This program demonstrates a rough edge in PySimpleGUI
#       arising from a bug of my own where I called reroute_stdout_to_here()
#       when also enabling rerouting in the Multiline() options.

#   I believe that it should fail gracefully and not hang or even better,
#       just ignore the multiple enables.

#   It hangs displaying the output from the print() statement and must
#       be killed externally.

#   Works fine:
#       reroute_stdout_to_here() is not called (ReRoute = False)
#    or
#       Multiline() echo_stdout_stderr = False
#    or
#       Multiline() reroute_stdout = False

# ----------------------------------------------------------------

import PySimpleGUI as sg

def do_test():

    # ----------------------------------------------------------------

    build_text = \
        sg.Multiline( default_text='',
                key='build-text',
                write_only = True,
                auto_refresh = True,
                size=(120, 40),
                autoscroll = True,
                echo_stdout_stderr = True,
                reroute_stdout = True
        )

    button_close = sg.Button('Close', key='build-button-close' )

    build_layout = [ [ build_text ], [button_close] ]

    build_window = sg.Window( 'Build Table',
                        finalize = True,
                        layout=build_layout,
                       )

    # ----------------------------------------------------------------

    ReRoute = True

    if ReRoute:
        build_window[ 'build-text' ].reroute_stdout_to_here()                                                

    for i in range(1, 10):
        print( 'hello there' * i )

    if ReRoute:
        build_window[ 'build-text' ].restore_stdout()

    # ----------------------------------------
    #   Event loop for build window

    while True:
        event, values = build_window.Read( )
        if event == sg.WINDOW_CLOSED:
            break

        if event == 'build-button-close':
            build_window.close()
            break

# --------------------------------------------------------------------------

do_test()

Screenshot, Sketch, or Drawing


Watcha Makin?

Birdland is a Linux-based multimedia music viewer and library manager for music books in PDF form including fakebooks. It displays a page of music or a ChordPro song by searching a database of titles and other metadata. Answering the Let's hear how it goes query it also suggests audio files, midi files, JJazzLab songs and YouTube links matching the search.

A secondary feature of Birdland is index management. Birdland contains tools to quickly create indexes using OCR, harmonize indexes from disparate sources, compare them, and integrate them into one database. Birdland ships with index data from 9 sources covering over 100 books and over 20,000 titles. Users can edit existing indexes and add their own.

Options and method of Multiline element

  • Option reroute_stdout call method reroute_stdout_to_here to write to Multiline element.
  • Option echo_stdout_stderr set method write to append text to Multiline element and also write text to previous sys.stdout
def write(self):
    self.update(txt, append=True)
    self.previous_stdout.write(txt)
  • Method reroute_stdout_to_here keep the value of sys.stdout in self.previous_stdout and set it to Multiline element.
def reroute_stdout_to_here(self):
    self.previous_stdout = sys.stdout
    sys.stdout = self

In your code,

  1. Set reroute_stdout=True will keep Python default stdout <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'> to self.previous_stdout, and set stdout to this Multiline element by call method reroute_stdout_to_here first time. So print text to console will be transferred to this Multiline.
  2. text transferred will be append to Multiline element by call method write of Multiline element.
  3. Set echo_stdout_stderr=True will write text to self.previous_stdout which is python default sys,stdout now, so text will also print to console.
  4. All above options fine, then you call method reroute_stdout_to_here again, self.previous_stdout will be Multiline element, not the python default sys.stdout. It means PySimpleGUI/tkinter will call method write which will also call method write itself recursively. That's why it hangs PySimpleGUI.

Not sure if it clear for you now, you cannot call reroute_stdout_to_here again after you set reroute_stdout=True and echo_stdout_stderr=True.

ReRoute = True

# if ReRoute:
#    build_window[ 'build-text' ].reroute_stdout_to_here()

for i in range(1, 10):
    print( 'hello there' * i+'\n')

if ReRoute:
    build_window[ 'build-text' ].restore_stdout()

image

Note: There should be a good way to avoid user's wrong call, or need to know much detail about the redirect of stdout and stderr.

Too much mixing of parms and methods. Choose one way of doing it. I'm sure I could have done a better job of protecting users from doing sequences that cause problems. There is error checking in PySimpleGUI, it just doesn't cover 100% of the cases... maybe 70% are detected and reported.

Perhaps not enough info in the Cookbook, Demo Programs, Call Reference, etc to explain the Design Patterns that are suggested and safe. The way I develop is to demonstrate good paths assuming others will follow.

Jason, as always, thanks very much for your quick response and detailed explanation of the cause of the hang. I suspected some sort of recursion once I isolated the problem. I agree with your comment on error checking - there is just so much that sensibly possible. But I strongly suggest that there should be a comment in the Call Reference for reroute options AND the reroute_*_to_hear() methods warning to use only one and the consequences of a hang if ignored.

Thanks again,
Bill