Release 3.30. New PySimpleGUIdebugger release to PyPI

This commit is contained in:
MikeTheWatchGuy 2019-05-24 21:04:15 -04:00
parent bf762e12b9
commit 7348cb67ba
8 changed files with 527 additions and 309 deletions

View file

@ -0,0 +1,42 @@
import PySimpleGUI as sg
import PySimpleGUIdebugger
"""
Demo program that shows you how to integrate the PySimpleGUI Debugger
into your program.
There are THREE steps, and they are copy and pastes.
1. At the top of your app to debug add
import PySimpleGUIdebugger
2. Initialize the debugger by calling:
PySimpleGUIdebugger.initialize()
2. At the top of your app's event loop add
PySimpleGUIdebugger.refresh(locals(), globals())
"""
PySimpleGUIdebugger.initialize()
layout = [
[sg.T('A typical PSG application')],
[sg.In(key='_IN_')],
[sg.T(' ', key='_OUT_')],
[sg.Radio('a',1, key='_R1_'), sg.Radio('b',1, key='_R2_'), sg.Radio('c',1, key='_R3_')],
[sg.Combo(['c1', 'c2', 'c3'], size=(6,3), key='_COMBO_')],
[sg.Output(size=(50,6))],
[sg.Ok(), sg.Exit()],
]
window = sg.Window('This is your Application Window', layout)
window.Element('_OUT_').Update(background_color='red')
# Variables that we'll use to demonstrate the debugger's features
counter = 0
timeout = 100
while True: # Event Loop
PySimpleGUIdebugger.refresh(locals(), globals()) # call the debugger to refresh the items being shown
event, values = window.Read(timeout=timeout)
if event in (None, 'Exit'):
break
elif event == 'Ok':
print('You clicked Ok.... this is where print output goes')
counter += 1
window.Element('_OUT_').Update(values['_IN_'])

View file

@ -0,0 +1,125 @@
import subprocess
import sys
import PySimpleGUI as sg
"""
The Offiicial Unofficiall official PySimpleGUI debug tool
Not calling it a debugger, but it is also quite a step up from "print statemements"
"""
PSGDebugLogo = b'R0lGODlhMgAtAPcAAAAAADD/2akK/4yz0pSxyZWyy5u3zZ24zpW30pG52J250J+60aC60KS90aDC3a3E163F2K3F2bPI2bvO3rzP3qvJ4LHN4rnR5P/zuf/zuv/0vP/0vsDS38XZ6cnb6f/xw//zwv/yxf/1w//zyP/1yf/2zP/3z//30wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAyAC0AAAj/AP8JHEiwoMGDCBMqXMiwoUOFAiJGXBigYoAPDxlK3CigwUGLIAOEyIiQI8cCBUOqJFnQpEkGA1XKZPlPgkuXBATK3JmRws2bB3TuXNmQw8+jQoeCbHj0qIGkSgNobNoUqlKIVJs++BfV4oiEWalaHVpyosCwJidw7Sr1YMQFBDn+y4qSbUW3AiDElXiWqoK1bPEKGLixr1jAXQ9GuGn4sN22Bl02roo4Kla+c8OOJbsQM9rNPJlORlr5asbPpTk/RP2YJGu7rjWnDm2RIQLZrSt3zgp6ZmqwmkHAng3ccWDEMe8Kpnw8JEHlkXnPdh6SxHPILaU/dp60LFUP07dfRq5aYntohAO0m+c+nvT6pVMPZ3jv8AJu8xktyNbw+ATJDtKFBx9NlA20gWU0DVQBYwZhsJMICRrkwEYJJGRCSBtEqGGCAQEAOw=='
COLOR_SCHEME = 'LightGreen'
WIDTH_VARIABLES = 12
WIDTH_RESULTS = 36
# done purely for testing / show
def func(x=''):
return f'return value from func()={x}'
def _init():
global watcher_window
sg.ChangeLookAndFeel(COLOR_SCHEME)
def InVar(key1, key2):
row1 = [sg.T(' '),
sg.I(key=key1, size=(WIDTH_VARIABLES,1)),
sg.T('',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.T('',key=key2 + 'CHANGED_', size=(WIDTH_RESULTS, 1)), sg.B('Detail', key=key2+'DETAIL_'),]
return row1
variables_frame = [ InVar('_VAR1_', '_VAR2_'),
InVar('_VAR3_', '_VAR4_'),
InVar('_VAR5_', '_VAR6_'),]
interactive_frame = [[sg.T('>>> '), sg.In(size=(83,1), key='_INTERACTIVE_'), sg.B('Go', bind_return_key=True, visible=False)],
[sg.Multiline(size=(88,12),key='_OUTPUT_',autoscroll=True, do_not_clear=True)],]
layout = [ [sg.Frame('Variables or Expressions to Watch', variables_frame, )],
[sg.Frame('REPL-Light', interactive_frame,)],
[sg.Button('Exit')]]
window = sg.Window('PySimpleGUI Debugger', layout, icon=PSGDebugLogo).Finalize()
window.Element('_INTERACTIVE_').SetFocus()
watcher_window = window
sg.ChangeLookAndFeel('SystemDefault')
return window
def _event_once(_window, mylocals, myglobals):
_window = watcher_window
global myrc
_event, _values = _window.Read(timeout=100)
if _event in (None, 'Exit'):
return False
cmd = _values['_INTERACTIVE_']
if _event == 'Run':
_runCommand(cmd=cmd, window=_window)
elif _event == 'Go':
_window.Element('_INTERACTIVE_').Update('')
_window.Element('_OUTPUT_').Update(">>> {}\n".format(cmd), append=True, autoscroll=True)
expression = """
global myrc
PSGdebugger.myrc = {} """.format(cmd)
try:
exec(expression, myglobals, mylocals)
_window.Element('_OUTPUT_').Update('{}\n'.format(myrc),append=True, autoscroll=True)
except Exception as e:
_window.Element('_OUTPUT_').Update('Exception {}\n'.format(e),append=True, autoscroll=True)
elif _event.endswith('_DETAIL_'):
expression = """
global myrc
PSGdebugger.myrc = {} """.format(_values[f'_VAR{_event[4]}_'])
try:
exec(expression, myglobals, mylocals)
sg.PopupScrolled(myrc)
except:
print('Detail failed')
# -------------------- Process the "watch list" ------------------
for i in range(1, 7):
key = f'_VAR{i}_'
out_key = f'_VAR{i}_CHANGED_'
myrc =''
if _window.Element(key):
if _values[key]:
expression = """
global myrc
PSGdebugger.myrc = {} """.format(_values[key])
try:
exec(expression, myglobals, mylocals)
except Exception as e:
pass
_window.Element(out_key).Update(myrc)
else:
_window.Element(out_key).Update('')
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)
def refresh(locals, globals):
global watcher_window
_event_once(watcher_window, locals, globals)
myrc = ''
watcher_window = _init()

View file

@ -0,0 +1,121 @@
![pysimplegui_logo](https://user-images.githubusercontent.com/13696193/43165867-fe02e3b2-8f62-11e8-9fd0-cc7c86b11772.png)
![Downloads](http://pepy.tech/badge/pysimpleguidebugger)
# PySimpleGUIdebugger
PySimpleGUI now has it's own built-in, sorta, debugger.
What you can do with this "debugger" is:
* Set "watch points" that update in realtime
* Write expressions that update in realtime
* Use a REPL style prompt to type in "code" / modify variables
All of this is done using a window secondary and separate from your primary application window.
Check out this video as a guide. The user's window is the smaller one one top. The PySimpleGUIdebugger is the green window on the buttom. You can watch variables, evaluate expressions, even xecute code.
![PSG Debugger2](https://user-images.githubusercontent.com/13696193/58362085-3ead8f00-7e61-11e9-9439-e77e9a059dbc.gif)
## Installation
Installation is via pip:
`pip install PySimpleGUIdebugger`
or if you need to upgrade later:
`pip install --upgrade --no-cache-dir PySimpleGUIdebugger`
Should this not work, you can copy and paste the file PySimpleGUIdebugger.py into your application folder.
## Integrating PySimpleGUIdebugger Into Your Application
There are 3 lines of code to add to a PySimpleGUI program in order to make it debugger ready - The import, an initialization, once each time through the even loop.
Here is an entire program including this integration code:
```python
import PySimpleGUI as sg
import PySimpleGUIdebugger
"""
Demo program that shows you how to integrate the PySimpleGUI Debugger
into your program.
There are THREE steps, and they are copy and pastes.
1. At the top of your app to debug add
import PySimpleGUIdebugger
2. Initialize the debugger by calling:
PySimpleGUIdebugger.initialize()
2. At the top of your app's event loop add
PySimpleGUIdebugger.refresh(locals(), globals())
"""
PySimpleGUIdebugger.initialize()
layout = [
[sg.T('A typical PSG application')],
[sg.In(key='_IN_')],
[sg.T(' ', key='_OUT_')],
[sg.Radio('a',1, key='_R1_'), sg.Radio('b',1, key='_R2_'), sg.Radio('c',1, key='_R3_')],
[sg.Combo(['c1', 'c2', 'c3'], size=(6,3), key='_COMBO_')],
[sg.Output(size=(50,6))],
[sg.Ok(), sg.Exit()],
]
window = sg.Window('This is your Application Window', layout)
window.Element('_OUT_').Update(background_color='red')
# Variables that we'll use to demonstrate the debugger's features
counter = 0
timeout = 100
while True: # Event Loop
PySimpleGUIdebugger.refresh(locals(), globals()) # call the debugger to refresh the items being shown
event, values = window.Read(timeout=timeout)
if event in (None, 'Exit'):
break
elif event == 'Ok':
print('You clicked Ok.... this is where print output goes')
counter += 1
window.Element('_OUT_').Update(values['_IN_'])
```
## Using PySimpleGUIdebugger
To use the debugger in your code you will need to add TWO lines of code:
The import at the top of your code:
`import PySimpleGUIdebugger`
You need to "initialize" the PySimpleGUIdebugger package by calling near the top of your code. This is what creates the debugger window:
`PySimpleGUIdebugger.initialize()`
This "refresh" call that must be added to your event loop. Your `window.Read` call should have a timeout value so that it does not block. If you do not have a timeout value, the debugger will not update in realtime.
Add this line to the top of your event loop.
`PySimpleGUIdebugger.refresh(locals(), globals())`
## Requirements
You'll need to have PySimpleGUI installed.
The debugger itself is written using PySimpleGUI, the tkinter version. It could be changed to use Qt for example.
## What's it good for, when should it be used??
Hell if I know. Maybe it's a terrible idea! Or, maybe it'll be really helpful, particularly in situations where you don't have many resources on the target system and perhaps you can't fit a debugger onto that system. PySimpleGUIdebugger provides another tool for your PySimpleGUI GUI Toolbox.
# Design
# Author
Mike B.
# License
GNU Lesser General Public License (LGPL 3) +