I'm having problems embedding an IPython console inside a subprocess when using prompt-toolkit.
I am developing an application using a TUI based on pt. For the subprocesses I am using concurrent.futures.ProcessPoolExecutor.
It seems that, for some reason, the subprocesses close sys.stdin and I can't embed an IPython in them. It only works on the parent process. The following snippet is a minimal reproducible example. It creates a dummy pt Application, spawns a subprocess that tries to execute IPython.embed(). I left the call to stdin_from_terminal() since it is needed when not using the TUI.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from prompt_toolkit.layout.dimension import LayoutDimension
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.application import Application
from prompt_toolkit.layout.layout import Layout
from concurrent.futures import ProcessPoolExecutor, wait
import contextlib
import threading
import IPython
import sys
import os
# --------------------------------------- #
TTYNAMES = {"posix": "/dev/tty", "nt": "con"}
@contextlib.contextmanager
def stdin_from_terminal():
try:
ttyname = TTYNAMES[os.name]
except KeyError:
raise OSError(f"{os.name} does not support manually reading from the terminal")
with open(ttyname) as tty:
sys.stdin, oldstdin = tty, sys.stdin
try:
yield
finally:
sys.stdin = oldstdin
# --------------------------------------- #
def worker_fcn():
print(f"Worker process => PID: {os.getpid()}")
with stdin_from_terminal():
IPython.embed()
def init_fcn(args, kwargs):
pass
def main():
app = Application(
layout=Layout(HSplit(
children = [Window(always_hide_cursor=True)],
height=LayoutDimension.exact(0),
)),
mouse_support=False,
full_screen=False,
)
# app.run()
tui_thread = threading.Thread(
target=app.run,
daemon=True,
kwargs={'in_thread': False},
)
tui_thread.start()
print(f"Parent process => PID: {os.getpid()}")
executor = ProcessPoolExecutor(
max_workers=1,
initializer=init_fcn,
initargs=([], {})
)
job = executor.submit(worker_fcn)
ex = job.exception()
if ex is not None:
print(f"Exception catched: {ex}")
executor.shutdown(wait=True)
app.exit()
tui_thread.join()
return 0
if __name__ == '__main__':
main()
$ python ipython-subprocess.py
Parent process => PID: 12161
Worker process => PID: 12162
Python 3.10.4 (main, Jun 29 2022, 12:14:53) [GCC 11.2.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.2.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: "It works as expected"
Out[1]: 'It works as expected'
In [2]: exit
$ python ipython-subprocess.py TUI
Parent process => PID: 12168
Worker process => PID: 12170
Python 3.10.4 (main, Jun 29 2022, 12:14:53) [GCC 11.2.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.2.0 -- An enhanced Interactive Python. Type '?' for help.
Exception catched: I/O operation on closed file
Is it a Prompt Toolkit error? Is there an option I need to specify that I missed?
Thank you very much in advance.
Hello,
I'm having problems embedding an IPython console inside a subprocess when using prompt-toolkit. I am developing an application using a TUI based on pt. For the subprocesses I am using
concurrent.futures.ProcessPoolExecutor
.It seems that, for some reason, the subprocesses close
sys.stdin
and I can't embed an IPython in them. It only works on the parent process. The following snippet is a minimal reproducible example. It creates a dummy pt Application, spawns a subprocess that tries to executeIPython.embed()
. I left the call tostdin_from_terminal()
since it is needed when not using the TUI.Is it a Prompt Toolkit error? Is there an option I need to specify that I missed? Thank you very much in advance.