DebugClients/Python/AsyncFile.py

changeset 0
de9c2efb9d02
child 13
1af94a91f439
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DebugClients/Python/AsyncFile.py	Mon Dec 28 16:03:33 2009 +0000
@@ -0,0 +1,289 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2002 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing an asynchronous file like socket interface for the debugger.
+"""
+
+import socket
+import sys
+
+from DebugProtocol import EOT, RequestOK
+
+
+def AsyncPendingWrite(file):
+    """
+    Module function to check for data to be written.
+    
+    @param file The file object to be checked (file)
+    @return Flag indicating if there is data wating (int)
+    """
+    try:
+        pending = file.pendingWrite()
+    except:
+        pending = 0
+
+    return pending
+
+
+class AsyncFile(object):
+    """
+    Class wrapping a socket object with a file interface.
+    """
+    maxtries = 10
+    maxbuffersize = 1024 * 1024 * 4
+    
+    def __init__(self,sock,mode,name):
+        """
+        Constructor
+        
+        @param sock the socket object being wrapped
+        @param mode mode of this file (string)
+        @param name name of this file (string)
+        """
+        # Initialise the attributes.
+        self.closed = 0
+        self.sock = sock
+        self.mode = mode
+        self.name = name
+        self.nWriteErrors = 0
+
+        self.wpending = u''
+
+    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.
+        
+        @param 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.
+        
+        @param n the number of bytes to be written (int)
+        """
+        if n:
+            try :
+                buf = "%s%s" % (self.wpending[:n], EOT)
+                try:
+                    buf = buf.encode('utf8')
+                except (UnicodeEncodeError, UnicodeDecodeError):
+                    pass
+                self.sock.sendall(buf)
+                self.wpending = self.wpending[n:]
+                self.nWriteErrors = 0
+            except socket.error:
+                self.nWriteErrors += 1
+                if self.nWriteErrors > self.maxtries:
+                    self.wpending = u'' # delete all output
+
+    def pendingWrite(self):
+        """
+        Public method that returns the number of bytes waiting to be written.
+        
+        @return the number of bytes to be written (int)
+        """
+        return self.wpending.rfind('\n') + 1
+
+    def close(self, closeit=0):
+        """
+        Public method to close the file.
+        
+        @param closeit flag to indicate a close ordered by the debugger code (boolean)
+        """
+        if closeit and 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.
+        
+        @return always false
+        """
+        return 0
+
+    def fileno(self):
+        """
+        Public method returning the file number.
+        
+        @return file number (int)
+        """
+        return self.sock.fileno()
+
+    def read_p(self,size=-1):
+        """
+        Public method to read bytes from this file.
+        
+        @param size maximum number of bytes to be read (int)
+        @return the bytes read (any)
+        """
+        self.__checkMode('r')
+
+        if size < 0:
+            size = 20000
+
+        return self.sock.recv(size).decode('utf8')
+
+    def read(self,size=-1):
+        """
+        Public method to read bytes from this file.
+        
+        @param size maximum number of bytes to be read (int)
+        @return the bytes read (any)
+        """
+        self.__checkMode('r')
+
+        buf = raw_input()
+        if size >= 0:
+            buf = buf[:size]
+        return buf
+
+    def readline_p(self,size=-1):
+        """
+        Public method to read a line from this file.
+        
+        <b>Note</b>: This method will not block and may return
+        only a part of a line if that is all that is available.
+        
+        @param size maximum number of bytes to be read (int)
+        @return one line of text up to size bytes (string)
+        """
+        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).decode('utf8')
+
+    def readlines(self,sizehint=-1):
+        """
+        Public method to read all lines from this file.
+        
+        @param sizehint hint of the numbers of bytes to be read (int)
+        @return list of lines read (list of strings)
+        """
+        self.__checkMode('r')
+
+        lines = []
+        room = sizehint
+
+        line = self.readline_p(room)
+        linelen = len(line)
+
+        while linelen > 0:
+            lines.append(line)
+
+            if sizehint >= 0:
+                room = room - linelen
+
+                if room <= 0:
+                    break
+
+            line = self.readline_p(room)
+            linelen = len(line)
+
+        return lines
+
+    def readline(self, sizehint=-1):
+        """
+        Public method to read one line from this file.
+        
+        @param sizehint hint of the numbers of bytes to be read (int)
+        @return one line read (string)
+        """
+        self.__checkMode('r')
+
+        line = raw_input() + '\n'
+        if sizehint >= 0:
+            line = line[:sizehint]
+        return line
+        
+    def seek(self,offset,whence=0):
+        """
+        Public method to move the filepointer.
+        
+        @exception IOError 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.
+        
+        @exception IOError 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.
+        
+        @exception IOError This method is not supported and always raises an
+        IOError.
+        """
+        raise IOError, '[Errno 29] Illegal seek'
+
+    def write(self,s):
+        """
+        Public method to write a string to the file.
+        
+        @param s bytes to be written (string)
+        """
+        self.__checkMode('w')
+        tries = 0
+        if not self.wpending:
+            self.wpending = s
+        elif type(self.wpending) != type(s) or \
+             len(self.wpending) + len(s) > self.maxbuffersize:
+            # flush wpending so that different string types are not concatenated
+            while self.wpending:
+                # if we have a persistent error in sending the data, an exception
+                # will be raised in __nWrite
+                self.flush()
+                tries += 1
+                if tries > self.maxtries:
+                    raise socket.error("Too many attempts to send data")
+            self.wpending = s
+        else:
+            self.wpending += s
+        self.__nWrite(self.pendingWrite())
+
+    def writelines(self,list):
+        """
+        Public method to write a list of strings to the file.
+        
+        @param list the list to be written (list of string)
+        """
+        map(self.write,list)

eric ide

mercurial