From 8f939ebd91a1c6420f653377b16dfb142fb1878a Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Mon, 20 May 2019 11:16:59 -0400 Subject: [PATCH 1/2] New Demo Program - GUI interface to REPL + Watch list for variables and expressions --- ...emo_Python_REPL_Variable_Watches_In_GUI.py | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py diff --git a/DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py b/DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py new file mode 100644 index 00000000..318c93b4 --- /dev/null +++ b/DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py @@ -0,0 +1,117 @@ +import subprocess +import sys +import ast +import copy +import PySimpleGUI as sg + +""" + Python repl with a "watch list" + This Demo Program was created as an answer to a Reddit question. + The idea is to build a Python interpreter >>> prompt, accept command and execute them... and + to also inslude a watcher feature. The "Watched" variables or expressions are constantly updated + as the proram runs. + At the moment, the event loop runs once a second. It could easily be shortened if that's too slow +""" + + +def convertExpr2Expression(Expr): + Expr.lineno = 0 + Expr.col_offset = 0 + result = ast.Expression(Expr.value, lineno=0, col_offset = 0) + + return result + +def exec_with_return(code): + code_ast = ast.parse(code) + + init_ast = copy.deepcopy(code_ast) + init_ast.body = code_ast.body[:-1] + + last_ast = copy.deepcopy(code_ast) + last_ast.body = code_ast.body[-1:] + + exec(compile(init_ast, "", "exec"), globals()) + if type(last_ast.body[0]) == ast.Expr: + return eval(compile(convertExpr2Expression(last_ast.body[0]), "", "eval"),globals()) + else: + exec(compile(last_ast, "", "exec"),globals()) + + +def func(x=''): + return f'return value from func()={x}' + + +def main(): + def InVar(key1, key2): + row1 = [sg.T(''), sg.I(key=key1, size=(18,1)), sg.I(key=key1+'CHANGED_', size=(18,1)), sg.T(' '), + sg.T(''), sg.I(key=key2, size=(18, 1)), sg.I(key=key2 + 'CHANGED_', size=(18, 1))] + return row1 + + variables_frame = [ InVar('_VAR1_', '_VAR2_'), + InVar('_VAR3_', '_VAR4_'), + InVar('_VAR5_', '_VAR6_'),] + + interactive_frame = [[sg.T('>>> '), sg.In(size=(70,1), key='_INTERACTIVE_'), sg.B('Go', bind_return_key=True, visible=False)], + [sg.Output(size=(70,8))],] + + layout = [ + [sg.Frame('Variables or Expressions to Watch', variables_frame)], + [sg.Frame('Interactive REPL', interactive_frame)], + [sg.Button('Exit')]] + + window = sg.Window('Realtime REPL Command Output + Watches', layout).Finalize() + window.Element('_INTERACTIVE_').SetFocus() + event_loop(window) + + +def event_loop(window): + var = 0 + while True: # Event Loop + event, values = window.Read(timeout=1000) + if event in (None, 'Exit'): + break + cmd = values['_INTERACTIVE_'] + if event == 'Run': + runCommand(cmd=cmd, window=window) + elif event == 'Go': + window.Element('_INTERACTIVE_').Update('') + out='' + print(">>> ", cmd) + try: + print(exec_with_return(cmd)) + except Exception as e: + print(f'Exception on output {e}') + # -------------------- Process the "watch list" ------------------ + for i in range(1, 6): + key = f'_VAR{i}_' + out_key = f'_VAR{i}_CHANGED_' + if window.Element(key): + if values[key]: + try: + window.Element(out_key).Update(eval(values[key])) + except: + window.Element(out_key).Update('') + var += 1 + window.Close() + + +def runCommand(cmd, timeout=None, window=None): + """ run shell command + @param cmd: command to execute + @param timeout: timeout for command execution + @param window: the PySimpleGUI window that the output is going to (needed to do refresh on) + @return: (return code from command, command output) + """ + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + output = '' + for line in p.stdout: + line = line.decode(errors='replace' if (sys.version_info) < (3, 5) else 'backslashreplace').rstrip() + output += line + print(line) + window.Refresh() if window else None # yes, a 1-line if, so shoot me + + retval = p.wait(timeout) + return (retval, output) + +main() +print('Exited program....') \ No newline at end of file From a90393643695e5151452de882d405af9d7700265 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Tue, 21 May 2019 15:31:14 -0400 Subject: [PATCH 2/2] A lot of changes for the better! --- ...emo_Python_REPL_Variable_Watches_In_GUI.py | 88 +++++++++++-------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py b/DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py index 318c93b4..c1eb9d7c 100644 --- a/DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py +++ b/DemoPrograms/Demo_Python_REPL_Variable_Watches_In_GUI.py @@ -13,6 +13,8 @@ import PySimpleGUI as sg At the moment, the event loop runs once a second. It could easily be shortened if that's too slow """ +WIDTH_VARIABLES = 12 +WIDTH_RESULTS = 16 def convertExpr2Expression(Expr): Expr.lineno = 0 @@ -41,10 +43,12 @@ def func(x=''): return f'return value from func()={x}' -def main(): +def init(): def InVar(key1, key2): - row1 = [sg.T(''), sg.I(key=key1, size=(18,1)), sg.I(key=key1+'CHANGED_', size=(18,1)), sg.T(' '), - sg.T(''), sg.I(key=key2, size=(18, 1)), sg.I(key=key2 + 'CHANGED_', size=(18, 1))] + row1 = [sg.T(' '), + sg.I(key=key1, size=(WIDTH_VARIABLES,1)), + sg.I(key=key1+'CHANGED_', size=(WIDTH_RESULTS,1)),sg.B('Detail', key=key1+'DETAIL_'), sg.T(' '), + sg.T(' '), sg.I(key=key2, size=(WIDTH_VARIABLES, 1)), sg.I(key=key2 + 'CHANGED_', size=(WIDTH_RESULTS, 1)), sg.B('Detail', key=key2+'DETAIL_'),] return row1 variables_frame = [ InVar('_VAR1_', '_VAR2_'), @@ -54,46 +58,49 @@ def main(): interactive_frame = [[sg.T('>>> '), sg.In(size=(70,1), key='_INTERACTIVE_'), sg.B('Go', bind_return_key=True, visible=False)], [sg.Output(size=(70,8))],] - layout = [ - [sg.Frame('Variables or Expressions to Watch', variables_frame)], + layout = [ [sg.Frame('Variables or Expressions to Watch', variables_frame)], [sg.Frame('Interactive REPL', interactive_frame)], [sg.Button('Exit')]] window = sg.Window('Realtime REPL Command Output + Watches', layout).Finalize() window.Element('_INTERACTIVE_').SetFocus() - event_loop(window) + return window + # event_loop(window) +event_once = lambda window, var=0 : exec(""" -def event_loop(window): - var = 0 - while True: # Event Loop - event, values = window.Read(timeout=1000) - if event in (None, 'Exit'): - break - cmd = values['_INTERACTIVE_'] - if event == 'Run': - runCommand(cmd=cmd, window=window) - elif event == 'Go': - window.Element('_INTERACTIVE_').Update('') - out='' - print(">>> ", cmd) +# while True: # Event Loop +event, values = window.Read(timeout=100) +print(event, values) if event != sg.TIMEOUT_KEY else None +if event in (None, 'Exit'): + False +cmd = values['_INTERACTIVE_'] +if event == 'Run': + runCommand(cmd=cmd, window=window) +elif event == 'Go': + window.Element('_INTERACTIVE_').Update('') + out='' + print(">>> ", cmd) + try: + print(exec_with_return(cmd)) + except Exception as e: + print(f'Exception on output {e}') +elif event.endswith('_DETAIL_'): + try: sg.PopupScrolled(eval(values[f'_VAR{event[4]}_'])) + except: pass +# -------------------- Process the "watch list" ------------------ +for i in range(1, 6): + key = f'_VAR{i}_' + out_key = f'_VAR{i}_CHANGED_' + if window.Element(key): + if values[key]: try: - print(exec_with_return(cmd)) - except Exception as e: - print(f'Exception on output {e}') - # -------------------- Process the "watch list" ------------------ - for i in range(1, 6): - key = f'_VAR{i}_' - out_key = f'_VAR{i}_CHANGED_' - if window.Element(key): - if values[key]: - try: - window.Element(out_key).Update(eval(values[key])) - except: - window.Element(out_key).Update('') - var += 1 - window.Close() - + window.Element(out_key).Update(eval(values[key])) + except: + window.Element(out_key).Update('') +var += 1 +True +""") def runCommand(cmd, timeout=None, window=None): """ run shell command @@ -113,5 +120,12 @@ def runCommand(cmd, timeout=None, window=None): retval = p.wait(timeout) return (retval, output) -main() -print('Exited program....') \ No newline at end of file +if __name__ == '__main__': + window = init() + my_variable=1000 + while True: + event_once(window) + # if not event_once(window): + # break + window.Close() +