Skip to content

Commit

Permalink
gh-85984: Add POSIX pseudo-terminal functions. (GH-102413)
Browse files Browse the repository at this point in the history
Signed-off-by: Soumendra Ganguly <soumendraganguly@gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
  • Loading branch information
3 people authored Jan 29, 2024
1 parent 0f54ee4 commit e351ca3
Show file tree
Hide file tree
Showing 9 changed files with 468 additions and 11 deletions.
5 changes: 5 additions & 0 deletions Doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,24 @@
('c:func', 'free'),
('c:func', 'gettimeofday'),
('c:func', 'gmtime'),
('c:func', 'grantpt'),
('c:func', 'localeconv'),
('c:func', 'localtime'),
('c:func', 'main'),
('c:func', 'malloc'),
('c:func', 'mktime'),
('c:func', 'posix_openpt'),
('c:func', 'printf'),
('c:func', 'ptsname'),
('c:func', 'ptsname_r'),
('c:func', 'realloc'),
('c:func', 'snprintf'),
('c:func', 'sprintf'),
('c:func', 'stat'),
('c:func', 'strftime'),
('c:func', 'system'),
('c:func', 'time'),
('c:func', 'unlockpt'),
('c:func', 'vsnprintf'),
# Standard C types
('c:type', 'FILE'),
Expand Down
59 changes: 59 additions & 0 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,20 @@ as internal buffering of data.
.. versionchanged:: 3.12
Added support for pipes on Windows.


.. function:: grantpt(fd, /)

Grant access to the slave pseudo-terminal device associated with the
master pseudo-terminal device to which the file descriptor *fd* refers.
The file descriptor *fd* is not closed upon failure.

Calls the C standard library function :c:func:`grantpt`.

.. availability:: Unix, not Emscripten, not WASI.

.. versionadded:: 3.13


.. function:: isatty(fd, /)

Return ``True`` if the file descriptor *fd* is open and connected to a
Expand Down Expand Up @@ -1429,6 +1443,23 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo
.. versionadded:: 3.3


.. function:: posix_openpt(oflag, /)

Open and return a file descriptor for a master pseudo-terminal device.

Calls the C standard library function :c:func:`posix_openpt`. The *oflag*
argument is used to set file status flags and file access modes as
specified in the manual page of :c:func:`posix_openpt` of your system.

The returned file descriptor is :ref:`non-inheritable <fd_inheritance>`.
If the value :data:`O_CLOEXEC` is available on the system, it is added to
*oflag*.

.. availability:: Unix, not Emscripten, not WASI.

.. versionadded:: 3.13


.. function:: preadv(fd, buffers, offset, flags=0, /)

Read from a file descriptor *fd* at a position of *offset* into mutable
Expand Down Expand Up @@ -1486,6 +1517,21 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo
.. versionadded:: 3.7


.. function:: ptsname(fd, /)

Return the name of the slave pseudo-terminal device associated with the
master pseudo-terminal device to which the file descriptor *fd* refers.
The file descriptor *fd* is not closed upon failure.

Calls the reentrant C standard library function :c:func:`ptsname_r` if
it is available; otherwise, the C standard library function
:c:func:`ptsname`, which is not guaranteed to be thread-safe, is called.

.. availability:: Unix, not Emscripten, not WASI.

.. versionadded:: 3.13


.. function:: pwrite(fd, str, offset, /)

Write the bytestring in *str* to file descriptor *fd* at position of
Expand Down Expand Up @@ -1738,6 +1784,19 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo
.. availability:: Unix.


.. function:: unlockpt(fd, /)

Unlock the slave pseudo-terminal device associated with the master
pseudo-terminal device to which the file descriptor *fd* refers.
The file descriptor *fd* is not closed upon failure.

Calls the C standard library function :c:func:`unlockpt`.

.. availability:: Unix, not Emscripten, not WASI.

.. versionadded:: 3.13


.. function:: write(fd, str, /)

Write the bytestring in *str* to file descriptor *fd*.
Expand Down
45 changes: 39 additions & 6 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -4536,13 +4536,46 @@ def test_dup2(self):
self.assertEqual(os.dup2(fd, fd3, inheritable=False), fd3)
self.assertFalse(os.get_inheritable(fd3))

@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
class PseudoterminalTests(unittest.TestCase):
def open_pty(self):
"""Open a pty fd-pair, and schedule cleanup for it"""
main_fd, second_fd = os.openpty()
self.addCleanup(os.close, main_fd)
self.addCleanup(os.close, second_fd)
return main_fd, second_fd

def test_openpty(self):
master_fd, slave_fd = os.openpty()
self.addCleanup(os.close, master_fd)
self.addCleanup(os.close, slave_fd)
self.assertEqual(os.get_inheritable(master_fd), False)
self.assertEqual(os.get_inheritable(slave_fd), False)
main_fd, second_fd = self.open_pty()
self.assertEqual(os.get_inheritable(main_fd), False)
self.assertEqual(os.get_inheritable(second_fd), False)

@unittest.skipUnless(hasattr(os, 'ptsname'), "need os.ptsname()")
@unittest.skipUnless(hasattr(os, 'O_RDWR'), "need os.O_RDWR")
@unittest.skipUnless(hasattr(os, 'O_NOCTTY'), "need os.O_NOCTTY")
def test_open_via_ptsname(self):
main_fd, second_fd = self.open_pty()
second_path = os.ptsname(main_fd)
reopened_second_fd = os.open(second_path, os.O_RDWR|os.O_NOCTTY)
self.addCleanup(os.close, reopened_second_fd)
os.write(reopened_second_fd, b'foo')
self.assertEqual(os.read(main_fd, 3), b'foo')

@unittest.skipUnless(hasattr(os, 'posix_openpt'), "need os.posix_openpt()")
@unittest.skipUnless(hasattr(os, 'grantpt'), "need os.grantpt()")
@unittest.skipUnless(hasattr(os, 'unlockpt'), "need os.unlockpt()")
@unittest.skipUnless(hasattr(os, 'ptsname'), "need os.ptsname()")
@unittest.skipUnless(hasattr(os, 'O_RDWR'), "need os.O_RDWR")
@unittest.skipUnless(hasattr(os, 'O_NOCTTY'), "need os.O_NOCTTY")
def test_posix_pty_functions(self):
mother_fd = os.posix_openpt(os.O_RDWR|os.O_NOCTTY)
self.addCleanup(os.close, mother_fd)
os.grantpt(mother_fd)
os.unlockpt(mother_fd)
son_path = os.ptsname(mother_fd)
son_fd = os.open(son_path, os.O_RDWR|os.O_NOCTTY)
self.addCleanup(os.close, son_fd)
self.assertEqual(os.ptsname(mother_fd), os.ttyname(son_fd))

@unittest.skipUnless(hasattr(os, 'spawnl'), "need os.openpty()")
def test_pipe_spawnl(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add POSIX pseudo-terminal functions :func:`os.posix_openpt`,
:func:`os.grantpt`, :func:`os.unlockpt`, and :func:`os.ptsname`.
168 changes: 167 additions & 1 deletion Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e351ca3

Please sign in to comment.