Closed dz0 closed 8 years ago
The way I evaluate the code is effectively to do eval(python_code). Brython's eval first transforms the python_code into javascript and then runs it: there is no stepping through the code. When an "atomic" javascript instruction is encountered, such as move(), its result is recorded in a "frame" where I record the entire state of the world at that point. When all the code execution is done, a series of such frames will have been recorded.
So, no stepping of the code takes place, and neither Brython's locals() nor globals() are necessarily available at a given step. If you recall,you can choose either Python or Javascript (or Coffeescript) as programming language.
After this code execution is done, I play back the frames one at a time with a specified time delay. The instruction "think(delay)" can be used in a given frame to change the delay between frames being shown from that point on.
The Python debugger you found looks like something extremely worthwhile to look at ... but it would mean changing significantly the way the program is run (and would likely not be compatible with the Javascript or Coffeescript implementation).
Probably what I call "stepping", is called "line highlighting" in Reeborg.
My idea/hack would be to inject variable "logging" alongside line highlighting
tracecall_name = 'print(list(locals().keys())); RUR.set_lineno_highlight'
Oh, I see ... this makes sense, of course! It's definitely something I will want to explore.
EDIT: narration
(mentioned previously in this comment) has been changed to print_html
; my plan is to enhance print_html.
I could not get something sensible that works. However, I could define a "watch" function, that would need to be called explicitly, and working like the following:
World("Empty")
no_highlight()
think(0)
r = UsedRobot()
def watch(*args):
out = []
for arg in args:
try:
out.append("{}: {}".format(arg, eval(arg)))
except:
pass
print_html("<br>".join(out))
for i in range(3):
move()
watch("r.body.x", "r.body.y", "a")
a = 3
pause(1000)
Perhaps I could create a dialog where the variable to watch are entered; when this is done, then a call to watch() is inserted in the same way I enter the code to highlight lines of code being executed...
Strange issue with locals()
But in their demo env this works ok:
print( locals() )
http://brython.info/tests/editor.html?lang=en Brython version: 3.2.3
but Reeborg uses a bit recent version -- maybe there's some bug? http://cdn.rawgit.com/brython-dev/brython/3c551ae3bf6d29191f7f62bf0d2ce987d70fc340/www/src/brython.js // implementation [3, 2, 4, 'alpha', 0]
ps.: adding watch variables via dialog is also a good way, imo :) even easier to use might be a textbox, where one could list them (add or delete)
On Sat, Dec 5, 2015 at 3:51 PM, André Roberge notifications@github.com wrote:
I could not get something sensible that works. However, I could define a "watch" function, that would need to be called explicitly, and working like the following:
World("Empty") no_highlight() think(0)
r = UsedRobot()def watch(*args): out = [] for arg in args: try: out.append("{}: {}".format(arg, eval(arg))) except: pass narration("
".join(out)) for i in range(3): move() watch("r.body.x", "r.body.y", "a") a = 3 pause(1000)Perhaps I could create a dialog where the variable to watch are entered; when this is done, then a call to watch() is inserted in the same way I enter the code to highlight lines of code being executed...
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162188747.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
The reason why locals() is behaving strangely I suspect is that I run the code using exec(src, some_dict)
inside a function named generic_translation_python which prepopulates some_dict
with some custom-defined functions, instead of a simple exec(src)
which would only use the built-ins.
I should add: Brython's 3.2.3 has bugs which I found and were affecting the way my program was working - which is why I linked to a newer version that had those bugs fixed.
hm, now world.html throws errors,
but in world_old.html I can get list of local vars
print(list(locals().keys()))
On Sat, Dec 5, 2015 at 11:23 PM, André Roberge notifications@github.com wrote:
I should add: Brython's 3.2.3 has bugs which I found and were affecting the way my program was working - which is why I linked to a newer version that had those bugs fixed.
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162249026.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
I have changed the UI for this in two ways: adding placeholder text in the input which, hopefully should be nearly self-explanatory; using only one image/button which is used to toggle the input: if the input is invisible, no variable is watched. The previous "red magnifying glass" could be confusing: does pressing the red button means stop ... or does it mean that something is stopped?
seems nice! :) few notices:
if the input is invisible, no variable is watched. If I toggle textbox to invisible, variables are still watchet/updated..
On Sun, Dec 6, 2015 at 4:52 PM, André Roberge notifications@github.com wrote:
I have changed the UI for this in two ways: adding placeholder text in the input which, hopefully should be nearly self-explanatory; using only one image/button which is used to toggle the input: if the input is invisible, no variable is watched. The previous "red magnifying glass" could be confusing: does pressing the red button means stop ... or does it mean that something is stopped?
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162322034.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
PS.: seems like I managed to get the list of system variables:
system_default_vars = list(locals().keys()) # before the user code
def filter_user_vars( vars ): return set( vars ) - set( system_default_vars )
watch ( filter_user_vars( list(locals().keys()) ) ) # would call watch with just vars from user code...
On Sun, Dec 6, 2015 at 8:26 PM, Jurgis Pralgauskis < jurgis.pralgauskis@gmail.com> wrote:
seems nice! :) few notices:
- print("hi") doesn't seem to work.. probably would be good to have "debug" output alongside "standart output".. Output pane could be split in two parts..?
if the input is invisible, no variable is watched. If I toggle textbox to invisible, variables are still watchet/updated..
On Sun, Dec 6, 2015 at 4:52 PM, André Roberge notifications@github.com wrote:
I have changed the UI for this in two ways: adding placeholder text in the input which, hopefully should be nearly self-explanatory; using only one image/button which is used to toggle the input: if the input is invisible, no variable is watched. The previous "red magnifying glass" could be confusing: does pressing the red button means stop ... or does it mean that something is stopped?
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162322034.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
Fixed broken print. I was trying to be too smart, appending the output of the watch to the previous recorded frame so that they would appear to be kept in sync. However, because both the watch() and the print() used a code of "output" for the frame, the watch appended would effectively replace the print.
I need to fix the toggle so that it works properly.
I'll look at your smart filtering option some time later today.
Thinking about it ... In some ways, I was trying too hard to re-use existing dialog and code. I think I need to create a few more dialogs, and separate out the logic of various parts so that they cannot interfere with each other. I like to give them somewhat descriptive titles, rather than just "debug". Including the current ones, I would have:
Currently, 1, 4, 5 and 6 were all using the same dialog.
I'll look at your smart filtering option some time later today.
Ok, no hurry :)
generally manual input is much flexibler -- as you can watch expressions!
Though one should be carefull if those expressions change the state of world/variables if they use functions .. But I guess nobody would need to watch "move()"
On Sun, Dec 6, 2015 at 8:52 PM, André Roberge notifications@github.com wrote:
Fixed broken print. I was trying to be too smart, appending the output of the watch to the previous recorded frame so that they would appear to be kept in sync. However, because both the watch() and the print() used a code of "output" for the frame, the watch appended would effectively replace the print.
I need to fix the toggle so that it works properly.
I'll look at your smart filtering option some time later today.
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162336663.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
Would be good to track when the watch value changes -- for students to notice it better :)
I tried to patch your code (but haven't tested):
previuos_watch_values = {}
def watch(args, loc={}):
global previuos_watch_values
current_watch_values = {} # collect current values here
out = []
f = "<span class='watch_name'>{}</span>: <span class='watch_value'>{}</span>" # NOQA
changed = "<span class='changed' style='color:red'>{}</span>"
for arg in args:
try:
value = eval(arg, globals(), loc)
current_watch_values[ arg ] = value
out.append(f.format(arg, value))
# if value changed, highlight it (Visual Studio does it in red)
if not arg in previuos_watch_values \
or value != previuos_watch_values[arg] :
out[-1] = changed.format( out[-1] )
except:
pass
window.print_html("<br>".join(out))
previuos_watch_values = current_watch_values # forgets currently unused args
ps.: maybe "watch" should be renamed to "_watch" just in case ..
Reeborg watches (color?): for watching variables
or maybe "Inspects"? and maybe its not Reeborg who watches -- its coder? I like Orange :)
Reeborg explores (color?): for view_source_js ... which is inexplicably not working anymore
Brown (because view'ing code is solid, and brown seems solid for me :)
Reeborg writes fancily (color?): for print_html()
Magenta (because it's fancy :)
On Sun, Dec 6, 2015 at 9:14 PM, André Roberge notifications@github.com wrote:
Thinking about it ... In some ways, I was trying too hard to re-use existing dialog and code. I think I need to create a few more dialogs, and separate out the logic of various parts so that they cannot interfere with each other. I like to give them somewhat descriptive titles, rather than just "debug". Including the current ones, I would have:
- Reeborg writes (blue gradient top bar), showing the output from print
- Reeborg says (green gradient top bar): for positive end of program
- Reeborg shouts (flat red top bar): any error condition, or goal not met
- Reeborg watches (color?): for watching variables
- Reeborg explores (color?): for view_source_js ... which is inexplicably not working anymore
- Reeborg writes fancily (color?): for print_html()
Currently, 1, 4, 5 and 6 were all using the same dialog.
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162337768.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
Watch variable has now a complete implementation that should work properly ... It takes a bit longer to run a program (i.e. to compute each frame before being ready to display). It prompted me to add a __str__
method to the UsedRobot
class. If you create a new robot, you will see the result.
Yahoo! :)
Someday it could integrate PythonTutor, if it can generate its trace format ;) https://github.com/pgbovine/OnlinePythonTutor/blob/master/v3/docs/opt-trace-format.md
On Mon, Dec 7, 2015 at 6:40 AM, André Roberge notifications@github.com wrote:
Watch variable has now a complete implementation that should work properly ... It takes a bit longer to run a program (i.e. to compute each frame before being ready to display). It prompted me to add a str method to the UsedRobot class. If you create a new robot, you will see the result.
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162411204.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
str method to the UsedRobot class
it should probably also include orientation for complete info? and tokens?
On Mon, Dec 7, 2015 at 6:40 AM, André Roberge notifications@github.com wrote:
Watch variable has now a complete implementation that should work properly ... It takes a bit longer to run a program (i.e. to compute each frame before being ready to display). It prompted me to add a str method to the UsedRobot class. If you create a new robot, you will see the result.
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162411204.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
for watch not to have delay, we probably can use
locals()[arg]
instead of eval?
eval would be usefull for expressions, for example when using lists with indexes: A[i] so textbox could be left with hint: expr1, expr2
but this can be left for next weekend :)
if I use some name, which is reserved, it is not shown in watch-list
ex.: vars = [10, 5]
On Mon, Dec 7, 2015 at 8:45 AM, Jurgis Pralgauskis < jurgis.pralgauskis@gmail.com> wrote:
for watch not to have delay, we probably can use
locals()[arg]
instead of eval?
eval would be usefull for expressions (for example when using lists with indexes A[i])
On Mon, Dec 7, 2015 at 8:30 AM, Jurgis Pralgauskis < jurgis.pralgauskis@gmail.com> wrote:
str method to the UsedRobot class
it should probably also include orientation for complete info? and tokens?
On Mon, Dec 7, 2015 at 6:40 AM, André Roberge notifications@github.com wrote:
Watch variable has now a complete implementation that should work properly ... It takes a bit longer to run a program (i.e. to compute each frame before being ready to display). It prompted me to add a str method to the UsedRobot class. If you create a new robot, you will see the result.
— Reply to this email directly or view it on GitHub https://github.com/aroberge/reeborg/issues/196#issuecomment-162411204.
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
Jurgis Pralgauskis tel: 8-616 77613; Don't worry, be happy and make things better ;) http://galvosukykla.lt
The slowdown was likely cause the the filtering function; I removed it and it is faster. Direct lookup instead of using eval also seems to make it faster; thanks for the suggestion.
Handling of variable assignments for builtins, like vars
now work.
Regarding P. Guo's Python tutor: my understanding is that it extracts information based on CPython's internals, which are unlikely to be equivalent in Brython. I think that what I have now is "good enough".
I do have one thing that puzzles me: with the nonlocal scope, we could have a third scope. However, there does not exists an equivalent to locals() or globals() for nonlocal as far as I can tell. I think I'll ask on the Brython list to see if it is possible to write an equivalent function.
@dz0 Waiting for your feedback before I close this issue ... hopefully for good this time!
Looks nice! :)
Someday i would like to be able to watch expressions (which would need eval way), but in most educational cases current var list is enough, and one can just print expressions... Less is more :)
Python tutor might consider Brython on their own -- so they wouldn't need serverside. Maybe I'll propose this to them :)
Thanks for now
Try the following on world Center 1
.
add_watch("dict(default_robot().objects)")
add_watch("default_robot().x")
move()
move()
put()
move()
btw, it should now work with Firefox as well as with Chrome (and Opera, and Edge...)
by the way, Brython nearly has watches as well...
https://github.com/amrdraz/python-debugger/issues/2#issuecomment-164898778
locals() and globals() are available in Brython -- so one can show them on each step.
ps.: https://github.com/amrdraz/python-debugger is designed for Brython and probably is better than the one Reeborg uses now :)