(prompt: OptionalArg<PyStrRef>, vm: &VirtualMachine)
| 684 | |
| 685 | #[pyfunction] |
| 686 | fn input(prompt: OptionalArg<PyStrRef>, vm: &VirtualMachine) -> PyResult { |
| 687 | use std::io::IsTerminal; |
| 688 | |
| 689 | let stdin = sys::get_stdin(vm)?; |
| 690 | let stdout = sys::get_stdout(vm)?; |
| 691 | let stderr = sys::get_stderr(vm)?; |
| 692 | |
| 693 | let _ = vm.call_method(&stderr, "flush", ()); |
| 694 | |
| 695 | let fd_matches = |obj, expected| { |
| 696 | vm.call_method(obj, "fileno", ()) |
| 697 | .and_then(|o| i64::try_from_object(vm, o)) |
| 698 | .is_ok_and(|fd| fd == expected) |
| 699 | }; |
| 700 | |
| 701 | // Check if we should use rustyline (interactive terminal, not PTY child) |
| 702 | let use_rustyline = fd_matches(&stdin, 0) |
| 703 | && fd_matches(&stdout, 1) |
| 704 | && std::io::stdin().is_terminal() |
| 705 | && !is_pty_child(); |
| 706 | |
| 707 | // Disable rustyline if prompt contains surrogates (not valid UTF-8 for terminal) |
| 708 | let prompt_str = match &prompt { |
| 709 | OptionalArg::Present(s) => s.to_str(), |
| 710 | OptionalArg::Missing => Some(""), |
| 711 | }; |
| 712 | let use_rustyline = use_rustyline && prompt_str.is_some(); |
| 713 | |
| 714 | if use_rustyline { |
| 715 | let prompt = prompt_str.unwrap(); |
| 716 | let mut readline = Readline::new(()); |
| 717 | match readline.readline(prompt) { |
| 718 | ReadlineResult::Line(s) => Ok(vm.ctx.new_str(s).into()), |
| 719 | ReadlineResult::Eof => { |
| 720 | Err(vm.new_exception_empty(vm.ctx.exceptions.eof_error.to_owned())) |
| 721 | } |
| 722 | ReadlineResult::Interrupt => { |
| 723 | Err(vm.new_exception_empty(vm.ctx.exceptions.keyboard_interrupt.to_owned())) |
| 724 | } |
| 725 | ReadlineResult::Io(e) => Err(vm.new_os_error(e.to_string())), |
| 726 | #[cfg(unix)] |
| 727 | ReadlineResult::OsError(num) => Err(vm.new_os_error(num.to_string())), |
| 728 | ReadlineResult::Other(e) => Err(vm.new_runtime_error(e.to_string())), |
| 729 | } |
| 730 | } else { |
| 731 | if let OptionalArg::Present(prompt) = prompt { |
| 732 | vm.call_method(&stdout, "write", (prompt,))?; |
| 733 | } |
| 734 | let _ = vm.call_method(&stdout, "flush", ()); |
| 735 | py_io::file_readline(&stdin, None, vm) |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | /// Check if we're running in a PTY child process (e.g., after pty.fork()). |
| 740 | /// pty.fork() calls setsid(), making the child a session leader. |
nothing calls this directly
no test coverage detected