Glad I could help! And yes, we could use more examples...
On Sat, May 17, 2014 at 6:23 PM, Dan McDougall <[email protected]> wrote: > On Saturday, May 17, 2014 5:43:34 PM UTC-4, Guido van Rossum wrote: >> >> The reason the reader/writer don't expose their FD is that there's >> already a handler registered for them, so registering your own would have >> disappointing effects. >> > > Ahh, now that makes perfect sense. I thought I was missing something or > perhaps someone "just forgot" to add the fileno() method (hehe). Thank > you. I figured there would be a very good reason why it works the way it > does. > > TBH I don't see anything wrong with your first version -- if you don't >> need the full treatment you shouldn't have to pay for it. :-) >> > > I just wanted to write simpler/easier-to-understand code. I know that it > took me a while to grok pty.fork() the first time I used it so I thought it > would be better to use something more concise like, "yield from > asyncio.the_one_right_way_to_do_this()" =D > > But if you want to use asyncio's create_subprocess_shell() you can just >> write a coroutine that reads from the reader and prints its output, and run >> that reader: >> >> @asyncio.coroutine >> def tail(reader): >> while True: >> data = yield from reader.read(8192) >> if not data: >> break >> # here you print data (note it's a bytes object) >> >> @asyncio.coroutine >> def setup(): >> reader, writer = yield from asyncio.create_subprocess_shell(......) >> yield from tail(reader) >> >> asyncio.get_event_loop().run_until_complete(setup()) >> >> There's also a lower-level subprocess API on the event loop; it lets you >> write a Protocol subclass; in that class you can write a data_received() >> method that prints your data: >> >> class TailProtocol: >> def data_received(self, data): >> # here you print data (note it's a bytes object) >> >> @asyncio.coroutine >> def setup(): >> transport, protocol = yield from loop.subprocess_shell(TailProtocol, >> program, *args) >> >> The termination condition in this case is a little complex, you probably >> want to create a Future in TailProtocol.__init__() that is made complete by >> the connection_lost() callback: >> >> class TailProtocol: >> def __init__(self): >> self.complete = asyncio.Future() >> def data_received(self, data): >> # etc. >> def connection_lost(self, err): >> self.complete.set_result(err) >> >> @asyncio.coroutine >> def setup(): >> transport, protocol = yield from loop.subprocess_shell(TailProtocol, >> program, *args) >> yield from protocol.complete >> >> asyncio.get_event_loop().run_until_complete(setup()) >> >> Hope this isn't too overwhelming for you. :-) >> > > Excellent. I figured there was a way to do it with a Protocol but I'm > still new to the asyncio package and hadn't crossed that bridge yet (my > mind is still in "Tornado mode"). Another thing making it tough is the > fact that asyncio *so new* that there's very little to be found when > googling for examples. I'm going to see if I can fix that =D > > For reference I'm not actually trying to run 'tail' on a log file... It's > all part of some re-plumbing of Gate > One<https://github.com/liftoff/GateOne>in order to better support the new > web-based > X11 interface <http://youtu.be/6zJ8TNcWTyo>. I figured, "If I'm going to > use asyncio with X11 stuff I might as well get regular ol' web-based > terminals working with it too." > -- --Guido van Rossum (python.org/~guido)
