Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
18
venv/Lib/site-packages/winpty/__init__.py
Normal file
18
venv/Lib/site-packages/winpty/__init__.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Pywinpty
|
||||
========
|
||||
This package provides a Cython wrapper around winpty C++ library.
|
||||
"""
|
||||
|
||||
# yapf: disable
|
||||
|
||||
# Local imports
|
||||
from .ptyprocess import PtyProcess
|
||||
from .winpty_wrapper import PTY
|
||||
|
||||
|
||||
PTY
|
||||
PtyProcess
|
||||
VERSION_INFO = (0, 5, 7)
|
||||
__version__ = '.'.join(map(str, VERSION_INFO))
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
venv/Lib/site-packages/winpty/_winpty/__init__.py
Normal file
2
venv/Lib/site-packages/winpty/_winpty/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Winpty headers."""
|
Binary file not shown.
BIN
venv/Lib/site-packages/winpty/cywinpty.cp36-win32.pyd
Normal file
BIN
venv/Lib/site-packages/winpty/cywinpty.cp36-win32.pyd
Normal file
Binary file not shown.
BIN
venv/Lib/site-packages/winpty/libgcc_s_dw2-1.dll
Normal file
BIN
venv/Lib/site-packages/winpty/libgcc_s_dw2-1.dll
Normal file
Binary file not shown.
BIN
venv/Lib/site-packages/winpty/libwinpthread-1.dll
Normal file
BIN
venv/Lib/site-packages/winpty/libwinpthread-1.dll
Normal file
Binary file not shown.
357
venv/Lib/site-packages/winpty/ptyprocess.py
Normal file
357
venv/Lib/site-packages/winpty/ptyprocess.py
Normal file
|
@ -0,0 +1,357 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Standard library imports
|
||||
import codecs
|
||||
import os
|
||||
import shlex
|
||||
import signal
|
||||
import socket
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
|
||||
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
from backports.shutil_which import which
|
||||
|
||||
|
||||
# Local imports
|
||||
from .winpty_wrapper import PTY, PY2
|
||||
|
||||
|
||||
class PtyProcess(object):
|
||||
"""This class represents a process running in a pseudoterminal.
|
||||
|
||||
The main constructor is the :meth:`spawn` classmethod.
|
||||
"""
|
||||
|
||||
def __init__(self, pty):
|
||||
assert isinstance(pty, PTY)
|
||||
self.pty = pty
|
||||
self.pid = pty.pid
|
||||
self.read_blocking = bool(os.environ.get('PYWINPTY_BLOCK', 1))
|
||||
self.closed = False
|
||||
self.flag_eof = False
|
||||
|
||||
self.decoder = codecs.getincrementaldecoder('utf-8')(errors='strict')
|
||||
|
||||
# Used by terminate() to give kernel time to update process status.
|
||||
# Time in seconds.
|
||||
self.delayafterterminate = 0.1
|
||||
# Used by close() to give kernel time to update process status.
|
||||
# Time in seconds.
|
||||
self.delayafterclose = 0.1
|
||||
|
||||
# Set up our file reader sockets.
|
||||
self._server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._server.bind(("127.0.0.1", 0))
|
||||
address = self._server.getsockname()
|
||||
self._server.listen(1)
|
||||
|
||||
# Read from the pty in a thread.
|
||||
self._thread = threading.Thread(target=_read_in_thread,
|
||||
args=(address, self.pty, self.read_blocking))
|
||||
self._thread.setDaemon(True)
|
||||
self._thread.start()
|
||||
|
||||
self.fileobj, _ = self._server.accept()
|
||||
self.fd = self.fileobj.fileno()
|
||||
|
||||
@classmethod
|
||||
def spawn(cls, argv, cwd=None, env=None, dimensions=(24, 80)):
|
||||
"""Start the given command in a child process in a pseudo terminal.
|
||||
|
||||
This does all the setting up the pty, and returns an instance of
|
||||
PtyProcess.
|
||||
|
||||
Dimensions of the psuedoterminal used for the subprocess can be
|
||||
specified as a tuple (rows, cols), or the default (24, 80) will be
|
||||
used.
|
||||
"""
|
||||
if isinstance(argv, str):
|
||||
argv = shlex.split(argv, posix=False)
|
||||
|
||||
if not isinstance(argv, (list, tuple)):
|
||||
raise TypeError("Expected a list or tuple for argv, got %r" % argv)
|
||||
|
||||
# Shallow copy of argv so we can modify it
|
||||
argv = argv[:]
|
||||
command = argv[0]
|
||||
env = env or os.environ
|
||||
|
||||
path = env.get('PATH', os.defpath)
|
||||
command_with_path = which(command, path=path)
|
||||
if command_with_path is None:
|
||||
raise FileNotFoundError(
|
||||
'The command was not found or was not ' +
|
||||
'executable: %s.' % command
|
||||
)
|
||||
command = command_with_path
|
||||
argv[0] = command
|
||||
cmdline = ' ' + subprocess.list2cmdline(argv[1:])
|
||||
cwd = cwd or os.getcwd()
|
||||
|
||||
proc = PTY(dimensions[1], dimensions[0])
|
||||
|
||||
# Create the environemnt string.
|
||||
envStrs = []
|
||||
for (key, value) in env.items():
|
||||
envStrs.append('%s=%s' % (key, value))
|
||||
env = '\0'.join(envStrs) + '\0'
|
||||
|
||||
if PY2:
|
||||
command = _unicode(command)
|
||||
cwd = _unicode(cwd)
|
||||
cmdline = _unicode(cmdline)
|
||||
env = _unicode(env)
|
||||
|
||||
if len(argv) == 1:
|
||||
proc.spawn(command, cwd=cwd, env=env)
|
||||
else:
|
||||
proc.spawn(command, cwd=cwd, env=env, cmdline=cmdline)
|
||||
|
||||
inst = cls(proc)
|
||||
inst._winsize = dimensions
|
||||
|
||||
# Set some informational attributes
|
||||
inst.argv = argv
|
||||
if env is not None:
|
||||
inst.env = env
|
||||
if cwd is not None:
|
||||
inst.launch_dir = cwd
|
||||
|
||||
return inst
|
||||
|
||||
@property
|
||||
def exitstatus(self):
|
||||
"""The exit status of the process.
|
||||
"""
|
||||
return self.pty.exitstatus
|
||||
|
||||
def fileno(self):
|
||||
"""This returns the file descriptor of the pty for the child.
|
||||
"""
|
||||
return self.fd
|
||||
|
||||
def close(self, force=False):
|
||||
"""This closes the connection with the child application. Note that
|
||||
calling close() more than once is valid. This emulates standard Python
|
||||
behavior with files. Set force to True if you want to make sure that
|
||||
the child is terminated (SIGKILL is sent if the child ignores
|
||||
SIGINT)."""
|
||||
if not self.closed:
|
||||
self.pty.close()
|
||||
self.fileobj.close()
|
||||
self._server.close()
|
||||
# Give kernel time to update process status.
|
||||
time.sleep(self.delayafterclose)
|
||||
if self.isalive():
|
||||
if not self.terminate(force):
|
||||
raise IOError('Could not terminate the child.')
|
||||
self.fd = -1
|
||||
self.closed = True
|
||||
del self.pty
|
||||
self.pty = None
|
||||
|
||||
def __del__(self):
|
||||
"""This makes sure that no system resources are left open. Python only
|
||||
garbage collects Python objects. OS file descriptors are not Python
|
||||
objects, so they must be handled explicitly. If the child file
|
||||
descriptor was opened outside of this class (passed to the constructor)
|
||||
then this does not close it.
|
||||
"""
|
||||
# It is possible for __del__ methods to execute during the
|
||||
# teardown of the Python VM itself. Thus self.close() may
|
||||
# trigger an exception because os.close may be None.
|
||||
try:
|
||||
self.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def flush(self):
|
||||
"""This does nothing. It is here to support the interface for a
|
||||
File-like object. """
|
||||
pass
|
||||
|
||||
def isatty(self):
|
||||
"""This returns True if the file descriptor is open and connected to a
|
||||
tty(-like) device, else False."""
|
||||
return self.isalive()
|
||||
|
||||
def read(self, size=1024):
|
||||
"""Read and return at most ``size`` characters from the pty.
|
||||
|
||||
Can block if there is nothing to read. Raises :exc:`EOFError` if the
|
||||
terminal was closed.
|
||||
"""
|
||||
data = self.fileobj.recv(size)
|
||||
if not data:
|
||||
self.flag_eof = True
|
||||
raise EOFError('Pty is closed')
|
||||
|
||||
return self.decoder.decode(data, final=False)
|
||||
|
||||
def readline(self):
|
||||
"""Read one line from the pseudoterminal as bytes.
|
||||
|
||||
Can block if there is nothing to read. Raises :exc:`EOFError` if the
|
||||
terminal was closed.
|
||||
"""
|
||||
buf = []
|
||||
while 1:
|
||||
try:
|
||||
ch = self.read(1)
|
||||
except EOFError:
|
||||
return ''.join(buf)
|
||||
buf.append(ch)
|
||||
if ch == '\n':
|
||||
return ''.join(buf)
|
||||
|
||||
def write(self, s):
|
||||
"""Write the string ``s`` to the pseudoterminal.
|
||||
|
||||
Returns the number of bytes written.
|
||||
"""
|
||||
if not self.isalive():
|
||||
raise EOFError('Pty is closed')
|
||||
if PY2:
|
||||
s = _unicode(s)
|
||||
|
||||
success, nbytes = self.pty.write(s)
|
||||
if not success:
|
||||
raise IOError('Write failed')
|
||||
return nbytes
|
||||
|
||||
def terminate(self, force=False):
|
||||
"""This forces a child process to terminate."""
|
||||
if not self.isalive():
|
||||
return True
|
||||
self.kill(signal.SIGINT)
|
||||
time.sleep(self.delayafterterminate)
|
||||
if not self.isalive():
|
||||
return True
|
||||
if force:
|
||||
self.kill(signal.SIGKILL)
|
||||
time.sleep(self.delayafterterminate)
|
||||
if not self.isalive():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def wait(self):
|
||||
"""This waits until the child exits. This is a blocking call. This will
|
||||
not read any data from the child.
|
||||
"""
|
||||
while self.isalive():
|
||||
time.sleep(0.1)
|
||||
return self.exitstatus
|
||||
|
||||
def isalive(self):
|
||||
"""This tests if the child process is running or not. This is
|
||||
non-blocking. If the child was terminated then this will read the
|
||||
exitstatus or signalstatus of the child. This returns True if the child
|
||||
process appears to be running or False if not.
|
||||
"""
|
||||
return self.pty and self.pty.isalive()
|
||||
|
||||
def kill(self, sig=None):
|
||||
"""Kill the process with the given signal.
|
||||
"""
|
||||
os.kill(self.pid, sig)
|
||||
|
||||
def sendcontrol(self, char):
|
||||
'''Helper method that wraps send() with mnemonic access for sending control
|
||||
character to the child (such as Ctrl-C or Ctrl-D). For example, to send
|
||||
Ctrl-G (ASCII 7, bell, '\a')::
|
||||
child.sendcontrol('g')
|
||||
See also, sendintr() and sendeof().
|
||||
'''
|
||||
char = char.lower()
|
||||
a = ord(char)
|
||||
if 97 <= a <= 122:
|
||||
a = a - ord('a') + 1
|
||||
byte = bytes([a])
|
||||
return self.pty.write(byte.decode('utf-8')), byte
|
||||
d = {'@': 0, '`': 0,
|
||||
'[': 27, '{': 27,
|
||||
'\\': 28, '|': 28,
|
||||
']': 29, '}': 29,
|
||||
'^': 30, '~': 30,
|
||||
'_': 31,
|
||||
'?': 127}
|
||||
if char not in d:
|
||||
return 0, b''
|
||||
|
||||
byte = bytes([d[char]])
|
||||
return self.pty.write(byte.decode('utf-8')), byte
|
||||
|
||||
def sendeof(self):
|
||||
"""This sends an EOF to the child. This sends a character which causes
|
||||
the pending parent output buffer to be sent to the waiting child
|
||||
program without waiting for end-of-line. If it is the first character
|
||||
of the line, the read() in the user program returns 0, which signifies
|
||||
end-of-file. This means to work as expected a sendeof() has to be
|
||||
called at the beginning of a line. This method does not send a newline.
|
||||
It is the responsibility of the caller to ensure the eof is sent at the
|
||||
beginning of a line."""
|
||||
# Send control character 4 (Ctrl-D)
|
||||
self.pty.write('\x04'), '\x04'
|
||||
|
||||
def sendintr(self):
|
||||
"""This sends a SIGINT to the child. It does not require
|
||||
the SIGINT to be the first character on a line. """
|
||||
# Send control character 3 (Ctrl-C)
|
||||
self.pty.write('\x03'), '\x03'
|
||||
|
||||
def eof(self):
|
||||
"""This returns True if the EOF exception was ever raised.
|
||||
"""
|
||||
return self.flag_eof
|
||||
|
||||
def getwinsize(self):
|
||||
"""Return the window size of the pseudoterminal as a tuple (rows, cols).
|
||||
"""
|
||||
return self._winsize
|
||||
|
||||
def setwinsize(self, rows, cols):
|
||||
"""Set the terminal window size of the child tty.
|
||||
"""
|
||||
self._winsize = (rows, cols)
|
||||
self.pty.set_size(cols, rows)
|
||||
|
||||
|
||||
def _read_in_thread(address, pty, blocking):
|
||||
"""Read data from the pty in a thread.
|
||||
"""
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
client.connect(address)
|
||||
|
||||
while 1:
|
||||
data = pty.read(4096, blocking=blocking)
|
||||
|
||||
if not data and not pty.isalive():
|
||||
while not data and not pty.iseof():
|
||||
data += pty.read(4096, blocking=blocking)
|
||||
|
||||
if not data:
|
||||
try:
|
||||
client.send(b'')
|
||||
except socket.error:
|
||||
pass
|
||||
break
|
||||
try:
|
||||
client.send(data)
|
||||
except socket.error:
|
||||
break
|
||||
|
||||
client.close()
|
||||
|
||||
|
||||
def _unicode(s):
|
||||
"""Ensure that a string is Unicode on Python 2.
|
||||
"""
|
||||
if isinstance(s, unicode): # noqa E891
|
||||
return s
|
||||
return s.decode('utf-8')
|
2
venv/Lib/site-packages/winpty/tests/__init__.py
Normal file
2
venv/Lib/site-packages/winpty/tests/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""winpty module tests."""
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
61
venv/Lib/site-packages/winpty/tests/test_cywinpty.py
Normal file
61
venv/Lib/site-packages/winpty/tests/test_cywinpty.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Cywinpty tests."""
|
||||
|
||||
# yapf: disable
|
||||
|
||||
# Third party imports
|
||||
from winpty.cywinpty import Agent
|
||||
from winpty.winpty_wrapper import PY2
|
||||
from winpty.ptyprocess import which
|
||||
import pytest
|
||||
|
||||
|
||||
# yapf: disable
|
||||
|
||||
CMD = which('cmd')
|
||||
if PY2:
|
||||
CMD = unicode(CMD) # noqa
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def agent_fixture():
|
||||
def _agent_factory(cols, rows):
|
||||
agent = Agent(cols, rows)
|
||||
return agent
|
||||
return _agent_factory
|
||||
|
||||
|
||||
def test_agent_spawn(agent_fixture):
|
||||
agent = agent_fixture(80, 25)
|
||||
succ = agent.spawn(CMD)
|
||||
assert succ
|
||||
del agent
|
||||
|
||||
|
||||
def test_agent_spawn_fail(agent_fixture):
|
||||
agent = agent_fixture(80, 25)
|
||||
try:
|
||||
agent.spawn(CMD)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
def test_agent_spawn_size_fail(agent_fixture):
|
||||
try:
|
||||
agent_fixture(80, -25)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
def test_agent_resize(agent_fixture):
|
||||
agent = agent_fixture(80, 25)
|
||||
agent.set_size(80, 70)
|
||||
del agent
|
||||
|
||||
|
||||
def test_agent_resize_fail(agent_fixture):
|
||||
agent = agent_fixture(80, 25)
|
||||
try:
|
||||
agent.set_size(-80, 70)
|
||||
except RuntimeError:
|
||||
pass
|
150
venv/Lib/site-packages/winpty/tests/test_ptyprocess.py
Normal file
150
venv/Lib/site-packages/winpty/tests/test_ptyprocess.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""winpty wrapper tests."""
|
||||
|
||||
# yapf: disable
|
||||
|
||||
# Standard library imports
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
|
||||
# Third party imports
|
||||
from flaky import flaky
|
||||
from winpty.ptyprocess import PtyProcess
|
||||
import pytest
|
||||
|
||||
|
||||
# yapf: enable
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pty_fixture():
|
||||
def _pty_factory(cmd=None, env=None):
|
||||
cmd = cmd or 'cmd'
|
||||
return PtyProcess.spawn(cmd, env=env)
|
||||
return _pty_factory
|
||||
|
||||
|
||||
@flaky(max_runs=4, min_passes=1)
|
||||
def test_read(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
loc = os.getcwd()
|
||||
data = ''
|
||||
while loc not in data:
|
||||
data += pty.read()
|
||||
pty.terminate()
|
||||
|
||||
|
||||
def test_write(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
|
||||
text = u'Eggs, ham and spam ünicode'
|
||||
pty.write(text)
|
||||
|
||||
data = ''
|
||||
while text not in data:
|
||||
data += pty.read()
|
||||
pty.terminate()
|
||||
|
||||
|
||||
def test_isalive(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
pty.write('exit\r\n')
|
||||
|
||||
text = 'exit'
|
||||
data = ''
|
||||
while text not in data:
|
||||
data += pty.read()
|
||||
|
||||
while 1:
|
||||
try:
|
||||
pty.read()
|
||||
except EOFError:
|
||||
break
|
||||
|
||||
assert not pty.isalive()
|
||||
pty.terminate()
|
||||
|
||||
|
||||
def test_readline(pty_fixture):
|
||||
env = os.environ.copy()
|
||||
env['foo'] = 'bar'
|
||||
pty = pty_fixture(env=env)
|
||||
pty.write('echo %foo%\r\n')
|
||||
|
||||
while 'bar' not in pty.readline():
|
||||
pass
|
||||
|
||||
pty.terminate()
|
||||
|
||||
|
||||
def test_close(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
pty.close()
|
||||
assert not pty.isalive()
|
||||
|
||||
|
||||
def test_flush(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
pty.flush()
|
||||
pty.terminate()
|
||||
|
||||
|
||||
def test_intr(pty_fixture):
|
||||
pty = pty_fixture(cmd=[sys.executable, 'import time; time.sleep(10)'])
|
||||
pty.sendintr()
|
||||
assert pty.wait() != 0
|
||||
|
||||
|
||||
def test_send_control(pty_fixture):
|
||||
pty = pty_fixture(cmd=[sys.executable, 'import time; time.sleep(10)'])
|
||||
pty.sendcontrol('d')
|
||||
assert pty.wait() != 0
|
||||
|
||||
|
||||
def test_send_eof(pty_fixture):
|
||||
cat = pty_fixture('cat')
|
||||
cat.sendeof()
|
||||
assert cat.wait() == 0
|
||||
|
||||
|
||||
def test_isatty(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
assert pty.isatty()
|
||||
pty.terminate()
|
||||
assert not pty.isatty()
|
||||
|
||||
|
||||
def test_wait(pty_fixture):
|
||||
pty = pty_fixture(cmd=[sys.executable, '--version'])
|
||||
assert pty.wait() == 0
|
||||
|
||||
|
||||
def test_exit_status(pty_fixture):
|
||||
pty = pty_fixture(cmd=[sys.executable])
|
||||
pty.write('import sys;sys.exit(1)\r\n')
|
||||
pty.wait()
|
||||
assert pty.exitstatus == 1
|
||||
|
||||
|
||||
def test_kill(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
pty.kill(signal.SIGTERM)
|
||||
assert not pty.isalive()
|
||||
assert pty.exitstatus == signal.SIGTERM
|
||||
|
||||
|
||||
def test_getwinsize(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
assert pty.getwinsize() == (24, 80)
|
||||
pty.terminate()
|
||||
|
||||
|
||||
def test_setwinsize(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
pty.setwinsize(50, 110)
|
||||
assert pty.getwinsize() == (50, 110)
|
||||
pty.terminate()
|
||||
|
||||
pty = PtyProcess.spawn('cmd', dimensions=(60, 120))
|
||||
assert pty.getwinsize() == (60, 120)
|
||||
pty.terminate()
|
78
venv/Lib/site-packages/winpty/tests/test_winpty_wrapper.py
Normal file
78
venv/Lib/site-packages/winpty/tests/test_winpty_wrapper.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""winpty wrapper tests."""
|
||||
|
||||
# yapf: disable
|
||||
|
||||
# Standard library imports
|
||||
import os
|
||||
|
||||
# Third party imports
|
||||
from flaky import flaky
|
||||
from winpty.winpty_wrapper import PTY, PY2
|
||||
from winpty.ptyprocess import which
|
||||
import pytest
|
||||
|
||||
|
||||
# yapf: enable
|
||||
|
||||
CMD = which('cmd')
|
||||
if PY2:
|
||||
CMD = unicode(CMD) # noqa
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pty_fixture():
|
||||
def _pty_factory():
|
||||
pty = PTY(80, 25)
|
||||
pty.spawn(CMD)
|
||||
return pty
|
||||
return _pty_factory
|
||||
|
||||
|
||||
@flaky(max_runs=4, min_passes=1)
|
||||
def test_read(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
loc = os.getcwd()
|
||||
line = ''
|
||||
while loc not in line:
|
||||
line += pty.read().decode('utf-8')
|
||||
assert loc in line
|
||||
pty.close()
|
||||
del pty
|
||||
|
||||
|
||||
def test_write(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
line = pty.read()
|
||||
while len(line) < 10:
|
||||
line = pty.read()
|
||||
|
||||
text = u'Eggs, ham and spam ünicode'
|
||||
pty.write(text)
|
||||
|
||||
line = u''
|
||||
while text not in line:
|
||||
line += pty.read().decode('utf-8')
|
||||
|
||||
assert text in line
|
||||
|
||||
pty.close()
|
||||
del pty
|
||||
|
||||
|
||||
def test_isalive(pty_fixture):
|
||||
pty = pty_fixture()
|
||||
pty.write(u'exit\r\n')
|
||||
|
||||
text = u'exit'
|
||||
line = u''
|
||||
while text not in line:
|
||||
line += pty.read().decode('utf-8')
|
||||
|
||||
while pty.isalive():
|
||||
pty.read()
|
||||
continue
|
||||
|
||||
assert not pty.isalive()
|
||||
pty.close()
|
||||
del pty
|
BIN
venv/Lib/site-packages/winpty/winpty-agent.exe
Normal file
BIN
venv/Lib/site-packages/winpty/winpty-agent.exe
Normal file
Binary file not shown.
BIN
venv/Lib/site-packages/winpty/winpty.dll
Normal file
BIN
venv/Lib/site-packages/winpty/winpty.dll
Normal file
Binary file not shown.
98
venv/Lib/site-packages/winpty/winpty_wrapper.py
Normal file
98
venv/Lib/site-packages/winpty/winpty_wrapper.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Wrap process I/O pipe communication using pywin32."""
|
||||
|
||||
# yapf: disable
|
||||
|
||||
# Standard library imports
|
||||
from ctypes import windll
|
||||
from ctypes.wintypes import DWORD, LPVOID, HANDLE, BOOL, LPCVOID
|
||||
import ctypes
|
||||
|
||||
# Local imports
|
||||
from .cywinpty import Agent
|
||||
|
||||
import sys
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
|
||||
# yapf: enable
|
||||
|
||||
OPEN_EXISTING = 3
|
||||
GENERIC_WRITE = 0x40000000
|
||||
GENERIC_READ = 0x80000000
|
||||
|
||||
LARGE_INTEGER = ctypes.c_ulong
|
||||
PLARGE_INTEGER = ctypes.POINTER(LARGE_INTEGER)
|
||||
LPOVERLAPPED = LPVOID
|
||||
|
||||
# LPDWORD is not in ctypes.wintypes on Python 2
|
||||
LPDWORD = ctypes.POINTER(DWORD)
|
||||
|
||||
ReadFile = windll.kernel32.ReadFile
|
||||
ReadFile.restype = BOOL
|
||||
ReadFile.argtypes = [HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED]
|
||||
|
||||
WriteFile = windll.kernel32.WriteFile
|
||||
WriteFile.restype = BOOL
|
||||
WriteFile.argtypes = [HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED]
|
||||
|
||||
|
||||
class PTY(Agent):
|
||||
"""
|
||||
This class provides a pywin32 communication wrapper around winpty process
|
||||
communication pipes.
|
||||
|
||||
Inherits all Cython winpty agent functionality and properties.
|
||||
"""
|
||||
|
||||
def __init__(self, cols, rows):
|
||||
"""Initialize a new Pseudo Terminal of size ``(cols, rows)``."""
|
||||
Agent.__init__(self, cols, rows, True)
|
||||
self.conin_pipe = windll.kernel32.CreateFileW(
|
||||
self.conin_pipe_name, GENERIC_WRITE, 0, None, OPEN_EXISTING, 0,
|
||||
None
|
||||
)
|
||||
self.conout_pipe = windll.kernel32.CreateFileW(
|
||||
self.conout_pipe_name, GENERIC_READ, 0, None, OPEN_EXISTING, 0,
|
||||
None
|
||||
)
|
||||
|
||||
def read(self, length=1000, blocking=False):
|
||||
"""
|
||||
Read ``length`` bytes from current process output stream.
|
||||
|
||||
Note: This method is not fully non-blocking, however it
|
||||
behaves like one.
|
||||
"""
|
||||
size_p = PLARGE_INTEGER(LARGE_INTEGER(0))
|
||||
if not blocking:
|
||||
windll.kernel32.GetFileSizeEx(self.conout_pipe, size_p)
|
||||
size = size_p[0]
|
||||
length = min(size, length)
|
||||
data = ctypes.create_string_buffer(length)
|
||||
if length > 0:
|
||||
num_bytes = PLARGE_INTEGER(LARGE_INTEGER(0))
|
||||
ReadFile(self.conout_pipe, data, length, num_bytes, None)
|
||||
return data.value
|
||||
|
||||
def write(self, data):
|
||||
"""Write string data to current process input stream."""
|
||||
data = data.encode('utf-8')
|
||||
data_p = ctypes.create_string_buffer(data)
|
||||
num_bytes = PLARGE_INTEGER(LARGE_INTEGER(0))
|
||||
bytes_to_write = len(data)
|
||||
success = WriteFile(self.conin_pipe, data_p,
|
||||
bytes_to_write, num_bytes, None)
|
||||
return success, num_bytes[0]
|
||||
|
||||
def close(self):
|
||||
"""Close all communication process streams."""
|
||||
windll.kernel32.CloseHandle(self.conout_pipe)
|
||||
windll.kernel32.CloseHandle(self.conin_pipe)
|
||||
|
||||
def iseof(self):
|
||||
"""Check if current process streams are still open."""
|
||||
succ = windll.kernel32.PeekNamedPipe(
|
||||
self.conout_pipe, None, None, None, None, None
|
||||
)
|
||||
return not bool(succ)
|
Loading…
Add table
Add a link
Reference in a new issue