Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-85984: Add POSIX pseudo-terminal functions. #102413

Merged
merged 14 commits into from
Jan 29, 2024
5 changes: 5 additions & 0 deletions Doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,21 @@
('c:func', 'fork'),
('c:func', 'free'),
('c:func', 'gmtime'),
('c:func', 'grantpt'),
('c:func', 'localtime'),
('c:func', 'main'),
('c:func', 'malloc'),
('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', '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*
gpshead marked this conversation as resolved.
Show resolved Hide resolved
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.
encukou marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -4477,13 +4477,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))


class PathTConverterTests(unittest.TestCase):
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
Loading