+++ /dev/null
-"""Implements a non-blocking pipe class."""\r
-\r
-# Since it uses thread rather than select, it is portable to at least\r
-# posix and windows environments.\r
-\r
-# Author: Rasjid Wilcox, copyright (c) 2002\r
-# Ideas taken from the Python 2.2 telnetlib.py library.\r
-#\r
-# Last modified: 3 August 2002\r
-# Licence: Python 2.2 Style License. See license.txt.\r
-\r
-# TO DO:\r
-# * Handle excpetions better, particularly Keyboard Interupts.\r
-# * Possibly do a threadless version for posix environments\r
-# where we can use select (is probably more efficient).\r
-# * A test function.\r
-\r
-import Queue\r
-import thread\r
-import os\r
-import time\r
-import types\r
-\r
-#INT_TYPE = type(1)\r
-MIN_TIMEOUT = 0.01\r
-\r
-class nbpipe:\r
- def __init__(self, readfile, pipesize=0, blocksize=1024):\r
- """Initialise a non-blocking pipe object, given a real file or file-descriptor.\r
- pipesize = the size (in blocks) of the queue used to buffer the blocks read\r
- blocksize = the maximum block size for a raw read."""\r
- if type(readfile) == types.IntType:\r
- self.fd = readfile\r
- else:\r
- self.fd = readfile.fileno()\r
- self.pipesize = pipesize\r
- self.blocksize = blocksize\r
- self.eof = 0\r
- self._q = Queue.Queue(self.pipesize)\r
- self.data = ''\r
- thread.start_new_thread(self._readtoq, ())\r
- def _readtoq(self):\r
- finish = 0\r
- while (1):\r
- try:\r
- item = os.read(self.fd, self.blocksize)\r
- except (IOError, OSError):\r
- finish = 1\r
- if (item == '') or finish:\r
- # Wait until everything has been read from the queue before\r
- # setting eof = 1 and exiting.\r
- while not self._q.empty():\r
- time.sleep(MIN_TIMEOUT)\r
- self.eof = 1\r
- thread.exit()\r
- else:\r
- self._q.put(item)\r
- def has_data(self):\r
- return self.data\r
- def eof(self):\r
- return self.eof\r
- def read_lazy(self):\r
- """Process and return data that's already in the queues (lazy).\r
-\r
- Return '' if no data available. Don't block.\r
-\r
- """\r
- while not self._q.empty():\r
- self.data += self._q.get()\r
- data = self.data\r
- self.data = ''\r
- return data\r
- def read_some(self, until_eof=False):\r
- """Read at least one byte of cooked data unless EOF is hit.\r
-\r
- Return '' if EOF is hit. Block if no data is immediately\r
- available.\r
-\r
- """\r
- data = ''\r
- while (until_eof or not data) and not self.eof:\r
- data += self.read_lazy()\r
- time.sleep(MIN_TIMEOUT)\r
- return data\r
- def read_until(self, match, timeout=None):\r
- """Read until a given string is encountered or until timeout.\r
-\r
- If no match is found or EOF is hit, return whatever is\r
- available instead, possibly the empty string.\r
- """\r
- if timeout is not None:\r
- timeout = timeout / MIN_TIMEOUT\r
- else:\r
- timeout = 1\r
- n = len(match)\r
- data = self.read_lazy()\r
- i = 0\r
- while timeout >= 0 and not self.eof:\r
- i = data.find(match, i)\r
- if i >= 0:\r
- i += n\r
- self.data = data[i:]\r
- return data[:i]\r
- time.sleep(MIN_TIMEOUT)\r
- timeout -= 1\r
- i = max(0, len(data) - n)\r
- data += self.read_lazy()\r
- return data\r
- def read_all(self):\r
- """Read until the EOF. May block."""\r
- return read_some(until_eof=True)\r