mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
fix input to check pty child (#6553)
* fix input to check pty child * Auto-format: cargo fmt --all --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
9b2ad34a08
commit
ce00640b22
2 files changed
+30
-7
No files matched your search
@@ -70,11 +70,14 @@ pub fn file_readline(obj: &PyObject, size: Option<usize>, vm: &VirtualMachine) -
|
||||
};
|
||||
let ret = match_class!(match ret {
|
||||
s @ PyStr => {
|
||||
let s_val = s.as_str();
|
||||
if s_val.is_empty() {
|
||||
// Use as_wtf8() to handle strings with surrogates (e.g., surrogateescape)
|
||||
let s_wtf8 = s.as_wtf8();
|
||||
if s_wtf8.is_empty() {
|
||||
return Err(eof_err());
|
||||
}
|
||||
if let Some(no_nl) = s_val.strip_suffix('\n') {
|
||||
// '\n' is ASCII, so we can check bytes directly
|
||||
if s_wtf8.as_bytes().last() == Some(&b'\n') {
|
||||
let no_nl = &s_wtf8[..s_wtf8.len() - 1];
|
||||
vm.ctx.new_str(no_nl).into()
|
||||
} else {
|
||||
s.into()
|
||||
|
||||
@@ -7,8 +7,6 @@ pub use builtins::{ascii, print, reversed};
|
||||
|
||||
#[pymodule]
|
||||
mod builtins {
|
||||
use std::io::IsTerminal;
|
||||
|
||||
use crate::{
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
|
||||
builtins::{
|
||||
@@ -464,6 +462,8 @@ mod builtins {
|
||||
|
||||
#[pyfunction]
|
||||
fn input(prompt: OptionalArg<PyStrRef>, vm: &VirtualMachine) -> PyResult {
|
||||
use std::io::IsTerminal;
|
||||
|
||||
let stdin = sys::get_stdin(vm)?;
|
||||
let stdout = sys::get_stdout(vm)?;
|
||||
let stderr = sys::get_stderr(vm)?;
|
||||
@@ -476,8 +476,13 @@ mod builtins {
|
||||
.is_ok_and(|fd| fd == expected)
|
||||
};
|
||||
|
||||
// everything is normal, we can just rely on rustyline to use stdin/stdout
|
||||
if fd_matches(&stdin, 0) && fd_matches(&stdout, 1) && std::io::stdin().is_terminal() {
|
||||
// Check if we should use rustyline (interactive terminal, not PTY child)
|
||||
let use_rustyline = fd_matches(&stdin, 0)
|
||||
&& fd_matches(&stdout, 1)
|
||||
&& std::io::stdin().is_terminal()
|
||||
&& !is_pty_child();
|
||||
|
||||
if use_rustyline {
|
||||
let prompt = prompt.as_ref().map_or("", |s| s.as_str());
|
||||
let mut readline = Readline::new(());
|
||||
match readline.readline(prompt) {
|
||||
@@ -502,6 +507,21 @@ mod builtins {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if we're running in a PTY child process (e.g., after pty.fork()).
|
||||
/// pty.fork() calls setsid(), making the child a session leader.
|
||||
/// In this case, rustyline may hang because it uses raw mode.
|
||||
#[cfg(unix)]
|
||||
fn is_pty_child() -> bool {
|
||||
use nix::unistd::{getpid, getsid};
|
||||
// If this process is a session leader, we're likely in a PTY child
|
||||
getsid(None) == Ok(getpid())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn is_pty_child() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn isinstance(obj: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
obj.is_instance(&typ, vm)
|
||||
|
||||
Reference in new issue
Block a user