Skip to content

Commit e351ca3

Browse files
8vasugpsheadencukou
authored
gh-85984: Add POSIX pseudo-terminal functions. (GH-102413)
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>
1 parent 0f54ee4 commit e351ca3

File tree

9 files changed

+468
-11
lines changed

9 files changed

+468
-11
lines changed

Doc/conf.py

+5
Original file line numberDiff line numberDiff line change
@@ -97,19 +97,24 @@
9797
('c:func', 'free'),
9898
('c:func', 'gettimeofday'),
9999
('c:func', 'gmtime'),
100+
('c:func', 'grantpt'),
100101
('c:func', 'localeconv'),
101102
('c:func', 'localtime'),
102103
('c:func', 'main'),
103104
('c:func', 'malloc'),
104105
('c:func', 'mktime'),
106+
('c:func', 'posix_openpt'),
105107
('c:func', 'printf'),
108+
('c:func', 'ptsname'),
109+
('c:func', 'ptsname_r'),
106110
('c:func', 'realloc'),
107111
('c:func', 'snprintf'),
108112
('c:func', 'sprintf'),
109113
('c:func', 'stat'),
110114
('c:func', 'strftime'),
111115
('c:func', 'system'),
112116
('c:func', 'time'),
117+
('c:func', 'unlockpt'),
113118
('c:func', 'vsnprintf'),
114119
# Standard C types
115120
('c:type', 'FILE'),

Doc/library/os.rst

+59
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,20 @@ as internal buffering of data.
11221122
.. versionchanged:: 3.12
11231123
Added support for pipes on Windows.
11241124

1125+
1126+
.. function:: grantpt(fd, /)
1127+
1128+
Grant access to the slave pseudo-terminal device associated with the
1129+
master pseudo-terminal device to which the file descriptor *fd* refers.
1130+
The file descriptor *fd* is not closed upon failure.
1131+
1132+
Calls the C standard library function :c:func:`grantpt`.
1133+
1134+
.. availability:: Unix, not Emscripten, not WASI.
1135+
1136+
.. versionadded:: 3.13
1137+
1138+
11251139
.. function:: isatty(fd, /)
11261140

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

14311445

1446+
.. function:: posix_openpt(oflag, /)
1447+
1448+
Open and return a file descriptor for a master pseudo-terminal device.
1449+
1450+
Calls the C standard library function :c:func:`posix_openpt`. The *oflag*
1451+
argument is used to set file status flags and file access modes as
1452+
specified in the manual page of :c:func:`posix_openpt` of your system.
1453+
1454+
The returned file descriptor is :ref:`non-inheritable <fd_inheritance>`.
1455+
If the value :data:`O_CLOEXEC` is available on the system, it is added to
1456+
*oflag*.
1457+
1458+
.. availability:: Unix, not Emscripten, not WASI.
1459+
1460+
.. versionadded:: 3.13
1461+
1462+
14321463
.. function:: preadv(fd, buffers, offset, flags=0, /)
14331464

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

14881519

1520+
.. function:: ptsname(fd, /)
1521+
1522+
Return the name of the slave pseudo-terminal device associated with the
1523+
master pseudo-terminal device to which the file descriptor *fd* refers.
1524+
The file descriptor *fd* is not closed upon failure.
1525+
1526+
Calls the reentrant C standard library function :c:func:`ptsname_r` if
1527+
it is available; otherwise, the C standard library function
1528+
:c:func:`ptsname`, which is not guaranteed to be thread-safe, is called.
1529+
1530+
.. availability:: Unix, not Emscripten, not WASI.
1531+
1532+
.. versionadded:: 3.13
1533+
1534+
14891535
.. function:: pwrite(fd, str, offset, /)
14901536

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

17401786

1787+
.. function:: unlockpt(fd, /)
1788+
1789+
Unlock the slave pseudo-terminal device associated with the master
1790+
pseudo-terminal device to which the file descriptor *fd* refers.
1791+
The file descriptor *fd* is not closed upon failure.
1792+
1793+
Calls the C standard library function :c:func:`unlockpt`.
1794+
1795+
.. availability:: Unix, not Emscripten, not WASI.
1796+
1797+
.. versionadded:: 3.13
1798+
1799+
17411800
.. function:: write(fd, str, /)
17421801

17431802
Write the bytestring in *str* to file descriptor *fd*.

Lib/test/test_os.py

+39-6
Original file line numberDiff line numberDiff line change
@@ -4536,13 +4536,46 @@ def test_dup2(self):
45364536
self.assertEqual(os.dup2(fd, fd3, inheritable=False), fd3)
45374537
self.assertFalse(os.get_inheritable(fd3))
45384538

4539-
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
4539+
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
4540+
class PseudoterminalTests(unittest.TestCase):
4541+
def open_pty(self):
4542+
"""Open a pty fd-pair, and schedule cleanup for it"""
4543+
main_fd, second_fd = os.openpty()
4544+
self.addCleanup(os.close, main_fd)
4545+
self.addCleanup(os.close, second_fd)
4546+
return main_fd, second_fd
4547+
45404548
def test_openpty(self):
4541-
master_fd, slave_fd = os.openpty()
4542-
self.addCleanup(os.close, master_fd)
4543-
self.addCleanup(os.close, slave_fd)
4544-
self.assertEqual(os.get_inheritable(master_fd), False)
4545-
self.assertEqual(os.get_inheritable(slave_fd), False)
4549+
main_fd, second_fd = self.open_pty()
4550+
self.assertEqual(os.get_inheritable(main_fd), False)
4551+
self.assertEqual(os.get_inheritable(second_fd), False)
4552+
4553+
@unittest.skipUnless(hasattr(os, 'ptsname'), "need os.ptsname()")
4554+
@unittest.skipUnless(hasattr(os, 'O_RDWR'), "need os.O_RDWR")
4555+
@unittest.skipUnless(hasattr(os, 'O_NOCTTY'), "need os.O_NOCTTY")
4556+
def test_open_via_ptsname(self):
4557+
main_fd, second_fd = self.open_pty()
4558+
second_path = os.ptsname(main_fd)
4559+
reopened_second_fd = os.open(second_path, os.O_RDWR|os.O_NOCTTY)
4560+
self.addCleanup(os.close, reopened_second_fd)
4561+
os.write(reopened_second_fd, b'foo')
4562+
self.assertEqual(os.read(main_fd, 3), b'foo')
4563+
4564+
@unittest.skipUnless(hasattr(os, 'posix_openpt'), "need os.posix_openpt()")
4565+
@unittest.skipUnless(hasattr(os, 'grantpt'), "need os.grantpt()")
4566+
@unittest.skipUnless(hasattr(os, 'unlockpt'), "need os.unlockpt()")
4567+
@unittest.skipUnless(hasattr(os, 'ptsname'), "need os.ptsname()")
4568+
@unittest.skipUnless(hasattr(os, 'O_RDWR'), "need os.O_RDWR")
4569+
@unittest.skipUnless(hasattr(os, 'O_NOCTTY'), "need os.O_NOCTTY")
4570+
def test_posix_pty_functions(self):
4571+
mother_fd = os.posix_openpt(os.O_RDWR|os.O_NOCTTY)
4572+
self.addCleanup(os.close, mother_fd)
4573+
os.grantpt(mother_fd)
4574+
os.unlockpt(mother_fd)
4575+
son_path = os.ptsname(mother_fd)
4576+
son_fd = os.open(son_path, os.O_RDWR|os.O_NOCTTY)
4577+
self.addCleanup(os.close, son_fd)
4578+
self.assertEqual(os.ptsname(mother_fd), os.ttyname(son_fd))
45464579

45474580
@unittest.skipUnless(hasattr(os, 'spawnl'), "need os.openpty()")
45484581
def test_pipe_spawnl(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add POSIX pseudo-terminal functions :func:`os.posix_openpt`,
2+
:func:`os.grantpt`, :func:`os.unlockpt`, and :func:`os.ptsname`.

Modules/clinic/posixmodule.c.h

+167-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)