Table of Contents

Eric3 Source Documentation: Debugger  
# -*- coding: utf-8 -*-

# Copyright (c) 2000 Phil Thompson <phil@river-bank.demon.co.uk>
# Copyright (c) 2002, 2003 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing an asynchronous interface for the debugger.
"""

import socket
from qt import SIGNAL, PYSIGNAL, QObject, QSocketNotifier


def AsyncPendingWrite(file):
    """
    Module function to check for data to be written.
    
    Arguments
    
        file -- the file object to be checked (file)
        
    Returns
    
        flag indicating if there is data wating (int)
    """
    try:
        pending = file.pendingWrite()
    except:
        pending = 0

    return pending


class AsyncFile:
    """
    Class wrapping a socket object with a file interface.
    """

    def __init__(self,sock,mode,name):
        """
        Constructor
        
        Arguments
        
            sock -- the socket object being wrapped
            
            mode -- mode of this file (string)
            
            name -- name of this file (string)
        """
        # Initialise the attributes.
        self.closed = 0
        self.sock = sock
        self.mode = mode
        self.name = name
        self.softspace = 0

        self.wpending = ''

    def checkMode(self,mode):
        """
        Private method to check the mode.
        
        This method checks, if an operation is permitted according to
        the mode of the file. If it is not, an IOError is raised.
        
        Arguments
        
            mode -- the mode to be checked (string)
        """
        if mode != self.mode:
            raise IOError, '[Errno 9] Bad file descriptor'

    def nWrite(self,n):
        """
        Private method to write a specific number of pending bytes.
        
        Arguments
        
            n -- the number of bytes to be written (int)
        """
        if n:
            sent = self.sock.send(self.wpending[:n])
            self.wpending = self.wpending[sent:]

    def pendingWrite(self):
        """
        Public method that returns the number of bytes waiting to be written.
        
        Returns
        
            the number of bytes to be written (int)
        """
        return self.wpending.rfind('\n') + 1

    def close(self):
        """
        Public method to close the file.
        """
        if not self.closed:
            self.flush()
            self.sock.close()
            self.closed = 1

    def flush(self):
        """
        Public method to write all pending bytes.
        """
        self.nWrite(len(self.wpending))

    def isatty(self):
        """
        Public method to indicate whether a tty interface is supported.
        
        Returns
        
            always false
        """
        return 0

    def fileno(self):
        """
        Public method returning the file number.
        
        Returns
        
            file number (int)
        """
        return self.sock.fileno()

    def read(self,size=-1):
        """
        Public method to read bytes from this file.
        
        Arguments
        
            size -- maximum number of bytes to be read (int)
            
        Returns
        
            the bytes read (any)
        """
        self.checkMode('r')

        if size < 0:
            size = 20000

        return self.sock.recv(size)

    def readline(self,size=-1):
        """
        Public method to read a line from this file.
        
        Arguments
        
            size -- maximum number of bytes to be read (int)
            
        Returns
        
            one line of text up to size bytes (string)
            
        Note
        
            This method will not block and may return only a part of a
            line if that is all that is available.
        """
        self.checkMode('r')

        if size < 0:
            size = 20000

        # The integration of the debugger client event loop and the connection
        # to the debugger relies on the two lines of the debugger command being
        # delivered as two separate events.  Therefore we make sure we only
        # read a line at a time.
        line = self.sock.recv(size,socket.MSG_PEEK)

        eol = line.find('\n')

        if eol >= 0:
            size = eol + 1
        else:
            size = len(line)

        # Now we know how big the line is, read it for real.
        return self.sock.recv(size)

    def readlines(self,sizehint=-1):
        """
        Public method to read all lines from this file.
        
        Arguments
        
            sizehint -- hint of the numbers of bytes to be read (int)
            
        Returns
        
            list of lines read (list of strings)
        """
        lines = []
        room = sizehint

        line = self.readline(room)
        linelen = len(line)

        while linelen > 0:
            lines.append(line)

            if sizehint >= 0:
                room = room - linelen

                if room <= 0:
                    break

            line = self.readline(room)
            linelen = len(line)

        return lines

    def seek(self,offset,whence=0):
        """
        Public method to move the filepointer.
        
        This method is not supported and always raises an
        IOError.
        """
        raise IOError, '[Errno 29] Illegal seek'

    def tell(self):
        """
        Public method to get the filepointer position.
        
        This method is not supported and always raises an
        IOError.
        """
        raise IOError, '[Errno 29] Illegal seek'

    def truncate(self,size=-1):
        """
        Public method to truncate the file.
        
        This method is not supported and always raises an
        IOError.
        """
        raise IOError, '[Errno 29] Illegal seek'

    def write(self,str):
        """
        Public method to write a string to the file.
        
        Arguments
        
            str -- bytes to be written (string)
        """
        self.checkMode('w')
        self.wpending = self.wpending + str
        self.nWrite(self.pendingWrite())

    def writelines(self,list):
        """
        Public method to write a list of strings to the file.
        
        Arguments
        
            list -- the list to be written (list of string)
        """
        map(self.write,list)


class AsyncIO(QObject):
    """
    Class implementing asynchronous reading and writing.
    
    It implements asynchronous reading and writing using the Qt event
    loop.  
    
    Signals
    
        lineReady -- emitted when a complete line has been read
        
        gotEOF -- emitted if EOF was read
    """
    def __init__(self,parent=None):
        """
        Constructor
        
        Arguments
        
            parent -- the optional parent of this object (QObject)
        """
        QObject.__init__(self,parent)

        # There is no connection yet.
        self.disconnect()

    def disconnect(self):
        """
        Public method to disconnect any current connection.
        """
        self.readsn = None
        self.readfd = None
        self.writesn = None
        self.writefd = None

    def setDescriptors(self,rfd,wfd):
        """
        Public method called to set the descriptors for the connection.
        
        Arguments
        
            rfd -- file descriptor of the input file (int)
            
            wfd -- file descriptor of the output file (int)
        """
        self.rbuf = ''
        self.readfd = rfd

        self.wbuf = ''
        self.writefd = wfd

    def setNotifiers(self):
        """
        Public method to set up the socket notifiers for the Qt event loop.
        """
        self.readsn = QSocketNotifier(self.readfd.fileno(),QSocketNotifier.Read)
        self.readsn.connect(self.readsn,SIGNAL('activated(int)'),self.readReady)

        self.writesn = QSocketNotifier(self.writefd.fileno(),QSocketNotifier.Write)
        self.writesn.connect(self.writesn,SIGNAL('activated(int)'),self.writeReady)
        self.setWriteNotifier()

    def readReady(self,fd):
        """
        Protected method called when there is data ready to be read.
        
        Arguments
        
            fd -- file descriptor of the file that has data to be read (int)
        """
        # There seems to be a problem under Windows that the QSocketNotifier
        # says that there is data from the server, but the Python socket module
        # complains that the recv() on the socket would block and raises an
        # exception.  However, everything goes on to work as expected so we
        # just catch the exception and ignore it.
        try:
            got = self.readfd.readline()
        except:
            return

        if len(got) == 0:
            self.emit(PYSIGNAL('gotEOF'),())
            return

        self.rbuf = self.rbuf + got

        # Emit a signal for the line if it is complete.
        eol = self.rbuf.find('\n')

        while eol >= 0:
            s = self.rbuf[:eol + 1]
            self.rbuf = self.rbuf[eol + 1:]
            self.emit(PYSIGNAL('lineReady'),(s,))
            eol = self.rbuf.find('\n')

    def writeReady(self,fd):
        """
        Protected method called when we are ready to write data.
        
        Arguments
        
            fd -- file descriptor of the file that has data to be written (int)
        """
        self.writefd.write(self.wbuf)
        self.writefd.flush()
        self.wbuf = ''

        if self.writesn is not None:
            self.setWriteNotifier()

    def setWriteNotifier(self):
        """
        Private method called to disable the write notifier.

        If there is no data to be written, the write notifier
        will be diabled.
        """
        if not AsyncPendingWrite(self.writefd):
            self.writesn.setEnabled(0)

    def write(self,s):
        """
        Public method to write a string.
        
        Arguments
        
            s -- the data to be written (string)
        """
        # Make sure any write notifier is enabled.
        if self.writesn is not None:
            self.writesn.setEnabled(1)

        self.wbuf = self.wbuf + s

Table of Contents

This document was automatically generated by HappyDoc version 2.1