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."

Reply via email to