def __init__(self, popen, select_task, on_stdout=None, on_stderr=None, on_exit=None, encoding=None): # Configure a logger first self.logger = logging.getLogger('sparts.process_stream_handler') # Keep track of inputs (callbacks, proc, fds, select loop, ...) self.select_task = select_task self._outfd = popen.stdout.fileno() self._errfd = popen.stderr.fileno() self._popen = popen self.stderr_callback = on_stderr self.stdout_callback = on_stdout self.exit_callback = on_exit # Set up a sane default for decoding stdout if encoding is None: self.encoding = getattr(sys.stdout, 'encoding') if self.encoding is None: self.encoding = sys.getdefaultencoding() else: self.encoding = encoding # Prepare and connect FDs set_nonblocking(self._outfd) set_nonblocking(self._errfd) self.select_task.register_read(self._outfd, self._on_stdout) self.select_task.register_read(self._errfd, self._on_stderr)
def initTask(self): # Flag to check on each iteration self._select_running = True # Allocate some pipes for meta-select control commands self.__rcontrol, self.__wcontrol = os.pipe() set_nonblocking(self.__rcontrol) # Declare callback lookup dicts self._rcallbacks = {} self._wcallbacks = {} self._xcallbacks = {} self.register_read(self.__rcontrol, self._on_control) super(SelectTask, self).initTask()
def test_nonblock(self): rfd, wfd = os.pipe() fileutils.set_nonblocking(rfd) # Read on an nonblocking fd when no data is available, will # result in an OSError with EAGAIN. Confirm it. with self.assertRaises(OSError) as cm: os.read(rfd, 1) # python-2.6's context manager implementation returns an incorrect # value of `exc_value`. Let's patch around this in the unittest for # now, but it may be worth generalizing a better solution in the # BaseSpartsTestCase wrapper long term. # See http://bugs.python.org/issue7853 for details. if sys.version < '2.7': cm.exception = OSError(*cm.exception) # Check the exception's errno self.assertEqual(cm.exception.errno, errno.EAGAIN)
def test_read_event(self): r, w = os.pipe() set_nonblocking(r) try: fired = threading.Event() def on_event(fd): self.logger.info('on_event(%s)', fd) self.assertEqual(fd, r) fired.set() self.task.register_read(r, on_event) os.write(w, six.b('1')) fired.wait(3.0) self.assertTrue(fired.is_set()) cb = self.task.unregister_read(r) self.assertEqual(cb, on_event) finally: os.close(r) os.close(w)