From 4a1f0bef627d07f22e66ddf39aa381bfd27a0368 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 25 Oct 2019 09:07:23 +0200 Subject: [PATCH 1/3] test_uses_current_stdin --- testing/test_readline.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/testing/test_readline.py b/testing/test_readline.py index a9a2a2c..e9a704d 100644 --- a/testing/test_readline.py +++ b/testing/test_readline.py @@ -6,6 +6,9 @@ from pyrepl.readline import _ReadlineWrapper +pytest_plugins = ["pytester"] + + @pytest.fixture def readline_wrapper(): master, slave = pty.openpty() @@ -103,3 +106,38 @@ def replace(cls, *args): readline_wrapper.write_history_file(str(histfile)) assert open(str(histfile), "r").readlines() == ["foo\n", "bar\n"] + + +@pytest.mark.parametrize("use_pyrepl", (True, False)) +def test_uses_current_stdin(use_pyrepl, testdir): + p1 = testdir.makepyfile(""" + import io, os, sys + + assert os.isatty(0) + dup_stdin = io.FileIO(os.dup(0)) + assert os.isatty(dup_stdin.fileno()) + + old_stdin = sys.stdin + sys.stdin = dup_stdin + + if {use_pyrepl!r}: + import pyrepl.readline + + print("input1:", input()) + dup_stdin.close() + + sys.stdin = old_stdin + print("input2:", input()) + """.format(use_pyrepl=use_pyrepl)) + + child = testdir.spawn(sys.executable + " " + str(p1), expect_timeout=1) + child.sendline("line1") + if use_pyrepl: + child.expect_exact("input1: line1\r\n") + else: + child.expect_exact("input1: b'line1'\r\n") + child.sendline("line2") + if use_pyrepl: + child.expect_exact("input2: line2\r\n") + else: + child.expect_exact(b'line2\r\ninput2: line2\r\n') From 051b9e4a28e955eb61d3c12ab2cbd218e0d6e295 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 25 Oct 2019 09:36:48 +0200 Subject: [PATCH 2/3] revisit stdin/stdout/stderr handling Reverts/changes 3ff3cfa. Unfortunately the example at https://github.com/pytest-dev/pytest/issues/5134 appears to be for py2 - at least it did not compile for me when trying it. --- pyrepl/readline.py | 47 +++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/pyrepl/readline.py b/pyrepl/readline.py index 8ac466d..8436c3c 100644 --- a/pyrepl/readline.py +++ b/pyrepl/readline.py @@ -189,22 +189,30 @@ class _ReadlineWrapper(object): saved_history_length = -1 startup_hook = None config = ReadlineConfig() - stdin = None - stdout = None - stderr = None - def __init__(self, f_in=None, f_out=None): - self.f_in = f_in if f_in is not None else os.dup(0) - self.f_out = f_out if f_out is not None else os.dup(1) + # Forced input/output, otherwise sys.stdin/sys.stdout will be used. + f_in = None + f_out = None - def setup_std_streams(self, stdin, stdout, stderr): - self.stdin = stdin - self.stdout = stdout - self.stderr = stderr + def __init__(self, f_in=None, f_out=None): + if f_in is not None: + self.f_in = f_in + if f_out is not None: + self.f_out = f_out def get_reader(self): - if self.reader is None: - console = UnixConsole(self.f_in, self.f_out, encoding=ENCODING) + if self.f_in is None: + fd_in = sys.stdin.fileno() + else: + fd_in = self.f_in + if self.f_out is None: + fd_out = sys.stdout.fileno() + else: + fd_out = self.f_out + if (self.reader is None + or fd_in != self.reader.console.input_fd + or fd_out != self.reader.console.output_fd): + console = UnixConsole(fd_in, fd_out, encoding=ENCODING) self.reader = ReadlineAlikeReader(console) self.reader.config = self.config return self.reader @@ -221,10 +229,14 @@ def raw_input(self, prompt=''): # behavior: it seems to be the correct thing to do, and moreover it # mitigates this pytest issue: # https://github.com/pytest-dev/pytest/issues/5134 - if self.stdout and hasattr(self.stdout, 'flush'): - self.stdout.flush() - if self.stderr and hasattr(self.stderr, 'flush'): - self.stderr.flush() + try: + sys.stdout.flush() + except AttributeError: + pass + try: + sys.stderr.flush() + except AttributeError: + pass ret = reader.readline(startup_hook=self.startup_hook) if not PY3: @@ -447,9 +459,6 @@ def _setup(): if not os.isatty(f_in) or not os.isatty(f_out): return - _wrapper.f_in = f_in - _wrapper.f_out = f_out - _wrapper.setup_std_streams(sys.stdin, sys.stdout, sys.stderr) if '__pypy__' in sys.builtin_module_names: # PyPy From 55873eabae10ea7da3e5af0ac07d71bb4fd88e55 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 25 Oct 2019 09:44:53 +0200 Subject: [PATCH 3/3] --cov-config for subprocesses --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 7a38e47..b90e99a 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ commands = passenv = TERM setenv = - coverage: PYTEST_ADDOPTS=--cov {env:PYTEST_ADDOPTS:} + coverage: PYTEST_ADDOPTS=--cov --cov-config={toxinidir}/tox.ini {env:PYTEST_ADDOPTS:} [testenv:qa] deps =