37 class AsyncFile(object): |
39 class AsyncFile(object): |
38 """ |
40 """ |
39 Class wrapping a socket object with a file interface. |
41 Class wrapping a socket object with a file interface. |
40 """ |
42 """ |
41 maxtries = 10 |
43 maxtries = 10 |
42 maxbuffersize = 1024 * 1024 * 4 |
|
43 |
44 |
44 def __init__(self, sock, mode, name): |
45 def __init__(self, sock, mode, name): |
45 """ |
46 """ |
46 Constructor |
47 Constructor |
47 |
48 |
48 @param sock the socket object being wrapped |
49 @param sock the socket object being wrapped |
49 @param mode mode of this file (string) |
50 @type socket |
50 @param name name of this file (string) |
51 @param mode mode of this file |
|
52 @type str |
|
53 @param name name of this file |
|
54 @type str |
51 """ |
55 """ |
52 # Initialise the attributes. |
56 # Initialise the attributes. |
53 self.closed = False |
57 self.closed = False |
54 self.sock = sock |
58 self.sock = sock |
55 self.mode = mode |
59 self.mode = mode |
56 self.name = name |
60 self.name = name |
57 self.nWriteErrors = 0 |
61 self.nWriteErrors = 0 |
58 self.encoding = "utf-8" |
62 self.encoding = "utf-8" |
59 |
63 |
60 self.wpending = unicode('') |
64 self.wpending = [] |
61 |
65 |
62 def __checkMode(self, mode): |
66 def __checkMode(self, mode): |
63 """ |
67 """ |
64 Private method to check the mode. |
68 Private method to check the mode. |
65 |
69 |
66 This method checks, if an operation is permitted according to |
70 This method checks, if an operation is permitted according to |
67 the mode of the file. If it is not, an IOError is raised. |
71 the mode of the file. If it is not, an IOError is raised. |
68 |
72 |
69 @param mode the mode to be checked (string) |
73 @param mode the mode to be checked |
|
74 @type string |
70 @exception IOError raised to indicate a bad file descriptor |
75 @exception IOError raised to indicate a bad file descriptor |
71 """ |
76 """ |
72 if mode != self.mode: |
77 if mode != self.mode: |
73 raise IOError((9, '[Errno 9] Bad file descriptor')) |
78 raise IOError((9, '[Errno 9] Bad file descriptor')) |
74 |
79 |
75 def __nWrite(self, n): |
80 def pendingWrite(self): |
76 """ |
81 """ |
77 Private method to write a specific number of pending bytes. |
82 Public method that returns the number of strings waiting to be written. |
78 |
83 |
79 @param n the number of bytes to be written (int) |
84 @return the number of strings to be written |
80 """ |
85 @rtype int |
81 if n: |
86 """ |
|
87 return len(self.wpending) |
|
88 |
|
89 def close(self, closeit=False): |
|
90 """ |
|
91 Public method to close the file. |
|
92 |
|
93 @param closeit flag to indicate a close ordered by the debugger code |
|
94 @type bool |
|
95 """ |
|
96 if closeit and not self.closed: |
|
97 self.flush() |
|
98 self.sock.close() |
|
99 self.closed = True |
|
100 |
|
101 def flush(self): |
|
102 """ |
|
103 Public method to write all pending entries. |
|
104 """ |
|
105 while self.wpending: |
|
106 buf = self.wpending.pop(0) |
82 try: |
107 try: |
83 buf = self.wpending[:n] |
|
84 try: |
108 try: |
85 buf = buf.encode('utf-8', 'backslashreplace') |
109 buf = buf.encode('utf-8', 'backslashreplace') |
86 except (UnicodeEncodeError, UnicodeDecodeError): |
110 except (UnicodeEncodeError, UnicodeDecodeError): |
87 pass |
111 pass |
88 self.sock.sendall(buf) |
112 self.sock.sendall(buf) |
89 self.wpending = self.wpending[n:] |
|
90 self.nWriteErrors = 0 |
113 self.nWriteErrors = 0 |
91 except socket.error: |
114 except socket.error: |
92 self.nWriteErrors += 1 |
115 self.nWriteErrors += 1 |
93 if self.nWriteErrors > self.maxtries: |
116 if self.nWriteErrors > self.maxtries: |
94 self.wpending = unicode('') # delete all output |
117 self.wpending = [] # delete all output |
95 |
|
96 def pendingWrite(self): |
|
97 """ |
|
98 Public method that returns the number of bytes waiting to be written. |
|
99 |
|
100 @return the number of bytes to be written (int) |
|
101 """ |
|
102 return self.wpending.rfind('\n') + 1 |
|
103 |
|
104 def close(self, closeit=False): |
|
105 """ |
|
106 Public method to close the file. |
|
107 |
|
108 @param closeit flag to indicate a close ordered by the debugger code |
|
109 (boolean) |
|
110 """ |
|
111 if closeit and not self.closed: |
|
112 self.flush() |
|
113 self.sock.close() |
|
114 self.closed = True |
|
115 |
|
116 def flush(self): |
|
117 """ |
|
118 Public method to write all pending bytes. |
|
119 """ |
|
120 self.__nWrite(len(self.wpending)) |
|
121 |
118 |
122 def isatty(self): |
119 def isatty(self): |
123 """ |
120 """ |
124 Public method to indicate whether a tty interface is supported. |
121 Public method to indicate whether a tty interface is supported. |
125 |
122 |
126 @return always false |
123 @return always false |
|
124 @rtype bool |
127 """ |
125 """ |
128 return False |
126 return False |
129 |
127 |
130 def fileno(self): |
128 def fileno(self): |
131 """ |
129 """ |
132 Public method returning the file number. |
130 Public method returning the file number. |
133 |
131 |
134 @return file number (int) |
132 @return file number |
|
133 @rtype int |
135 """ |
134 """ |
136 try: |
135 try: |
137 return self.sock.fileno() |
136 return self.sock.fileno() |
138 except socket.error: |
137 except socket.error: |
139 return -1 |
138 return -1 |
140 |
139 |
141 def readable(self): |
140 def readable(self): |
142 """ |
141 """ |
143 Public method to check, if the stream is readable. |
142 Public method to check, if the stream is readable. |
144 |
143 |
145 @return flag indicating a readable stream (boolean) |
144 @return flag indicating a readable stream |
|
145 @rtype bool |
146 """ |
146 """ |
147 return self.mode == "r" |
147 return self.mode == "r" |
148 |
148 |
149 def read_p(self, size=-1): |
149 def read_p(self, size=-1): |
150 """ |
150 """ |
151 Public method to read bytes from this file. |
151 Public method to read bytes from this file. |
152 |
152 |
153 @param size maximum number of bytes to be read (int) |
153 @param size maximum number of bytes to be read |
154 @return the bytes read (any) |
154 @type int |
|
155 @return the bytes read |
|
156 @rtype str |
155 """ |
157 """ |
156 self.__checkMode('r') |
158 self.__checkMode('r') |
157 |
159 |
158 if size < 0: |
160 if size < 0: |
159 size = 20000 |
161 size = 20000 |
278 |
291 |
279 def truncate(self, size=-1): |
292 def truncate(self, size=-1): |
280 """ |
293 """ |
281 Public method to truncate the file. |
294 Public method to truncate the file. |
282 |
295 |
283 @param size size to truncate to (integer) |
296 @param size size to truncate to |
|
297 @type int |
284 @exception IOError This method is not supported and always raises an |
298 @exception IOError This method is not supported and always raises an |
285 IOError. |
299 IOError. |
286 """ |
300 """ |
287 raise IOError((29, '[Errno 29] Illegal seek')) |
301 raise IOError((29, '[Errno 29] Illegal seek')) |
288 |
302 |
289 def writable(self): |
303 def writable(self): |
290 """ |
304 """ |
291 Public method to check, if a stream is writable. |
305 Public method to check, if a stream is writable. |
292 |
306 |
293 @return flag indicating a writable stream (boolean) |
307 @return flag indicating a writable stream |
|
308 @rtype bool |
294 """ |
309 """ |
295 return self.mode == "w" |
310 return self.mode == "w" |
296 |
311 |
297 def write(self, s): |
312 def write(self, s): |
298 """ |
313 """ |
299 Public method to write a string to the file. |
314 Public method to write a string to the file. |
300 |
315 |
301 @param s text to be written (string) |
316 @param s text to be written |
|
317 @type str |
302 """ |
318 """ |
303 self.__checkMode('w') |
319 self.__checkMode('w') |
304 |
320 |
305 cmd = prepareJsonCommand("ClientOutput", { |
321 cmd = prepareJsonCommand("ClientOutput", { |
306 "text": s, |
322 "text": s, |
307 }) |
323 }) |
308 self.write_p(cmd) |
324 self.wpending.append(cmd) |
|
325 self.flush() |
309 |
326 |
310 def write_p(self, s): |
327 def write_p(self, s): |
311 """ |
328 """ |
312 Public method to write a string to the file. |
329 Public method to write a json-rpc 2.0 coded string to the file. |
313 |
330 |
314 @param s text to be written (string) |
331 @param s text to be written |
315 @exception socket.error raised to indicate too many send attempts |
332 @type str |
316 """ |
333 """ |
317 self.__checkMode('w') |
334 self.__checkMode('w') |
318 tries = 0 |
335 |
319 if not self.wpending: |
336 self.wpending.append(s) |
320 self.wpending = s |
337 self.flush() |
321 elif len(self.wpending) + len(s) > self.maxbuffersize: |
|
322 # flush wpending if it is too big |
|
323 while self.wpending: |
|
324 # if we have a persistent error in sending the data, an |
|
325 # exception will be raised in __nWrite |
|
326 self.flush() |
|
327 tries += 1 |
|
328 if tries > self.maxtries: |
|
329 raise socket.error("Too many attempts to send data") |
|
330 self.wpending = s |
|
331 else: |
|
332 self.wpending += s |
|
333 self.__nWrite(self.pendingWrite()) |
|
334 |
338 |
335 def writelines(self, lines): |
339 def writelines(self, lines): |
336 """ |
340 """ |
337 Public method to write a list of strings to the file. |
341 Public method to write a list of strings to the file. |
338 |
342 |
339 @param lines list of texts to be written (list of string) |
343 @param lines list of texts to be written |
|
344 @type list of str |
340 """ |
345 """ |
341 self.write("".join(lines)) |
346 self.write("".join(lines)) |
342 |
347 |
343 # |
348 # |
344 # eflag: noqa = M702 |
349 # eflag: noqa = M702 |