python interactive - threaded console (run -i)

castironpi at gmail.com castironpi at gmail.com
Tue Mar 11 00:19:12 EDT 2008


#interactive run -i
import threading
import Queue
import functools
class GenThread( threading.Thread, Queue.Queue ):
    _taskid= 0
    def __init__( self, *ar, **kw ):
        threading.Thread.__init__( self, *ar, **kw )
        Queue.Queue.__init__( self )
        self.setDaemon( True )
        self.start()
        self._doneevents= {}
    def run( self ):
        while 1:
            id, fun, ar, kw= self.get()
            self._= fun( *ar, **kw )
            self._doneevents[id].set()
            if self._:
                self._print( self._ )
    def me( self, fun, *ar, **kw ):
        id= GenThread._taskid
        GenThread._taskid+= 1
        self.put( ( id, fun, ar, kw ) )
        self._doneevents[ id ]= e= threading.Event()
        return e
    def _print( self, *ar, **kw ):
        print( self.getName(), *ar, **kw )

for i in range( 10 ):
    exec( 'th%i= GenThread()'% i )

import socket
host= socket.socket( socket.AF_INET,
    socket.SOCK_STREAM )
host.bind( ( '', 8000 ) )
th1.me( host.listen, 1 )
_acc= th1.me( host.accept )
cli= socket.socket( socket.AF_INET,
    socket.SOCK_STREAM )
th2.me( cli.connect, ( 'localhost', 8000 ) )
_acc.wait()
conn= th1._[0]

ConnClose= object()
class IncompleteTransmission( Exception ): pass
def _draintilclose( conn, understandfun= None ):
    while 1:
        _preamb= ''
        while 1:
            _data= conn.recv( 1 )
            if not _data:
                conn.close()
                return ConnClose
            if _data== b'\x00':
                break
            _preamb+= _data.decode()
        _len= int( _preamb, 16 )
        _lenleft= _len
        _curmsg= bytearray()
        while _lenleft:
            _data= conn.recv( min( 4096, _lenleft ) )
            if not _data:
                raise IncompleteTransmission
            _curmsg.extend( _data )
            _lenleft-= len( _data )
        assert len( _curmsg )== _len
        if None is not understandfun:
            understandfun( _curmsg )

def _dressandsend( sck, msg ):
    _preamble= hex( len( msg ) )[2:]+ '\x00'
    _dressed= bytes( _preamble, 'ascii' )+ msg
    _lenleft= len( _dressed )
    while _lenleft:
        _sent= sck.send( _dressed[-_lenleft:] )
        _lenleft-= _sent

th1.me( _draintilclose, conn, th1._print )
th2.me( _draintilclose, cli, th2._print )

This is cool!  Set up a socket and listen 'til close on one thread,
print output by default as complete messages are received.  Listen
'til close, same, on another, th1, th2 respectively.  Roughly off the
console:

>>> _dressandsend( conn, b'abc' )
Thread-2 bytearray(b'abc')
>>> _dressandsend( cli, b'def' )
Thread-1 bytearray(b'def')

Rearranged the '>>>'.  It's damn annoying.  Probably a specialized
stdout to detect when in a prompt and add extra newline, maybe
modified GenThread._print.  Someone go replace hex with base255 and
conn.recv( 1 ) with conn.recv( 2 ).  Should take any length-- base256
over hex is just a factor of 2, and still O( log( message length ) ).

>>> dir()
['ConnClose', 'GenThread', 'IncompleteTransmission', 'Queue',
'__builtins__', '__doc__', '__name__', '__package__', '_acc',
'_draintilclose', '_dressandsend', 'cli', 'conn', 'functools', 'host',
'i', 'socket', 'th1', 'th2', 'th3', 'th4', 'th5', 'th6', 'th7', 'th8',
'th9', 'threading']



More information about the Python-list mailing list