15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""This is like pexpect, but will work on any file descriptor that you pass it.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)You are reponsible for opening and close the file descriptor.
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PEXPECT LICENSE
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    This license is approved by the OSI and FSF as GPL-compatible.
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        http://opensource.org/licenses/isc-license.txt
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Copyright (c) 2012, Noah Spurrier <noah@noah.org>
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pexpect import *
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__all__ = ['fdspawn']
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class fdspawn (spawn):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """This is like pexpect.spawn but allows you to supply your own open file
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    descriptor. For example, you could use it to read through a file looking
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for patterns, or to control a modem or serial device. """
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __init__ (self, fd, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None):
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        """This takes a file descriptor (an int) or an object that support the
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fileno() method (returning an int). All Python file-like objects
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        support fileno(). """
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ### TODO: Add better handling of trying to use fdspawn in place of spawn
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ### TODO: (overload to allow fdspawn to also handle commands as spawn does.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if type(fd) != type(0) and hasattr(fd, 'fileno'):
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fd = fd.fileno()
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if type(fd) != type(0):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            raise ExceptionPexpect ('The fd argument is not an int. If this is a command string then maybe you want to use pexpect.spawn.')
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try: # make sure fd is a valid file descriptor
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            os.fstat(fd)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        except OSError:
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            raise ExceptionPexpect, 'The fd argument is not a valid file descriptor.'
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.args = None
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.command = None
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        spawn.__init__(self, None, args, timeout, maxread, searchwindowsize, logfile)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.child_fd = fd
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.own_fd = False
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.closed = False
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.name = '<file descriptor %d>' % fd
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __del__ (self):
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def close (self):
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if self.child_fd == -1:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if self.own_fd:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.close (self)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.flush()
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            os.close(self.child_fd)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.child_fd = -1
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.closed = True
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def isalive (self):
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        """This checks if the file descriptor is still valid. If os.fstat()
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        does not raise an exception then we assume it is alive. """
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if self.child_fd == -1:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return False
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            os.fstat(self.child_fd)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return True
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        except:
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return False
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def terminate (self, force=False):
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise ExceptionPexpect ('This method is not valid for file descriptors.')
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def kill (self, sig):
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
99