mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Merge pull request #962 from kennethreitz/pexpect-fix
update the vendored pexpect for python 3.7 async support to fix #956
This commit is contained in:
@@ -12,22 +12,30 @@ def expect_async(expecter, timeout=None):
|
||||
idx = expecter.new_data(previously_read)
|
||||
if idx is not None:
|
||||
return idx
|
||||
|
||||
transport, pw = yield from asyncio.get_event_loop()\
|
||||
.connect_read_pipe(lambda: PatternWaiter(expecter), expecter.spawn)
|
||||
|
||||
if not expecter.spawn.async_pw_transport:
|
||||
pw = PatternWaiter()
|
||||
pw.set_expecter(expecter)
|
||||
transport, pw = yield from asyncio.get_event_loop()\
|
||||
.connect_read_pipe(lambda: pw, expecter.spawn)
|
||||
expecter.spawn.async_pw_transport = pw, transport
|
||||
else:
|
||||
pw, transport = expecter.spawn.async_pw_transport
|
||||
pw.set_expecter(expecter)
|
||||
transport.resume_reading()
|
||||
try:
|
||||
return (yield from asyncio.wait_for(pw.fut, timeout))
|
||||
except asyncio.TimeoutError as e:
|
||||
transport.pause_reading()
|
||||
return expecter.timeout(e)
|
||||
|
||||
|
||||
class PatternWaiter(asyncio.Protocol):
|
||||
transport = None
|
||||
def __init__(self, expecter):
|
||||
|
||||
def set_expecter(self, expecter):
|
||||
self.expecter = expecter
|
||||
self.fut = asyncio.Future()
|
||||
|
||||
|
||||
def found(self, result):
|
||||
if not self.fut.done():
|
||||
self.fut.set_result(result)
|
||||
Vendored
+3
-4
@@ -79,7 +79,6 @@ class Expecter(object):
|
||||
def expect_loop(self, timeout=-1):
|
||||
"""Blocking expect"""
|
||||
spawn = self.spawn
|
||||
from . import EOF, TIMEOUT
|
||||
|
||||
if timeout is not None:
|
||||
end_time = time.time() + timeout
|
||||
@@ -161,7 +160,7 @@ class searcher_string(object):
|
||||
return '\n'.join(ss)
|
||||
|
||||
def search(self, buffer, freshlen, searchwindowsize=None):
|
||||
'''This searches 'buffer' for the first occurence of one of the search
|
||||
'''This searches 'buffer' for the first occurrence of one of the search
|
||||
strings. 'freshlen' must indicate the number of bytes at the end of
|
||||
'buffer' which have not been searched before. It helps to avoid
|
||||
searching the same, possibly big, buffer over and over again.
|
||||
@@ -220,7 +219,7 @@ class searcher_re(object):
|
||||
|
||||
start - index into the buffer, first byte of match
|
||||
end - index into the buffer, first byte after match
|
||||
match - the re.match object returned by a succesful re.search
|
||||
match - the re.match object returned by a successful re.search
|
||||
|
||||
'''
|
||||
|
||||
@@ -267,7 +266,7 @@ class searcher_re(object):
|
||||
return '\n'.join(ss)
|
||||
|
||||
def search(self, buffer, freshlen, searchwindowsize=None):
|
||||
'''This searches 'buffer' for the first occurence of one of the regular
|
||||
'''This searches 'buffer' for the first occurrence of one of the regular
|
||||
expressions. 'freshlen' must indicate the number of bytes at the end of
|
||||
'buffer' which have not been searched before.
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
'''This is like pexpect, but it will work with any file descriptor that you
|
||||
pass it. You are reponsible for opening and close the file descriptor.
|
||||
pass it. You are responsible for opening and close the file descriptor.
|
||||
This allows you to use Pexpect with sockets and named pipes (FIFOs).
|
||||
|
||||
PEXPECT LICENSE
|
||||
|
||||
Vendored
+7
-3
@@ -106,8 +106,9 @@ class spawn(SpawnBase):
|
||||
child = pexpect.spawn('some_command')
|
||||
child.logfile = sys.stdout
|
||||
|
||||
# In Python 3, spawnu should be used to give str to stdout:
|
||||
child = pexpect.spawnu('some_command')
|
||||
# In Python 3, we'll use the ``encoding`` argument to decode data
|
||||
# from the subprocess and handle it as unicode:
|
||||
child = pexpect.spawn('some_command', encoding='utf-8')
|
||||
child.logfile = sys.stdout
|
||||
|
||||
The logfile_read and logfile_send members can be used to separately log
|
||||
@@ -315,7 +316,10 @@ class spawn(SpawnBase):
|
||||
and SIGINT). '''
|
||||
|
||||
self.flush()
|
||||
self.ptyproc.close(force=force)
|
||||
with _wrap_ptyprocess_err():
|
||||
# PtyProcessError may be raised if it is not possible to terminate
|
||||
# the child.
|
||||
self.ptyproc.close(force=force)
|
||||
self.isalive() # Update exit status from ptyproc
|
||||
self.child_fd = -1
|
||||
|
||||
|
||||
Vendored
+3
-3
@@ -114,12 +114,12 @@ class pxssh (spawn):
|
||||
#prompt command different than the regex.
|
||||
|
||||
# used to match the command-line prompt
|
||||
self.UNIQUE_PROMPT = "\[PEXPECT\][\$\#] "
|
||||
self.UNIQUE_PROMPT = r"\[PEXPECT\][\$\#] "
|
||||
self.PROMPT = self.UNIQUE_PROMPT
|
||||
|
||||
# used to set shell command-line prompt to UNIQUE_PROMPT.
|
||||
self.PROMPT_SET_SH = "PS1='[PEXPECT]\$ '"
|
||||
self.PROMPT_SET_CSH = "set prompt='[PEXPECT]\$ '"
|
||||
self.PROMPT_SET_SH = r"PS1='[PEXPECT]\$ '"
|
||||
self.PROMPT_SET_CSH = r"set prompt='[PEXPECT]\$ '"
|
||||
self.SSH_OPTS = ("-o'RSAAuthentication=no'"
|
||||
+ " -o 'PubkeyAuthentication=no'")
|
||||
# Disabling host key checking, makes you vulnerable to MITM attacks.
|
||||
|
||||
Vendored
+1
-1
@@ -69,7 +69,7 @@ def constrain (n, min, max):
|
||||
|
||||
class screen:
|
||||
'''This object maintains the state of a virtual text screen as a
|
||||
rectangluar array. This maintains a virtual cursor position and handles
|
||||
rectangular array. This maintains a virtual cursor position and handles
|
||||
scrolling as characters are added. This supports most of the methods needed
|
||||
by an ANSI text screen. Row and column indexes are 1-based (not zero-based,
|
||||
like arrays).
|
||||
|
||||
Vendored
+28
-14
@@ -115,6 +115,8 @@ class SpawnBase(object):
|
||||
self.linesep = os.linesep.decode('ascii')
|
||||
# This can handle unicode in both Python 2 and 3
|
||||
self.write_to_stdout = sys.stdout.write
|
||||
# storage for async transport
|
||||
self.async_pw_transport = None
|
||||
|
||||
def _log(self, s, direction):
|
||||
if self.logfile is not None:
|
||||
@@ -221,7 +223,7 @@ class SpawnBase(object):
|
||||
self._pattern_type_err(p)
|
||||
return compiled_pattern_list
|
||||
|
||||
def expect(self, pattern, timeout=-1, searchwindowsize=-1, async=False):
|
||||
def expect(self, pattern, timeout=-1, searchwindowsize=-1, async_=False, **kw):
|
||||
'''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.
|
||||
@@ -305,7 +307,7 @@ class SpawnBase(object):
|
||||
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,
|
||||
``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::
|
||||
|
||||
@@ -313,15 +315,19 @@ class SpawnBase(object):
|
||||
|
||||
With this non-blocking form::
|
||||
|
||||
index = yield from p.expect(patterns, async=True)
|
||||
index = yield from p.expect(patterns, async_=True)
|
||||
'''
|
||||
if 'async' in kw:
|
||||
async_ = kw.pop('async')
|
||||
if kw:
|
||||
raise TypeError("Unknown keyword arguments: {}".format(kw))
|
||||
|
||||
compiled_pattern_list = self.compile_pattern_list(pattern)
|
||||
return self.expect_list(compiled_pattern_list,
|
||||
timeout, searchwindowsize, async)
|
||||
timeout, searchwindowsize, async_)
|
||||
|
||||
def expect_list(self, pattern_list, timeout=-1, searchwindowsize=-1,
|
||||
async=False):
|
||||
async_=False, **kw):
|
||||
'''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
|
||||
@@ -331,21 +337,25 @@ class SpawnBase(object):
|
||||
the expect() method. This is called by expect().
|
||||
|
||||
|
||||
Like :meth:`expect`, passing ``async=True`` will make this return an
|
||||
Like :meth:`expect`, passing ``async_=True`` will make this return an
|
||||
asyncio coroutine.
|
||||
'''
|
||||
if timeout == -1:
|
||||
timeout = self.timeout
|
||||
if 'async' in kw:
|
||||
async_ = kw.pop('async')
|
||||
if kw:
|
||||
raise TypeError("Unknown keyword arguments: {}".format(kw))
|
||||
|
||||
exp = Expecter(self, searcher_re(pattern_list), searchwindowsize)
|
||||
if async:
|
||||
from .async import expect_async
|
||||
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):
|
||||
async_=False, **kw):
|
||||
|
||||
'''This is similar to expect(), but uses plain string matching instead
|
||||
of compiled regular expressions in 'pattern_list'. The 'pattern_list'
|
||||
@@ -359,11 +369,15 @@ class SpawnBase(object):
|
||||
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
|
||||
Like :meth:`expect`, passing ``async_=True`` will make this return an
|
||||
asyncio coroutine.
|
||||
'''
|
||||
if timeout == -1:
|
||||
timeout = self.timeout
|
||||
if 'async' in kw:
|
||||
async_ = kw.pop('async')
|
||||
if kw:
|
||||
raise TypeError("Unknown keyword arguments: {}".format(kw))
|
||||
|
||||
if (isinstance(pattern_list, self.allowed_string_types) or
|
||||
pattern_list in (TIMEOUT, EOF)):
|
||||
@@ -383,8 +397,8 @@ class SpawnBase(object):
|
||||
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
|
||||
if async_:
|
||||
from ._async import expect_async
|
||||
return expect_async(exp, timeout)
|
||||
else:
|
||||
return exp.expect_loop(timeout)
|
||||
@@ -415,7 +429,7 @@ class SpawnBase(object):
|
||||
|
||||
# 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.
|
||||
# I would catch any bugs early and ensure consistent 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
|
||||
@@ -487,7 +501,7 @@ class SpawnBase(object):
|
||||
# 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.
|
||||
|
||||
Reference in New Issue
Block a user