Open alexandruionascu opened 3 years ago
Hi,
Thanks for the feedback! That is a great idea. It also enables parallelism as far as the browser can go, which I can see a few usecases for. The Brython engine is actually already using a webworker implementation, so it is possible now, but I see the value of having that option on all the engines - as they all have their advantages and disadvantages. I must admit I am not that experienced with webworkers, but I will add that to the top of my priorities here.
I am also open for PR's, though I see that it may be hard to contribute as the project is a little mess right now. Maybe I should focus on cleaning up while I am at it.
Again, thanks for the feedback!
Investigated this issue for a while.
I tried Skulpt with this library (not actively maintained but it has been working great for me in the past) https://github.com/icodeforlove/task.js/ since it is based on web workers in the browser.
However, is not necessarily the best idea to run inside web-workers to prevent infinite loops. Skulpt relies on window and document objects, that are not available in web workers and cloning them might not be a good idea. So, it will work but with several limitations.
From what I see now, Skulpt has an option to set a timeout, that would be much better to use IMO.
For pyodide is much more complicated, it's very difficult to make it work with web workers and it doesn't seem to have a timeout like Skulpt.
I totally agree on your reasoning about infinite loops. I think enabling web workers - where it is possible - should be an option (regardless), but it is not essential to stop infinite loops.
I have actually worked with avoiding infinite loops in the past (not sure why I did not mention this earlier, I may got too focused on the web worker part of the issue), and one method that I found to be working nicely (at least in javascript - inspired by CodePen) is to inject a line of code after every loop statement that will count executions or keep track of time, and after a certain threshold will break out of the loop. One of the issues with this would be to keep track of the line numbers in errors as Python probably would need to add a new line for each of the "circuit breakers". Another issue would be to find these loops. Maybe a simple text search could be sufficient? Or do one need a full fledged AST graph generator to find them all?
A third way, a part from web workers and injecting circuit breakers, is to use the inbuilt functionality in e.g. Skulpt (as you mentioned). This may be limited to a few "Python runners", but is definitly the cheapest and robust option.
Maybe a hybrid approach could work? I can imagine the smartest choice is to use inbuilt functionality. One could then just fall back on using circuit breakers if that does not exist on the current Python runner. Even if it may come with disadvantages, I think the benefits are huge for e.g. educational tools where learners fail with loops all the time.
Injecting Python code, really nice idea. I've been doing that for a while but didn't think it would help to count the steps. I'm working on a Python live visualisation. You can try a demo here: https://project-emun.web.app
Link to repo (wip) https://github.com/alexandruionascu/emun-studio I've been using a Python 3.7 grammar and Jison to parse the Python code, and then I injected printing lines to get step-by-step variable values. I think it is working pretty nice from what I tested, I might be able to integrate this in your library, since it has support for variables values, but having also their history might be nice for debugging purposes.
Cool project! Love it when developers make demos look so smooth and easy to use. It is really inspiring 😄 I also liked how responsive it was.
Using Jison was brilliant! I must admit I do not have much skills when it comes to the theory part behind programming languages - which is mainly why I am only using existing solutions here. It would be amazing to get this integrated somehow. I cannot figure out how to do it on the spot, but I can imagine it could be another "engine" called "Skulpt (with debugging)". Or would it be possible to add it to all the existing engines? I do not know a lot about parsers. Seems like you mixed it with Skulpt, so maybe that is possible?
I was actually creating this library because of the lack of variable-management. I saw that all the python runners had some issues with getting the variables (or the state), and I wanted to be able to "store" the state, then modify it and continue with that modified state (pyodide has this by default, but has problems with clearing the state instead). Using this library I could have variable-management out of the box (even though it uses a little hacky solution in some engines). I hope that I do not need this library in the future, but for now there are too many quirks with each of the python runners. I kind of think of this project as a polyfill for the python runners out there.
This also leads me to the point that I am really happy to add more functionality to this library which could make Brython, Skulpt and Pyodide even better to use! They cannot experiment much with this - since they aim to shrink their assets and therefore cannot add extra stuff, but this library can!
I would say go for it! I may be able to help a little with cleaning up the code. Maybe I should attempt to use a compiler for the package soon such that we could split the project into more files as well as using TypeScript files (instead of JSDoc type definitions for the types)
I had a look on the code, supporting all the runners is really tedious. Pyodide, Skulpt (I didn't work with Brython yet) are very different. I think some of their features cannot be abstracted (in an educational app for instance, you may need to add support for libraries, external code, etc.).
I was trying to include those changes, I was thinking some sort of callback based options might be doable.
Something like
runCode(your_code, { output: (stdout) => console.log(stdout), onStep(variable, newValue, scope, step) => {} }
where step can be the number of steps, then you can add some logic to break the infinite loops, and you can get the variable history.
Hello,
Thank you for your work in this library, really love the idea of running Python in the browser!
I was thinking those runners should run somehow using web workers, to not freeze the page in infinite loops.
LE: if the runner is set in window object the library shouldn't provide that, but some samples would be cool.