lupa icon indicating copy to clipboard operation
lupa copied to clipboard

How to define Lua coroutines from Python?

Open noahcgreen opened this issue 4 years ago • 2 comments

I'd like to give my lua scripts access to some coroutines defined in Python. Here's what I tried:

lua = LuaRuntime()
lua_yield = lua.eval('coroutine.yield')

def py_task(args)
    # Does some work...
    lua_yield()
    # Does some more work...

lua.globals().py_task = py_task
f = lua.eval('function() py_task("Some args from script here") end')
coroutine = f.coroutine()

At this point I'd expect running coroutine to execute py_task and yield when it reaches lua_yield (since coroutine.yield does yield from nested functions in Lua). However, I get this error instead:

coroutine.send(None)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "lupa/_lupa.pyx", line 876, in lupa._lupa._LuaThread.send
  File "lupa/_lupa.pyx", line 941, in lupa._lupa.resume_lua_thread
  File "lupa/_lupa.pyx", line 1268, in lupa._lupa.raise_lua_error
lupa._lupa.LuaError

Is there a way to accomplish the behavior I'm looking for here? If not, could some helpful description be added to the error raised?

noahcgreen avatar Jul 06 '20 20:07 noahcgreen

I think I've found a workaround by making the task a regular Python coroutine and wrapping it in a Lua one:

lua = LuaRuntime()
wrap = lua.eval('function(task) return function(...) for x in python.iter(task(...)) do coroutine.yield(x) end end end')

def py_task(args):
    # Does some work...
    yield
    # Does some more work...

lua.globals().py_task = wrap(py_task)
f = lua.eval('function() py_task("Some args from script here") end')
coroutine = f.coroutine()
coroutine.send(None)

I'm leaving this issue open since it would be nice if the method I tried before worked, and the error given is not descriptive.

noahcgreen avatar Jul 07 '20 01:07 noahcgreen

def py_task(args)
    # Does some work...
    lua_yield()
    # Does some more work...

You can't just expect this to work across the language runtimes. A yield in both Python and Lua touches the inner workings of functions and gravely changes the way they behave.

Could you explain your use case a little? There's probably a way to do what you want to achieve, instead of trying this specific approach.

scoder avatar Jul 24 '20 07:07 scoder