| Index: third_party/pexpect/pexpect/spawnbase.py
|
| diff --git a/third_party/pexpect/pexpect/spawnbase.py b/third_party/pexpect/pexpect/spawnbase.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0518d839765527c7128a5d01e6e73ad8b65ae3c3
|
| --- /dev/null
|
| +++ b/third_party/pexpect/pexpect/spawnbase.py
|
| @@ -0,0 +1,488 @@
|
| +import codecs
|
| +import os
|
| +import sys
|
| +import re
|
| +import errno
|
| +from .exceptions import ExceptionPexpect, EOF, TIMEOUT
|
| +from .expect import Expecter, searcher_string, searcher_re
|
| +
|
| +PY3 = (sys.version_info[0] >= 3)
|
| +text_type = str if PY3 else unicode
|
| +
|
| +class _NullCoder(object):
|
| + """Pass bytes through unchanged."""
|
| + @staticmethod
|
| + def encode(b, final=False):
|
| + return b
|
| +
|
| + @staticmethod
|
| + def decode(b, final=False):
|
| + return b
|
| +
|
| +class SpawnBase(object):
|
| + """A base class providing the backwards-compatible spawn API for Pexpect.
|
| +
|
| + This should not be instantiated directly: use :class:`pexpect.spawn` or
|
| + :class:`pexpect.fdpexpect.fdspawn`.
|
| + """
|
| + encoding = None
|
| + pid = None
|
| + flag_eof = False
|
| +
|
| + def __init__(self, timeout=30, maxread=2000, searchwindowsize=None,
|
| + logfile=None, encoding=None, codec_errors='strict'):
|
| + self.stdin = sys.stdin
|
| + self.stdout = sys.stdout
|
| + self.stderr = sys.stderr
|
| +
|
| + self.searcher = None
|
| + self.ignorecase = False
|
| + self.before = None
|
| + self.after = None
|
| + self.match = None
|
| + self.match_index = None
|
| + self.terminated = True
|
| + self.exitstatus = None
|
| + self.signalstatus = None
|
| + # status returned by os.waitpid
|
| + self.status = None
|
| + # the child file descriptor is initially closed
|
| + self.child_fd = -1
|
| + self.timeout = timeout
|
| + self.delimiter = EOF
|
| + self.logfile = logfile
|
| + # input from child (read_nonblocking)
|
| + self.logfile_read = None
|
| + # output to send (send, sendline)
|
| + self.logfile_send = None
|
| + # max bytes to read at one time into buffer
|
| + self.maxread = maxread
|
| + # This is the read buffer. See maxread.
|
| + self.buffer = bytes() if (encoding is None) else text_type()
|
| + # Data before searchwindowsize point is preserved, but not searched.
|
| + self.searchwindowsize = searchwindowsize
|
| + # Delay used before sending data to child. Time in seconds.
|
| + # Most Linux machines don't like this to be below 0.03 (30 ms).
|
| + self.delaybeforesend = 0.05
|
| + # Used by close() to give kernel time to update process status.
|
| + # Time in seconds.
|
| + self.delayafterclose = 0.1
|
| + # Used by terminate() to give kernel time to update process status.
|
| + # Time in seconds.
|
| + self.delayafterterminate = 0.1
|
| + self.softspace = False
|
| + self.name = '<' + repr(self) + '>'
|
| + self.closed = True
|
| +
|
| + # Unicode interface
|
| + self.encoding = encoding
|
| + self.codec_errors = codec_errors
|
| + if encoding is None:
|
| + # bytes mode (accepts some unicode for backwards compatibility)
|
| + self._encoder = self._decoder = _NullCoder()
|
| + self.string_type = bytes
|
| + self.crlf = b'\r\n'
|
| + if PY3:
|
| + self.allowed_string_types = (bytes, str)
|
| + self.linesep = os.linesep.encode('ascii')
|
| + def write_to_stdout(b):
|
| + try:
|
| + return sys.stdout.buffer.write(b)
|
| + except AttributeError:
|
| + # If stdout has been replaced, it may not have .buffer
|
| + return sys.stdout.write(b.decode('ascii', 'replace'))
|
| + self.write_to_stdout = write_to_stdout
|
| + else:
|
| + self.allowed_string_types = (basestring,) # analysis:ignore
|
| + self.linesep = os.linesep
|
| + self.write_to_stdout = sys.stdout.write
|
| + else:
|
| + # unicode mode
|
| + self._encoder = codecs.getincrementalencoder(encoding)(codec_errors)
|
| + self._decoder = codecs.getincrementaldecoder(encoding)(codec_errors)
|
| + self.string_type = text_type
|
| + self.crlf = u'\r\n'
|
| + self.allowed_string_types = (text_type, )
|
| + if PY3:
|
| + self.linesep = os.linesep
|
| + else:
|
| + self.linesep = os.linesep.decode('ascii')
|
| + # This can handle unicode in both Python 2 and 3
|
| + self.write_to_stdout = sys.stdout.write
|
| +
|
| + def _log(self, s, direction):
|
| + if self.logfile is not None:
|
| + self.logfile.write(s)
|
| + self.logfile.flush()
|
| + second_log = self.logfile_send if (direction=='send') else self.logfile_read
|
| + if second_log is not None:
|
| + second_log.write(s)
|
| + second_log.flush()
|
| +
|
| + # For backwards compatibility, in bytes mode (when encoding is None)
|
| + # unicode is accepted for send and expect. Unicode mode is strictly unicode
|
| + # only.
|
| + def _coerce_expect_string(self, s):
|
| + if self.encoding is None and not isinstance(s, bytes):
|
| + return s.encode('ascii')
|
| + return s
|
| +
|
| + def _coerce_send_string(self, s):
|
| + if self.encoding is None and not isinstance(s, bytes):
|
| + return s.encode('utf-8')
|
| + return s
|
| +
|
| + def read_nonblocking(self, size=1, timeout=None):
|
| + """This reads data from the file descriptor.
|
| +
|
| + This is a simple implementation suitable for a regular file. Subclasses using ptys or pipes should override it.
|
| +
|
| + The timeout parameter is ignored.
|
| + """
|
| +
|
| + try:
|
| + s = os.read(self.child_fd, size)
|
| + except OSError as err:
|
| + if err.args[0] == errno.EIO:
|
| + # Linux-style EOF
|
| + self.flag_eof = True
|
| + raise EOF('End Of File (EOF). Exception style platform.')
|
| + raise
|
| + if s == b'':
|
| + # BSD-style EOF
|
| + self.flag_eof = True
|
| + raise EOF('End Of File (EOF). Empty string style platform.')
|
| +
|
| + s = self._decoder.decode(s, final=False)
|
| + self._log(s, 'read')
|
| + return s
|
| +
|
| + def _pattern_type_err(self, pattern):
|
| + raise TypeError('got {badtype} ({badobj!r}) as pattern, must be one'
|
| + ' of: {goodtypes}, pexpect.EOF, pexpect.TIMEOUT'\
|
| + .format(badtype=type(pattern),
|
| + badobj=pattern,
|
| + goodtypes=', '.join([str(ast)\
|
| + for ast in self.allowed_string_types])
|
| + )
|
| + )
|
| +
|
| + def compile_pattern_list(self, patterns):
|
| + '''This compiles a pattern-string or a list of pattern-strings.
|
| + Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of
|
| + those. Patterns may also be None which results in an empty list (you
|
| + might do this if waiting for an EOF or TIMEOUT condition without
|
| + expecting any pattern).
|
| +
|
| + This is used by expect() when calling expect_list(). Thus expect() is
|
| + nothing more than::
|
| +
|
| + cpl = self.compile_pattern_list(pl)
|
| + return self.expect_list(cpl, timeout)
|
| +
|
| + If you are using expect() within a loop it may be more
|
| + efficient to compile the patterns first and then call expect_list().
|
| + This avoid calls in a loop to compile_pattern_list()::
|
| +
|
| + cpl = self.compile_pattern_list(my_pattern)
|
| + while some_condition:
|
| + ...
|
| + i = self.expect_list(cpl, timeout)
|
| + ...
|
| + '''
|
| +
|
| + if patterns is None:
|
| + return []
|
| + if not isinstance(patterns, list):
|
| + patterns = [patterns]
|
| +
|
| + # Allow dot to match \n
|
| + compile_flags = re.DOTALL
|
| + if self.ignorecase:
|
| + compile_flags = compile_flags | re.IGNORECASE
|
| + compiled_pattern_list = []
|
| + for idx, p in enumerate(patterns):
|
| + if isinstance(p, self.allowed_string_types):
|
| + p = self._coerce_expect_string(p)
|
| + compiled_pattern_list.append(re.compile(p, compile_flags))
|
| + elif p is EOF:
|
| + compiled_pattern_list.append(EOF)
|
| + elif p is TIMEOUT:
|
| + compiled_pattern_list.append(TIMEOUT)
|
| + elif isinstance(p, type(re.compile(''))):
|
| + compiled_pattern_list.append(p)
|
| + else:
|
| + self._pattern_type_err(p)
|
| + return compiled_pattern_list
|
| +
|
| + def expect(self, pattern, timeout=-1, searchwindowsize=-1, async=False):
|
| + '''This seeks through the stream until a pattern is matched. The
|
| + pattern is overloaded and may take several types. The pattern can be a
|
| + StringType, EOF, a compiled re, or a list of any of those types.
|
| + Strings will be compiled to re types. This returns the index into the
|
| + pattern list. If the pattern was not a list this returns index 0 on a
|
| + successful match. This may raise exceptions for EOF or TIMEOUT. To
|
| + avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern
|
| + list. That will cause expect to match an EOF or TIMEOUT condition
|
| + instead of raising an exception.
|
| +
|
| + If you pass a list of patterns and more than one matches, the first
|
| + match in the stream is chosen. If more than one pattern matches at that
|
| + point, the leftmost in the pattern list is chosen. For example::
|
| +
|
| + # the input is 'foobar'
|
| + index = p.expect(['bar', 'foo', 'foobar'])
|
| + # returns 1('foo') even though 'foobar' is a "better" match
|
| +
|
| + Please note, however, that buffering can affect this behavior, since
|
| + input arrives in unpredictable chunks. For example::
|
| +
|
| + # the input is 'foobar'
|
| + index = p.expect(['foobar', 'foo'])
|
| + # returns 0('foobar') if all input is available at once,
|
| + # but returs 1('foo') if parts of the final 'bar' arrive late
|
| +
|
| + When a match is found for the given pattern, the class instance
|
| + attribute *match* becomes an re.MatchObject result. Should an EOF
|
| + or TIMEOUT pattern match, then the match attribute will be an instance
|
| + of that exception class. The pairing before and after class
|
| + instance attributes are views of the data preceding and following
|
| + the matching pattern. On general exception, class attribute
|
| + *before* is all data received up to the exception, while *match* and
|
| + *after* attributes are value None.
|
| +
|
| + When the keyword argument timeout is -1 (default), then TIMEOUT will
|
| + raise after the default value specified by the class timeout
|
| + attribute. When None, TIMEOUT will not be raised and may block
|
| + indefinitely until match.
|
| +
|
| + When the keyword argument searchwindowsize is -1 (default), then the
|
| + value specified by the class maxread attribute is used.
|
| +
|
| + A list entry may be EOF or TIMEOUT instead of a string. This will
|
| + catch these exceptions and return the index of the list entry instead
|
| + of raising the exception. The attribute 'after' will be set to the
|
| + exception type. The attribute 'match' will be None. This allows you to
|
| + write code like this::
|
| +
|
| + index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
|
| + if index == 0:
|
| + do_something()
|
| + elif index == 1:
|
| + do_something_else()
|
| + elif index == 2:
|
| + do_some_other_thing()
|
| + elif index == 3:
|
| + do_something_completely_different()
|
| +
|
| + instead of code like this::
|
| +
|
| + try:
|
| + index = p.expect(['good', 'bad'])
|
| + if index == 0:
|
| + do_something()
|
| + elif index == 1:
|
| + do_something_else()
|
| + except EOF:
|
| + do_some_other_thing()
|
| + except TIMEOUT:
|
| + do_something_completely_different()
|
| +
|
| + These two forms are equivalent. It all depends on what you want. You
|
| + can also just expect the EOF if you are waiting for all output of a
|
| + child to finish. For example::
|
| +
|
| + p = pexpect.spawn('/bin/ls')
|
| + p.expect(pexpect.EOF)
|
| + print p.before
|
| +
|
| + If you are trying to optimize for speed then see expect_list().
|
| +
|
| + On Python 3.4, or Python 3.3 with asyncio installed, passing
|
| + ``async=True`` will make this return an :mod:`asyncio` coroutine,
|
| + which you can yield from to get the same result that this method would
|
| + normally give directly. So, inside a coroutine, you can replace this code::
|
| +
|
| + index = p.expect(patterns)
|
| +
|
| + With this non-blocking form::
|
| +
|
| + index = yield from p.expect(patterns, async=True)
|
| + '''
|
| +
|
| + compiled_pattern_list = self.compile_pattern_list(pattern)
|
| + return self.expect_list(compiled_pattern_list,
|
| + timeout, searchwindowsize, async)
|
| +
|
| + def expect_list(self, pattern_list, timeout=-1, searchwindowsize=-1,
|
| + async=False):
|
| + '''This takes a list of compiled regular expressions and returns the
|
| + index into the pattern_list that matched the child output. The list may
|
| + also contain EOF or TIMEOUT(which are not compiled regular
|
| + expressions). This method is similar to the expect() method except that
|
| + expect_list() does not recompile the pattern list on every call. This
|
| + may help if you are trying to optimize for speed, otherwise just use
|
| + the expect() method. This is called by expect().
|
| +
|
| +
|
| + Like :meth:`expect`, passing ``async=True`` will make this return an
|
| + asyncio coroutine.
|
| + '''
|
| + if timeout == -1:
|
| + timeout = self.timeout
|
| +
|
| + exp = Expecter(self, searcher_re(pattern_list), searchwindowsize)
|
| + if async:
|
| + from .async import expect_async
|
| + return expect_async(exp, timeout)
|
| + else:
|
| + return exp.expect_loop(timeout)
|
| +
|
| + def expect_exact(self, pattern_list, timeout=-1, searchwindowsize=-1,
|
| + async=False):
|
| +
|
| + '''This is similar to expect(), but uses plain string matching instead
|
| + of compiled regular expressions in 'pattern_list'. The 'pattern_list'
|
| + may be a string; a list or other sequence of strings; or TIMEOUT and
|
| + EOF.
|
| +
|
| + This call might be faster than expect() for two reasons: string
|
| + searching is faster than RE matching and it is possible to limit the
|
| + search to just the end of the input buffer.
|
| +
|
| + This method is also useful when you don't want to have to worry about
|
| + escaping regular expression characters that you want to match.
|
| +
|
| + Like :meth:`expect`, passing ``async=True`` will make this return an
|
| + asyncio coroutine.
|
| + '''
|
| + if timeout == -1:
|
| + timeout = self.timeout
|
| +
|
| + if (isinstance(pattern_list, self.allowed_string_types) or
|
| + pattern_list in (TIMEOUT, EOF)):
|
| + pattern_list = [pattern_list]
|
| +
|
| + def prepare_pattern(pattern):
|
| + if pattern in (TIMEOUT, EOF):
|
| + return pattern
|
| + if isinstance(pattern, self.allowed_string_types):
|
| + return self._coerce_expect_string(pattern)
|
| + self._pattern_type_err(pattern)
|
| +
|
| + try:
|
| + pattern_list = iter(pattern_list)
|
| + except TypeError:
|
| + self._pattern_type_err(pattern_list)
|
| + pattern_list = [prepare_pattern(p) for p in pattern_list]
|
| +
|
| + exp = Expecter(self, searcher_string(pattern_list), searchwindowsize)
|
| + if async:
|
| + from .async import expect_async
|
| + return expect_async(exp, timeout)
|
| + else:
|
| + return exp.expect_loop(timeout)
|
| +
|
| + def expect_loop(self, searcher, timeout=-1, searchwindowsize=-1):
|
| + '''This is the common loop used inside expect. The 'searcher' should be
|
| + an instance of searcher_re or searcher_string, which describes how and
|
| + what to search for in the input.
|
| +
|
| + See expect() for other arguments, return value and exceptions. '''
|
| +
|
| + exp = Expecter(self, searcher, searchwindowsize)
|
| + return exp.expect_loop(timeout)
|
| +
|
| + def read(self, size=-1):
|
| + '''This reads at most "size" bytes from the file (less if the read hits
|
| + EOF before obtaining size bytes). If the size argument is negative or
|
| + omitted, read all data until EOF is reached. The bytes are returned as
|
| + a string object. An empty string is returned when EOF is encountered
|
| + immediately. '''
|
| +
|
| + if size == 0:
|
| + return self.string_type()
|
| + if size < 0:
|
| + # delimiter default is EOF
|
| + self.expect(self.delimiter)
|
| + return self.before
|
| +
|
| + # I could have done this more directly by not using expect(), but
|
| + # I deliberately decided to couple read() to expect() so that
|
| + # I would catch any bugs early and ensure consistant behavior.
|
| + # It's a little less efficient, but there is less for me to
|
| + # worry about if I have to later modify read() or expect().
|
| + # Note, it's OK if size==-1 in the regex. That just means it
|
| + # will never match anything in which case we stop only on EOF.
|
| + cre = re.compile(self._coerce_expect_string('.{%d}' % size), re.DOTALL)
|
| + # delimiter default is EOF
|
| + index = self.expect([cre, self.delimiter])
|
| + if index == 0:
|
| + ### FIXME self.before should be ''. Should I assert this?
|
| + return self.after
|
| + return self.before
|
| +
|
| + def readline(self, size=-1):
|
| + '''This reads and returns one entire line. The newline at the end of
|
| + line is returned as part of the string, unless the file ends without a
|
| + newline. An empty string is returned if EOF is encountered immediately.
|
| + This looks for a newline as a CR/LF pair (\\r\\n) even on UNIX because
|
| + this is what the pseudotty device returns. So contrary to what you may
|
| + expect you will receive newlines as \\r\\n.
|
| +
|
| + If the size argument is 0 then an empty string is returned. In all
|
| + other cases the size argument is ignored, which is not standard
|
| + behavior for a file-like object. '''
|
| +
|
| + if size == 0:
|
| + return self.string_type()
|
| + # delimiter default is EOF
|
| + index = self.expect([self.crlf, self.delimiter])
|
| + if index == 0:
|
| + return self.before + self.crlf
|
| + else:
|
| + return self.before
|
| +
|
| + def __iter__(self):
|
| + '''This is to support iterators over a file-like object.
|
| + '''
|
| + return iter(self.readline, self.string_type())
|
| +
|
| + def readlines(self, sizehint=-1):
|
| + '''This reads until EOF using readline() and returns a list containing
|
| + the lines thus read. The optional 'sizehint' argument is ignored.
|
| + Remember, because this reads until EOF that means the child
|
| + process should have closed its stdout. If you run this method on
|
| + a child that is still running with its stdout open then this
|
| + method will block until it timesout.'''
|
| +
|
| + lines = []
|
| + while True:
|
| + line = self.readline()
|
| + if not line:
|
| + break
|
| + lines.append(line)
|
| + return lines
|
| +
|
| + def fileno(self):
|
| + '''Expose file descriptor for a file-like interface
|
| + '''
|
| + return self.child_fd
|
| +
|
| + def flush(self):
|
| + '''This does nothing. It is here to support the interface for a
|
| + File-like object. '''
|
| + pass
|
| +
|
| + def isatty(self):
|
| + """Overridden in subclass using tty"""
|
| + return False
|
| +
|
| + # For 'with spawn(...) as child:'
|
| + def __enter__(self):
|
| + return self
|
| +
|
| + def __exit__(self, etype, evalue, tb):
|
| + # We rely on subclasses to implement close(). If they don't, it's not
|
| + # clear what a context manager should do.
|
| + self.close()
|
|
|