Pyodide Issues
I am currently working on an online console for Quackery that is using the Pyodide in-browser Python interpreter. The only bad thing is, Python’s input()
function blocks until input is provided, which can’t be done in the browser because everything is asynchronous. The only way for it to work is an annoying prompt()
box.
I thought, maybe I could automatically rewrite the Quackery source code and patch in an async input function, then make everything else that needs to be async, async.
The general process of patching went as follows:
- Find and replace the offending
input()
function with an async patched version. - Find all the functions that are now invalid (i.e. are not declared with
async def
but now have anawait
inside of them) and make themasync def
. - Find all the places where those functions are called, and
await
them. - If something changed, go back to step 2.
My first attempt used the Python AST module to walk the abstract syntax tree and replace FunctionDef
nodes with AsyncFunctionDef
nodes and wrap their calls in Await
nodes. For some reason, that either crapped out halfway through or hung forever. I don’t know why.
My second attempt was to use the regular expression module to find all the non-async
functions that have await
inside of them, and insert async
onto the definition, then find their references and insert await
. This proved tricky using regular expressions and often produced absurd (and incorrect) results such as async async def
(until I checked and removed all occurrences of async async
and await await
manually) or even self.string_await from_stack()
(because from_stack
happened to be processed before string_from_stack
and their names overlapped).
My third attempt was to simply manually go through and make the edits. The tricky thing here is, even though I am sure I have asynced and awaited everything I need to, Quackery operators (Python functions) are passed by reference to the interpreter, and some must be made async and some are not. And that wreaks havoc on the entire program, because it is impossible to predict whether that passed-by-reference function is async or not and whether it should be awaited. Whereas in Javascript – and Phoo, too – await undefined
works, simply returning undefined
immediately, await None
throws TypeError: object NoneType can't be used in 'await' expression
and crashes the whole program. So the TypeError
must be suppressed with a try-catch block. Unfortunately, this causes some other problems, which I don’t really understand and so I can’t fix them.
I sure hope the Pyodide people can get the async input fixed soon!
Related Posts
- Now Fully Two-Dimensional
- In Defense Of Eval
- Perhaps It Was Too Complicated
- Zero-Thickness Tree
- PICKLE Has Regular Expressions, Apparently