Python, pymonome, asyncio, and concurrency

  • Dear monome community,

    How can I run a pymonome server from an interpreter without losing the ability to type into the interpreter? I want to live-code in Python (3.4) using pymonome.

    The problem being concurrency, I have tried for days to understand asyncio, but it baffles me. (I even spent a couple days trying to work with Erlang instead, but its installers for the Mac all seem to be broken.)

    pymonome 0.2.3 comes with an examples/ folder that includes a file called lights.py. If I start the python interpreter from that folder, I can start Lights by doing this:

    >>> import random, asyncio, monome, lights
    >>> loop = asyncio.get_event_loop()
    >>> asyncio.async(monome.create_serialosc_connection(lights.Lights), loop=loop)
    Task()
    >>> loop.run_forever()

    Everything after the import statement is cribbed straight from lights.py. Running that starts the monome blinking but freezes the interpreter. If I press Ctrl-C I regain interpreter access but the lights stop.

    Does anybody know how to do this?

    Thanks,
    Jeff

  • You won't be able to livecode in the interactive Python shell because of blocking calls like loop.run_forever(). You need to to add a network/fifo listener to your program that will receive and execute your live code, which you'll be sending from another software (the editor).

  • Thanks, Art!

    I can't tell whether I nearly have a working solution or am nowhere close. I don't know how to implement a network/fifo listener, but regarding the blocking problem I have a solution that at least works in other contexts:

    From the Python Cookbook there's this example of how to run something that otherwise would block as a background process. It works from an interpreter or the shell. It prints a number every two seconds until it runs out of them:

    ````import time
    ````def countdown(n):
    ````````while n > 0:
    ````````````print('T-minus', n)
    ````````````n -= 1
    ````````````time.sleep(5)
    ````
    ````from threading import Thread
    ````t = Thread(target=countdown, args=(10,))
    ````t.start()

    It seems like I should similarly be able to instantiate a monome server, and then pass its event loop to a thread, something like this:

    ````loop = asyncio.get_event_loop()
    ````asyncio.async(monome.create_serialosc_connection(Lights), loop=loop)
    ````
    ````from threading import Thread
    ````t = Thread(target=loop.run_forever, args=(10,))
    ````t.start()

    It doesn't work. But maybe it is close?

    (I apologize for the backquotes; when I copy leading space into here it vanishes, even if the first character is not space.)

  • You shouldn't use threads with asyncio.

    For your specific case, I'd suggest creating a socket server (check out asyncio documentation for recipes) that would compile and/or replace the press handlers in your monome app (e.g. Lights) or some other parts of code that you want to write live.

    Then just send code snippets from another app (editor) to that socket, so things will run in the same event loop.