Skip to content

Commit 8bcef35

Browse files
committed
Add login_tty and fix termios/syslog/mmap
termios.error is Exception, not OSError. os.login_tty prepares a tty for a new session. syslog.openlog encodes ident as UTF-8. mmap.seek returns the new position. Assisted-by: Grok:grok-4.6
1 parent d5523b8 commit 8bcef35

9 files changed

Lines changed: 52 additions & 28 deletions

File tree

‎Lib/test/test_mmap.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ def tearDown(self):
4646
except OSError:
4747
pass
4848

49-
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: 'mmap' object has no attribute 'seekable'
5049
def test_basic(self):
5150
# Test mmap module on Unix systems and Windows
5251

‎Lib/test/test_pty.py‎

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ def write_all(fd, data):
8989

9090
# Marginal testing of pty suite. Cannot do extensive 'do or fail' testing
9191
# because pty code is not too portable.
92-
@unittest.skipIf(getattr(tty, "tcgetwinsize", None) is None, "TODO: RUSTPYTHON; `tty.tcgetwinsize` is required for setUp")
9392
class PtyTest(unittest.TestCase):
9493
def setUp(self):
9594
old_sighup = signal.signal(signal.SIGHUP, self.handle_sighup)
@@ -195,11 +194,6 @@ def test_openpty(self):
195194
s2 = _readline(master_fd)
196195
self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2))
197196

198-
# skip (not expectedFailure) because the test still forks a real child
199-
# process, which crashes on missing os.login_tty() inside the parallel
200-
# test runner's worker process, corrupting its JSON reporting channel
201-
# ("worker bug", reproducible under --slow-ci -j N; not under plain -m test).
202-
@unittest.skip("TODO: RUSTPYTHON; pty.fork() calls os.login_tty(), which is not implemented")
203197
def test_fork(self):
204198
debug("calling pty.fork()")
205199
pid, master_fd = pty.fork()
@@ -301,11 +295,6 @@ def test_master_read(self):
301295

302296
self.assertEqual(data, b"")
303297

304-
# skip (not expectedFailure) because the test still forks a real child
305-
# process, which crashes on missing os.login_tty() inside the parallel
306-
# test runner's worker process, corrupting its JSON reporting channel
307-
# ("worker bug", reproducible under --slow-ci -j N; not under plain -m test).
308-
@unittest.skip("TODO: RUSTPYTHON; pty.fork() calls os.login_tty(), which is not implemented")
309298
def test_spawn_doesnt_hang(self):
310299
# gh-140482: Do the test in a pty.fork() child to avoid messing
311300
# with the interactive test runner's terminal settings.

‎Lib/test/test_syslog.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class Test(unittest.TestCase):
1616
def tearDown(self):
1717
syslog.closelog()
1818

19-
@unittest.expectedFailure # TODO: RUSTPYTHON
2019
def test_openlog(self):
2120
syslog.openlog('python')
2221
# Issue #6697.

‎Lib/test/test_termios.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,6 @@ def test_ioctl_constants(self):
289289
with self.subTest(name=name):
290290
self.assertGreaterEqual(value, 0)
291291

292-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: <class 'termios.error'> is a subclass of <class 'OSError'>
293292
def test_exception(self):
294293
self.assertIsSubclass(termios.error, Exception)
295294
self.assertNotIsSubclass(termios.error, OSError)

‎crates/host_env/src/posix.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,16 @@ pub fn setresuid(ruid: u32, euid: u32, suid: u32) -> std::io::Result<()> {
10131013
.map_err(std::io::Error::from)
10141014
}
10151015

1016+
#[cfg(not(target_os = "wasi"))]
1017+
pub fn login_tty(fd: i32) -> std::io::Result<()> {
1018+
let ret = unsafe { libc::login_tty(fd) };
1019+
if ret < 0 {
1020+
Err(std::io::Error::last_os_error())
1021+
} else {
1022+
Ok(())
1023+
}
1024+
}
1025+
10161026
#[cfg(not(target_os = "redox"))]
10171027
pub fn openpty() -> std::io::Result<(OwnedFd, OwnedFd)> {
10181028
let pty = nix::pty::openpty(None, None).map_err(std::io::Error::from)?;

‎crates/stdlib/src/mmap.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,7 @@ mod mmap {
10951095
dist: isize,
10961096
whence: OptionalArg<core::ffi::c_int>,
10971097
vm: &VirtualMachine,
1098-
) -> PyResult<()> {
1098+
) -> PyResult<usize> {
10991099
let how = whence.unwrap_or(0);
11001100
let size = self.__len__();
11011101

@@ -1125,7 +1125,7 @@ mod mmap {
11251125

11261126
self.pos.store(new_pos as usize);
11271127

1128-
Ok(())
1128+
Ok(new_pos as usize)
11291129
}
11301130

11311131
#[cfg(unix)]

‎crates/stdlib/src/syslog.rs‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod syslog {
77
use crate::vm::{
88
PyObjectRef, PyPayload, PyResult, VirtualMachine,
99
builtins::{PyStr, PyStrRef},
10+
convert::ToPyException,
1011
function::{OptionalArg, OptionalOption},
1112
utils::ToCString,
1213
};
@@ -28,6 +29,27 @@ mod syslog {
2829
#[pyattr]
2930
use host_syslog::{LOG_FTP, LOG_INSTALL, LOG_LAUNCHD, LOG_NETINFO, LOG_RAS, LOG_REMOTEAUTH};
3031

32+
fn ident_to_utf8_cstring(
33+
ident: &PyStrRef,
34+
vm: &VirtualMachine,
35+
) -> PyResult<alloc::ffi::CString> {
36+
let utf8 = ident.to_str().ok_or_else(|| {
37+
let start = ident
38+
.as_wtf8()
39+
.code_points()
40+
.position(|c| c.to_char().is_none())
41+
.unwrap_or(0);
42+
vm.new_unicode_encode_error_real(
43+
vm.ctx.new_str("utf-8"),
44+
ident.clone(),
45+
start,
46+
start + 1,
47+
vm.ctx.new_str("surrogates not allowed"),
48+
)
49+
})?;
50+
alloc::ffi::CString::new(utf8).map_err(|err| err.to_pyexception(vm))
51+
}
52+
3153
fn get_argv(vm: &VirtualMachine) -> Option<PyStrRef> {
3254
if let Some(argv) = vm.state.config.settings.argv.first()
3355
&& !argv.is_empty()
@@ -58,8 +80,10 @@ mod syslog {
5880
let logoption = args.logoption.unwrap_or(0);
5981
let facility = args.facility.unwrap_or(LOG_USER);
6082
let ident = match args.ident.clone().flatten() {
61-
Some(args) => Some(args.to_cstring(vm)?),
62-
None => get_argv(vm).map(|argv| argv.to_cstring(vm)).transpose()?,
83+
Some(ident) => Some(ident_to_utf8_cstring(&ident, vm)?),
84+
None => get_argv(vm)
85+
.map(|argv| ident_to_utf8_cstring(&argv, vm))
86+
.transpose()?,
6387
}
6488
.map(|ident| ident.into_boxed_c_str());
6589

‎crates/stdlib/src/termios.rs‎

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -297,20 +297,17 @@ mod termios {
297297
}
298298

299299
fn termios_error(err: std::io::Error, vm: &VirtualMachine) -> PyBaseExceptionRef {
300-
vm.new_os_subtype_error(
300+
vm.new_exception(
301301
error_type(vm),
302-
Some(err.posix_errno()),
303-
vm.ctx.new_str(err.to_string()),
302+
vec![
303+
vm.ctx.new_int(err.posix_errno()).into(),
304+
vm.ctx.new_str(err.to_string()).into(),
305+
],
304306
)
305-
.upcast()
306307
}
307308

308309
#[pyattr(name = "error", once)]
309310
fn error_type(vm: &VirtualMachine) -> PyTypeRef {
310-
vm.ctx.new_exception_type(
311-
"termios",
312-
"error",
313-
Some(vec![vm.ctx.exceptions.os_error.to_owned()]),
314-
)
311+
vm.ctx.new_exception_type("termios", "error", None)
315312
}
316313
}

‎crates/vm/src/stdlib/posix.rs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub mod module {
3939
use rustpython_host_env::os::ffi::OsStringExt;
4040
use std::{
4141
fs, io,
42-
os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
42+
os::fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
4343
};
4444
use strum::IntoEnumIterator;
4545
use strum_macros::{EnumIter, EnumString};
@@ -1304,6 +1304,13 @@ pub mod module {
13041304
.map_err(|err| err.into_pyexception(vm))
13051305
}
13061306

1307+
#[cfg(not(target_os = "wasi"))]
1308+
#[pyfunction]
1309+
fn login_tty(fd: BorrowedFd<'_>, vm: &VirtualMachine) -> PyResult<()> {
1310+
rustpython_host_env::posix::login_tty(fd.as_raw_fd())
1311+
.map_err(|err| err.into_pyexception(vm))
1312+
}
1313+
13071314
#[cfg(not(target_os = "redox"))]
13081315
#[pyfunction]
13091316
fn openpty(vm: &VirtualMachine) -> PyResult<(OwnedFd, OwnedFd)> {

0 commit comments

Comments
 (0)