Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e44dba3

Browse files
committed
Issue #24402: Factor out PtyTests.run_child() in input() tests
This reuses existing code to hopefully make the new test_input_no_stdout_ fileno() test work. It is hanging Free BSD 9 and OS X Tiger buildbots, and I don't know why.
1 parent c9a6ab5 commit e44dba3

1 file changed

Lines changed: 48 additions & 45 deletions

File tree

Lib/test/test_builtin.py

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,47 +1493,31 @@ class PtyTests(unittest.TestCase):
14931493
"""Tests that use a pseudo terminal to guarantee stdin and stdout are
14941494
terminals in the test environment"""
14951495

1496-
def fork(self):
1496+
def run_child(self, child, terminal_input):
1497+
r, w = os.pipe() # Pipe test results from child back to parent
14971498
try:
1498-
return pty.fork()
1499+
pid, fd = pty.fork()
14991500
except (OSError, AttributeError) as e:
1500-
self.skipTest("pty.fork() raised {}".format(e))
1501-
1502-
def check_input_tty(self, prompt, terminal_input, stdio_encoding=None):
1503-
if not sys.stdin.isatty() or not sys.stdout.isatty():
1504-
self.skipTest("stdin and stdout must be ttys")
1505-
r, w = os.pipe()
1506-
try:
1507-
pid, fd = self.fork()
1508-
except:
15091501
os.close(r)
15101502
os.close(w)
1503+
self.skipTest("pty.fork() raised {}".format(e))
15111504
raise
15121505
if pid == 0:
15131506
# Child
15141507
try:
15151508
# Make sure we don't get stuck if there's a problem
15161509
signal.alarm(2)
15171510
os.close(r)
1518-
# Check the error handlers are accounted for
1519-
if stdio_encoding:
1520-
sys.stdin = io.TextIOWrapper(sys.stdin.detach(),
1521-
encoding=stdio_encoding,
1522-
errors='surrogateescape')
1523-
sys.stdout = io.TextIOWrapper(sys.stdout.detach(),
1524-
encoding=stdio_encoding,
1525-
errors='replace')
15261511
with open(w, "w") as wpipe:
1527-
print("tty =", sys.stdin.isatty() and sys.stdout.isatty(), file=wpipe)
1528-
print(ascii(input(prompt)), file=wpipe)
1512+
child(wpipe)
15291513
except:
15301514
traceback.print_exc()
15311515
finally:
15321516
# We don't want to return to unittest...
15331517
os._exit(0)
15341518
# Parent
15351519
os.close(w)
1536-
os.write(fd, terminal_input + b"\r\n")
1520+
os.write(fd, terminal_input)
15371521
# Get results from the pipe
15381522
with open(r, "r") as rpipe:
15391523
lines = []
@@ -1546,10 +1530,38 @@ def check_input_tty(self, prompt, terminal_input, stdio_encoding=None):
15461530
# Check the result was got and corresponds to the user's terminal input
15471531
if len(lines) != 2:
15481532
# Something went wrong, try to get at stderr
1549-
with open(fd, "r", encoding="ascii", errors="ignore") as child_output:
1550-
self.fail("got %d lines in pipe but expected 2, child output was:\n%s"
1551-
% (len(lines), child_output.read()))
1533+
# Beware of Linux raising EIO when the slave is closed
1534+
child_output = bytearray()
1535+
while True:
1536+
try:
1537+
chunk = os.read(fd, 3000)
1538+
except OSError: # Assume EIO
1539+
break
1540+
if not chunk:
1541+
break
1542+
child_output.extend(chunk)
1543+
os.close(fd)
1544+
child_output = child_output.decode("ascii", "ignore")
1545+
self.fail("got %d lines in pipe but expected 2, child output was:\n%s"
1546+
% (len(lines), child_output))
15521547
os.close(fd)
1548+
return lines
1549+
1550+
def check_input_tty(self, prompt, terminal_input, stdio_encoding=None):
1551+
if not sys.stdin.isatty() or not sys.stdout.isatty():
1552+
self.skipTest("stdin and stdout must be ttys")
1553+
def child(wpipe):
1554+
# Check the error handlers are accounted for
1555+
if stdio_encoding:
1556+
sys.stdin = io.TextIOWrapper(sys.stdin.detach(),
1557+
encoding=stdio_encoding,
1558+
errors='surrogateescape')
1559+
sys.stdout = io.TextIOWrapper(sys.stdout.detach(),
1560+
encoding=stdio_encoding,
1561+
errors='replace')
1562+
print("tty =", sys.stdin.isatty() and sys.stdout.isatty(), file=wpipe)
1563+
print(ascii(input(prompt)), file=wpipe)
1564+
lines = self.run_child(child, terminal_input + b"\r\n")
15531565
# Check we did exercise the GNU readline path
15541566
self.assertIn(lines[0], {'tty = True', 'tty = False'})
15551567
if lines[0] != 'tty = True':
@@ -1577,26 +1589,17 @@ def test_input_tty_non_ascii_unicode_errors(self):
15771589
def test_input_no_stdout_fileno(self):
15781590
# Issue #24402: If stdin is the original terminal but stdout.fileno()
15791591
# fails, do not use the original stdout file descriptor
1580-
pid, pty = self.fork()
1581-
if pid: # Parent process
1582-
# Ideally this should read and write concurrently using select()
1583-
# or similar, to avoid the possibility of a deadlock.
1584-
os.write(pty, b"quux\r")
1585-
_, status = os.waitpid(pid, 0)
1586-
output = os.read(pty, 3000).decode("ascii", "backslashreplace")
1587-
os.close(pty)
1588-
self.assertEqual(status, 0, output)
1589-
else: # Child process
1590-
try:
1591-
self.assertTrue(sys.stdin.isatty(), "stdin not a terminal")
1592-
sys.stdout = io.StringIO() # Does not support fileno()
1593-
input("prompt")
1594-
self.assertEqual(sys.stdout.getvalue(), "prompt")
1595-
os._exit(0) # Success!
1596-
except:
1597-
sys.excepthook(*sys.exc_info())
1598-
finally:
1599-
os._exit(1) # Failure
1592+
def child(wpipe):
1593+
print("stdin.isatty():", sys.stdin.isatty(), file=wpipe)
1594+
sys.stdout = io.StringIO() # Does not support fileno()
1595+
input("prompt")
1596+
print("captured:", ascii(sys.stdout.getvalue()), file=wpipe)
1597+
lines = self.run_child(child, b"quux\r")
1598+
expected = (
1599+
"stdin.isatty(): True",
1600+
"captured: 'prompt'",
1601+
)
1602+
self.assertSequenceEqual(lines, expected)
16001603

16011604
class TestSorted(unittest.TestCase):
16021605

0 commit comments

Comments
 (0)