diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index 1126404fee7..0a915d0199d 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -195,6 +195,7 @@ def test_openpty(self): s2 = _readline(master_fd) self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2)) + @unittest.expectedFailure # TODO: RUSTPYTHON; pty.fork() child is not made a session leader def test_fork(self): debug("calling pty.fork()") pid, master_fd = pty.fork() @@ -296,6 +297,7 @@ def test_master_read(self): self.assertEqual(data, b"") + @unittest.expectedFailure # TODO: RUSTPYTHON; pty.fork() child is not made a session leader def test_spawn_doesnt_hang(self): # gh-140482: Do the test in a pty.fork() child to avoid messing # with the interactive test runner's terminal settings. diff --git a/Lib/test/test_termios.py b/Lib/test/test_termios.py index 216609719ac..1207855fa2d 100644 --- a/Lib/test/test_termios.py +++ b/Lib/test/test_termios.py @@ -221,7 +221,6 @@ def writer(): 'output was not resumed') self.assertEqual(os.read(rfd, 1024), b'def') - @unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'termios' has no attribute 'tcgetwinsize' def test_tcgetwinsize(self): size = termios.tcgetwinsize(self.fd) self.assertIsInstance(size, tuple) @@ -230,7 +229,6 @@ def test_tcgetwinsize(self): self.assertIsInstance(size[1], int) self.assertEqual(termios.tcgetwinsize(self.stream), size) - @unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'termios' has no attribute 'tcgetwinsize' def test_tcgetwinsize_errors(self): self.assertRaisesTermiosError(errno.ENOTTY, termios.tcgetwinsize, self.bad_fd) self.assertRaises(ValueError, termios.tcgetwinsize, -1) @@ -238,14 +236,12 @@ def test_tcgetwinsize_errors(self): self.assertRaises(TypeError, termios.tcgetwinsize, object()) self.assertRaises(TypeError, termios.tcgetwinsize) - @unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'termios' has no attribute 'tcgetwinsize' def test_tcsetwinsize(self): size = termios.tcgetwinsize(self.fd) termios.tcsetwinsize(self.fd, size) termios.tcsetwinsize(self.fd, list(size)) termios.tcsetwinsize(self.stream, size) - @unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'termios' has no attribute 'tcgetwinsize' def test_tcsetwinsize_errors(self): size = termios.tcgetwinsize(self.fd) self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, size[:-1]) diff --git a/crates/host_env/src/termios.rs b/crates/host_env/src/termios.rs index 0a96078be94..612f68be924 100644 --- a/crates/host_env/src/termios.rs +++ b/crates/host_env/src/termios.rs @@ -165,3 +165,27 @@ pub fn tcflush(fd: i32, queue: i32) -> std::io::Result<()> { pub fn tcflow(fd: i32, action: i32) -> std::io::Result<()> { ::termios::tcflow(fd, action) } + +pub fn tcgetwinsize(fd: i32) -> std::io::Result<(u16, u16)> { + let mut size: libc::winsize = unsafe { core::mem::zeroed() }; + let ret = unsafe { libc::ioctl(fd, TIOCGWINSZ as _, &mut size) }; + if ret < 0 { + return Err(std::io::Error::last_os_error()); + } + Ok((size.ws_row, size.ws_col)) +} + +pub fn tcsetwinsize(fd: i32, row: u16, col: u16) -> std::io::Result<()> { + let mut size: libc::winsize = unsafe { core::mem::zeroed() }; + let ret = unsafe { libc::ioctl(fd, TIOCGWINSZ as _, &mut size) }; + if ret < 0 { + return Err(std::io::Error::last_os_error()); + } + size.ws_row = row; + size.ws_col = col; + let ret = unsafe { libc::ioctl(fd, TIOCSWINSZ as _, &size) }; + if ret < 0 { + return Err(std::io::Error::last_os_error()); + } + Ok(()) +} diff --git a/crates/stdlib/src/termios.rs b/crates/stdlib/src/termios.rs index 2207276f81e..6fde771a987 100644 --- a/crates/stdlib/src/termios.rs +++ b/crates/stdlib/src/termios.rs @@ -268,6 +268,30 @@ mod termios { Ok(()) } + #[pyfunction] + fn tcgetwinsize(fd: PyObjectRef, vm: &VirtualMachine) -> PyResult<(u16, u16)> { + let fd = Fildes::try_from_object(vm, fd).map(Into::into)?; + let size = host_termios::tcgetwinsize(fd).map_err(|e| termios_error(e, vm))?; + Ok(size) + } + + #[pyfunction] + fn tcsetwinsize(fd: PyObjectRef, size: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + let fd = Fildes::try_from_object(vm, fd).map(Into::into)?; + let seq = size.try_sequence(vm)?; + if seq.length(vm)? != 2 { + return Err(vm.new_type_error("tcsetwinsize: size must be a 2 element sequence")); + } + let row = seq.get_item(0, vm)?; + let col = seq.get_item(1, vm)?; + + let row: u16 = row.try_index(vm)?.try_to_primitive(vm)?; + let col: u16 = col.try_index(vm)?.try_to_primitive(vm)?; + + host_termios::tcsetwinsize(fd, row, col).map_err(|e| termios_error(e, vm))?; + Ok(()) + } + fn termios_error(err: std::io::Error, vm: &VirtualMachine) -> PyBaseExceptionRef { vm.new_os_subtype_error( error_type(vm),