/eric4-4.4.19/eric/DebugClients/Python3/AsyncFile.py
# · Python · 295 lines · 120 code · 44 blank · 131 comment · 27 complexity · 66ef4aaa32c8e40fbb99b2b7d75c3317 MD5 · raw file
- # -*- coding: utf-8 -*-
- # Copyright (c) 2009 - 2011 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 = False
- self.sock = sock
- self.mode = mode
- self.name = name
- self.nWriteErrors = 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.
-
- @param mode the mode to be checked (string)
- """
- if mode != self.mode:
- raise IOError((9, '[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 = "{0!s}{1!s}".format(self.wpending[:n], EOT)
- try:
- buf = buf.encode('utf8', 'backslashreplace')
- 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 = '' # 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 = False):
- """
- 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 = True
- 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 False
- def fileno(self):
- """
- Public method returning the file number.
-
- @return file number (int)
- """
- try:
- return self.sock.fileno()
- except socket.error:
- return -1
- 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 = 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(b'\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 = input() + '\n'
- if sizehint >= 0:
- line = line[:sizehint]
- return line
-
- def seek(self, offset, whence = 0):
- """
- Public method to move the filepointer.
-
- @param offset offset to move the filepointer to (integer)
- @param whence position the offset relates to
- @exception IOError This method is not supported and always raises an
- IOError.
- """
- raise IOError((29, '[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((29, '[Errno 29] Illegal seek'))
- def truncate(self, size = -1):
- """
- Public method to truncate the file.
-
- @param size size to truncaze to (integer)
- @exception IOError This method is not supported and always raises an
- IOError.
- """
- raise IOError((29, '[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 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)
- """
- for l in list:
- self.write(l)