gh-119273: Don't run test_ioctl in a process group
Python test runner no longer runs tests using TTY (ex: test_ioctl) in a process group (using setsid()). Previously, tests using TTY were skipped.
- Issue: gh-119273
Without this change, the test is skipped:
$ ./python -m test test_ioctl -j1
(...)
test_ioctl skipped -- Unable to open /dev/tty
With the change, the test is no longer skipped:
$ ./python -m test test_ioctl -j1
(...)
Result: SUCCESS
Test on fork+setsid:
import io
import os
def check_tty(context):
try:
f = io.FileIO("/dev/tty", "a")
tty = f.isatty()
f.close()
except OSError as exc:
print(f"{context}: Is a TTY? {exc}")
else:
print(f"{context}: Is a TTY? {tty}")
check_tty("parent")
pid = os.fork()
if pid:
os.waitpid(pid, 0)
else:
os.setsid()
check_tty("child after fork+setsid")
Result on Linux:
parent: Is a TTY? True
child after fork+setsid: Is a TTY? [Errno 6] No such device or address: '/dev/tty'
The child process cannot open /dev/tty after fork+setsid.
The following tests contains the word tty (outside comments). I checked if they are skipped when run in a worker process.
Skipped tests:
test_builtin: always skipped.test_input_tty*()tests need a TTY and requires that readline is not loaded.test_fileio: always skipped silently.testAbles()test_ioctl: always skipped (whole file).test_shutil: always skipped.test_shutil.test_stty_match()requiressys.__stdout__to be a TTY to run the commandstty size. When using worker process, stdout is a pipe and not a TTY.
Tests not skipped (ok):
test_cursestest_filetest_getpass: accessing/dev/ttyuses a mocktest_os: stdin is a TTY.test_ptytest_readlinetest_sundrytest_threadingtest_tty: useos.openpty()test_utf8_mode
Using os.openpty() is fine with fork+setsid:
import io
import os
def check_tty(context):
try:
parent_fd, child_fd = os.openpty()
tty = os.isatty(parent_fd)
os.close(parent_fd)
os.close(child_fd)
except OSError as exc:
print(f"{context}: Is a TTY? {exc}")
else:
print(f"{context}: Is a TTY? {tty}")
check_tty("parent")
pid = os.fork()
if pid:
os.waitpid(pid, 0)
else:
os.setsid()
check_tty("child after fork+setsid")
Output:
parent: Is a TTY? True
child after fork+setsid: Is a TTY? True
I merged this PR as it is. I will prepare a following PR to handle test_builtin, test_fileio and test_shutil.
test_builtin: always skipped. test_input_tty*() tests need a TTY and requires that readline is not loaded. test_shutil: always skipped. test_shutil.test_stty_match() requires sys.stdout to be a TTY to run the command stty size. When using worker process, stdout is a pipe and not a TTY.
Sadly, these two tests need stdout to be a TTY. It's only doable if tests are run sequentially.
test_fileio: always skipped silently. testAbles()
Well, it's just a subset of a minor test. I don't think that it's worth it to create a whole test file just for a few lines.
Follow-up: I created issue gh-119727: Add --sequentially option to regrtest to always run tests sequentially (ignore -jN option).