PageRenderTime 64ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/eric4-4.4.19/eric/DebugClients/Python/AsyncFile.py

#
Python | 292 lines | 258 code | 11 blank | 23 comment | 1 complexity | 87dcd7c7fb999962d920a3c63e438dbe MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, BSD-2-Clause
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2002 - 2011 Detlev Offenbach <detlev@die-offenbachs.de>
  3. #
  4. """
  5. Module implementing an asynchronous file like socket interface for the debugger.
  6. """
  7. import socket
  8. import sys
  9. from DebugProtocol import EOT, RequestOK
  10. def AsyncPendingWrite(file):
  11. """
  12. Module function to check for data to be written.
  13. @param file The file object to be checked (file)
  14. @return Flag indicating if there is data wating (int)
  15. """
  16. try:
  17. pending = file.pendingWrite()
  18. except:
  19. pending = 0
  20. return pending
  21. class AsyncFile(object):
  22. """
  23. Class wrapping a socket object with a file interface.
  24. """
  25. maxtries = 10
  26. maxbuffersize = 1024 * 1024 * 4
  27. def __init__(self,sock,mode,name):
  28. """
  29. Constructor
  30. @param sock the socket object being wrapped
  31. @param mode mode of this file (string)
  32. @param name name of this file (string)
  33. """
  34. # Initialise the attributes.
  35. self.closed = 0
  36. self.sock = sock
  37. self.mode = mode
  38. self.name = name
  39. self.nWriteErrors = 0
  40. self.wpending = u''
  41. def __checkMode(self,mode):
  42. """
  43. Private method to check the mode.
  44. This method checks, if an operation is permitted according to
  45. the mode of the file. If it is not, an IOError is raised.
  46. @param mode the mode to be checked (string)
  47. """
  48. if mode != self.mode:
  49. raise IOError, '[Errno 9] Bad file descriptor'
  50. def __nWrite(self,n):
  51. """
  52. Private method to write a specific number of pending bytes.
  53. @param n the number of bytes to be written (int)
  54. """
  55. if n:
  56. try :
  57. buf = "%s%s" % (self.wpending[:n], EOT)
  58. try:
  59. buf = buf.encode('utf8')
  60. except (UnicodeEncodeError, UnicodeDecodeError):
  61. pass
  62. self.sock.sendall(buf)
  63. self.wpending = self.wpending[n:]
  64. self.nWriteErrors = 0
  65. except socket.error:
  66. self.nWriteErrors += 1
  67. if self.nWriteErrors > self.maxtries:
  68. self.wpending = u'' # delete all output
  69. def pendingWrite(self):
  70. """
  71. Public method that returns the number of bytes waiting to be written.
  72. @return the number of bytes to be written (int)
  73. """
  74. return self.wpending.rfind('\n') + 1
  75. def close(self, closeit=0):
  76. """
  77. Public method to close the file.
  78. @param closeit flag to indicate a close ordered by the debugger code (boolean)
  79. """
  80. if closeit and not self.closed:
  81. self.flush()
  82. self.sock.close()
  83. self.closed = 1
  84. def flush(self):
  85. """
  86. Public method to write all pending bytes.
  87. """
  88. self.__nWrite(len(self.wpending))
  89. def isatty(self):
  90. """
  91. Public method to indicate whether a tty interface is supported.
  92. @return always false
  93. """
  94. return 0
  95. def fileno(self):
  96. """
  97. Public method returning the file number.
  98. @return file number (int)
  99. """
  100. try:
  101. return self.sock.fileno()
  102. except socket.error:
  103. return -1
  104. def read_p(self,size=-1):
  105. """
  106. Public method to read bytes from this file.
  107. @param size maximum number of bytes to be read (int)
  108. @return the bytes read (any)
  109. """
  110. self.__checkMode('r')
  111. if size < 0:
  112. size = 20000
  113. return self.sock.recv(size).decode('utf8')
  114. def read(self,size=-1):
  115. """
  116. Public method to read bytes from this file.
  117. @param size maximum number of bytes to be read (int)
  118. @return the bytes read (any)
  119. """
  120. self.__checkMode('r')
  121. buf = raw_input()
  122. if size >= 0:
  123. buf = buf[:size]
  124. return buf
  125. def readline_p(self,size=-1):
  126. """
  127. Public method to read a line from this file.
  128. <b>Note</b>: This method will not block and may return
  129. only a part of a line if that is all that is available.
  130. @param size maximum number of bytes to be read (int)
  131. @return one line of text up to size bytes (string)
  132. """
  133. self.__checkMode('r')
  134. if size < 0:
  135. size = 20000
  136. # The integration of the debugger client event loop and the connection
  137. # to the debugger relies on the two lines of the debugger command being
  138. # delivered as two separate events. Therefore we make sure we only
  139. # read a line at a time.
  140. line = self.sock.recv(size, socket.MSG_PEEK)
  141. eol = line.find('\n')
  142. if eol >= 0:
  143. size = eol + 1
  144. else:
  145. size = len(line)
  146. # Now we know how big the line is, read it for real.
  147. return self.sock.recv(size).decode('utf8')
  148. def readlines(self,sizehint=-1):
  149. """
  150. Public method to read all lines from this file.
  151. @param sizehint hint of the numbers of bytes to be read (int)
  152. @return list of lines read (list of strings)
  153. """
  154. self.__checkMode('r')
  155. lines = []
  156. room = sizehint
  157. line = self.readline_p(room)
  158. linelen = len(line)
  159. while linelen > 0:
  160. lines.append(line)
  161. if sizehint >= 0:
  162. room = room - linelen
  163. if room <= 0:
  164. break
  165. line = self.readline_p(room)
  166. linelen = len(line)
  167. return lines
  168. def readline(self, sizehint=-1):
  169. """
  170. Public method to read one line from this file.
  171. @param sizehint hint of the numbers of bytes to be read (int)
  172. @return one line read (string)
  173. """
  174. self.__checkMode('r')
  175. line = raw_input() + '\n'
  176. if sizehint >= 0:
  177. line = line[:sizehint]
  178. return line
  179. def seek(self,offset,whence=0):
  180. """
  181. Public method to move the filepointer.
  182. @exception IOError This method is not supported and always raises an
  183. IOError.
  184. """
  185. raise IOError, '[Errno 29] Illegal seek'
  186. def tell(self):
  187. """
  188. Public method to get the filepointer position.
  189. @exception IOError This method is not supported and always raises an
  190. IOError.
  191. """
  192. raise IOError, '[Errno 29] Illegal seek'
  193. def truncate(self,size=-1):
  194. """
  195. Public method to truncate the file.
  196. @exception IOError This method is not supported and always raises an
  197. IOError.
  198. """
  199. raise IOError, '[Errno 29] Illegal seek'
  200. def write(self,s):
  201. """
  202. Public method to write a string to the file.
  203. @param s bytes to be written (string)
  204. """
  205. self.__checkMode('w')
  206. tries = 0
  207. if not self.wpending:
  208. self.wpending = s
  209. elif type(self.wpending) != type(s) or \
  210. len(self.wpending) + len(s) > self.maxbuffersize:
  211. # flush wpending so that different string types are not concatenated
  212. while self.wpending:
  213. # if we have a persistent error in sending the data, an exception
  214. # will be raised in __nWrite
  215. self.flush()
  216. tries += 1
  217. if tries > self.maxtries:
  218. raise socket.error("Too many attempts to send data")
  219. self.wpending = s
  220. else:
  221. self.wpending += s
  222. self.__nWrite(self.pendingWrite())
  223. def writelines(self,list):
  224. """
  225. Public method to write a list of strings to the file.
  226. @param list the list to be written (list of string)
  227. """
  228. map(self.write,list)