2014-09-17 02:43:19 +00:00
|
|
|
class QueueFile(object):
|
2016-03-29 21:01:15 +00:00
|
|
|
""" Class which implements a file-like interface and reads QueueResult's from a blocking
|
2014-09-17 02:43:19 +00:00
|
|
|
multiprocessing queue.
|
|
|
|
"""
|
|
|
|
def __init__(self, queue, name=None):
|
|
|
|
self._queue = queue
|
|
|
|
self._closed = False
|
|
|
|
self._done = False
|
|
|
|
self._buffer = ''
|
|
|
|
self._total_size = 0
|
|
|
|
self._name = name
|
2014-10-08 17:43:12 +00:00
|
|
|
self.raised_exception = False
|
|
|
|
self._exception_handlers = []
|
|
|
|
|
|
|
|
def add_exception_handler(self, handler):
|
|
|
|
self._exception_handlers.append(handler)
|
2014-09-17 02:43:19 +00:00
|
|
|
|
2016-03-29 21:01:15 +00:00
|
|
|
def read(self, size=-1):
|
|
|
|
# If the queuefile was closed or we have finished, send back any remaining data.
|
2014-09-17 02:43:19 +00:00
|
|
|
if self._closed or self._done:
|
2016-03-29 21:01:15 +00:00
|
|
|
if size == -1:
|
|
|
|
buf = self._buffer
|
|
|
|
self._buffer = ''
|
|
|
|
return buf
|
|
|
|
|
2014-10-16 16:54:16 +00:00
|
|
|
buf = self._buffer[0:size]
|
|
|
|
self._buffer = self._buffer[size:]
|
|
|
|
return buf
|
2014-09-17 02:43:19 +00:00
|
|
|
|
2016-03-29 21:01:15 +00:00
|
|
|
# Loop until we reach the requested data size (or forever if all data was requested).
|
|
|
|
while (len(self._buffer) < size) or (size == -1):
|
2014-09-17 02:43:19 +00:00
|
|
|
result = self._queue.get(block=True)
|
2014-09-29 16:54:22 +00:00
|
|
|
|
2016-03-29 21:01:15 +00:00
|
|
|
# Check for any exceptions raised by the queue process.
|
|
|
|
if result.exception is not None:
|
2014-09-29 16:54:22 +00:00
|
|
|
self._closed = True
|
2014-10-08 17:43:12 +00:00
|
|
|
self.raised_exception = True
|
2014-10-08 18:18:41 +00:00
|
|
|
|
2016-03-29 21:01:15 +00:00
|
|
|
# Fire off the exception to any registered handlers. If no handlers were registered,
|
|
|
|
# then raise the exception locally.
|
2014-10-08 18:18:41 +00:00
|
|
|
handled = False
|
2014-10-08 17:43:12 +00:00
|
|
|
for handler in self._exception_handlers:
|
2016-03-29 21:01:15 +00:00
|
|
|
handler(result.exception)
|
2014-10-08 18:18:41 +00:00
|
|
|
handled = True
|
2014-11-24 21:07:38 +00:00
|
|
|
|
2014-10-08 18:18:41 +00:00
|
|
|
if handled:
|
2016-05-13 22:29:57 +00:00
|
|
|
return ''
|
2016-03-29 21:01:15 +00:00
|
|
|
else:
|
|
|
|
raise result.exception
|
2014-10-08 18:18:41 +00:00
|
|
|
|
2016-03-29 21:01:15 +00:00
|
|
|
# Check for no further data. If the QueueProcess has finished producing data, then break
|
|
|
|
# out of the loop to return the data already acquired.
|
|
|
|
if result.data is None:
|
|
|
|
self._done = True
|
|
|
|
break
|
|
|
|
|
|
|
|
# Add the data to the buffer.
|
|
|
|
self._buffer += result.data
|
|
|
|
self._total_size += len(result.data)
|
2014-09-29 16:54:22 +00:00
|
|
|
|
2016-03-29 21:01:15 +00:00
|
|
|
# Return the requested slice of the buffer.
|
|
|
|
if size == -1:
|
|
|
|
buf = self._buffer
|
|
|
|
self._buffer = ''
|
|
|
|
return buf
|
2014-11-24 21:07:38 +00:00
|
|
|
|
2014-09-17 02:43:19 +00:00
|
|
|
buf = self._buffer[0:size]
|
|
|
|
self._buffer = self._buffer[size:]
|
|
|
|
return buf
|
|
|
|
|
|
|
|
def flush(self):
|
2016-03-29 21:01:15 +00:00
|
|
|
# Purposefully not implemented.
|
2014-09-17 02:43:19 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self._closed = True
|