Skip to content

Conversation

@vstinner
Copy link
Member

@vstinnervstinner commented May 20, 2024

Python test runner no longer runs tests using TTY (ex: test_ioctl) in a process group (using setsid()). Previously, tests using TTY were skipped.

Python test runner no longer runs tests using TTY (ex: test_ioctl) in a process group (using setsid()). Previously, tests using TTY were skipped.
@vstinner
Copy link
MemberAuthor

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 

Copy link
Member

@gpsheadgpshead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. While I wish there were a better way to avoid maintaining a special case list within libregrtest itself, the implementation of how not to use a process group is the same even if we gain that more direct ability instead of a far removed list in the future.


USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg"))
NEED_TTY = set('''
test_ioctl
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a couple of other tests that skip some of the test methods/classes when stdout is not a tty: test_builtin, test_curses, test_os, test_shutil at least, from a quick grep. I'm not sure it's going to be maintainable to keep a list like this up to date...

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One option would be to move "tty" tests in separated test files and disable setsid() if the test name contains _tty. For example, we already do that with GUI tests (ex: test_ttk and test_ttk_textonly).

@vstinner
Copy link
MemberAuthor

Test on fork+setsid:

importioimportosdefcheck_tty(context): try: f=io.FileIO("/dev/tty", "a") tty=f.isatty() f.close() exceptOSErrorasexc: print(f"{context}: Is a TTY? {exc}") else: print(f"{context}: Is a TTY? {tty}") check_tty("parent") pid=os.fork() ifpid: 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.

@vstinner
Copy link
MemberAuthor

vstinner commented May 23, 2024

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() 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.

Tests not skipped (ok):

  • test_curses
  • test_file
  • test_getpass: accessing /dev/tty uses a mock
  • test_os: stdin is a TTY.
  • test_pty
  • test_readline
  • test_sundry
  • test_threading
  • test_tty: use os.openpty()
  • test_utf8_mode

@vstinner
Copy link
MemberAuthor

Using os.openpty() is fine with fork+setsid:

importioimportosdefcheck_tty(context): try: parent_fd, child_fd=os.openpty() tty=os.isatty(parent_fd) os.close(parent_fd) os.close(child_fd) exceptOSErrorasexc: print(f"{context}: Is a TTY? {exc}") else: print(f"{context}: Is a TTY? {tty}") check_tty("parent") pid=os.fork() ifpid: 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 

@vstinnervstinner marked this pull request as ready for review May 29, 2024 12:43
@vstinnervstinner enabled auto-merge (squash) May 29, 2024 12:44
@vstinnervstinner merged commit 1f481fd into python:mainMay 29, 2024
@vstinnervstinner deleted the regrtest_tty branch May 29, 2024 12:44
@vstinner
Copy link
MemberAuthor

I merged this PR as it is. I will prepare a following PR to handle test_builtin, test_fileio and test_shutil.

@vstinner
Copy link
MemberAuthor

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.

@vstinner
Copy link
MemberAuthor

Follow-up: I created issue gh-119727: Add --sequentially option to regrtest to always run tests sequentially (ignore -jN option).

@vstinnervstinner mentioned this pull request May 30, 2024
noahbkim pushed a commit to hudson-trading/cpython that referenced this pull request Jul 11, 2024
Python test runner no longer runs tests using TTY (ex: test_ioctl) in a process group (using setsid()). Previously, tests using TTY were skipped.
estyxx pushed a commit to estyxx/cpython that referenced this pull request Jul 17, 2024
Python test runner no longer runs tests using TTY (ex: test_ioctl) in a process group (using setsid()). Previously, tests using TTY were skipped.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@vstinner@gpshead@Yhg1s