@@ -151,6 +151,10 @@ class IPKernelApp(BaseIPythonApplication, InteractiveShellApp, ConnectionFileMix
151151
152152 _ports = Dict ()
153153
154+ _original_io = Any ()
155+ _io_modified = Bool (False )
156+ _blackhole = Any ()
157+
154158 subcommands = {
155159 "install" : (
156160 "ipykernel.kernelspec.InstallIPythonKernelSpecApp" ,
@@ -204,10 +208,6 @@ def abs_connection_file(self):
204208 Interrupt this process when the parent is signaled.
205209 """ ,
206210 ).tag (config = True )
207- closed = Bool (
208- True ,
209- help = "whether this is closed" ,
210- )
211211
212212 def init_crash_handler (self ):
213213 """Initialize the crash handler."""
@@ -401,9 +401,6 @@ def init_heartbeat(self):
401401 self .heartbeat .start ()
402402
403403 def close (self ):
404- if self .closed :
405- return
406- self .closed = True
407404 """Close zmq sockets in an orderly fashion"""
408405 # un-capture IO before we start closing channels
409406 self .reset_io ()
@@ -477,6 +474,7 @@ def log_connection_info(self):
477474
478475 def init_blackhole (self ):
479476 """redirects stdout/stderr to devnull if necessary"""
477+ self ._save_io ()
480478 if self .no_stdout or self .no_stderr :
481479 # keep reference around so that it would not accidentally close the pipe fds
482480 self ._blackhole = open (os .devnull , "w" ) # noqa: SIM115
@@ -491,6 +489,7 @@ def init_blackhole(self):
491489
492490 def init_io (self ):
493491 """Redirect input streams and set a display hook."""
492+ self ._save_io ()
494493 if self .outstream_class :
495494 outstream_factory = import_item (str (self .outstream_class ))
496495
@@ -531,34 +530,42 @@ def init_io(self):
531530
532531 self .patch_io ()
533532
533+ def _save_io (self ):
534+ if not self ._io_modified :
535+ self ._original_io = sys .stdout , sys .stderr , sys .displayhook
536+ self ._io_modified = True
537+
534538 def reset_io (self ):
535539 """restore original io
536540
537541 restores state after init_io
538542 """
543+ if not self ._io_modified :
544+ return
539545 stdout , stderr , displayhook = sys .stdout , sys .stderr , sys .displayhook
540546 sys .stdout , sys .stderr , sys .displayhook = self ._original_io
547+ self ._io_modified = False
541548 if finish_displayhook := getattr (displayhook , "finish_displayhook" , None ):
542549 finish_displayhook ()
543- if hasattr (sys . stderr , "_original_stdstream_copy" ):
550+ if hasattr (stderr , "_original_stdstream_copy" ):
544551 for handler in self .log .handlers :
545552 if (
546553 isinstance (handler , StreamHandler )
547554 and (buffer := handler .stream .buffer )
548555 and (fileno := buffer .fileno )
549- and fileno () == sys . stderr ._original_stdstream_copy
556+ and fileno () == stderr ._original_stdstream_copy
550557 ):
551558 self .log .debug ("Seeing logger to raw filedescriptor, rerouting back to stderr" )
552559
553560 handler .stream = TextIOWrapper (
554561 FileIO (
555- sys . stderr ._original_stdstream_fd ,
562+ stderr ._original_stdstream_fd ,
556563 "w" ,
557564 )
558565 )
559- if hasattr (sys . stderr , "_original_stdstream_copy" ):
566+ if hasattr (stderr , "_original_stdstream_copy" ):
560567 stderr .close ()
561- if hasattr (sys . stdout , "_original_stdstream_copy" ):
568+ if hasattr (stdout , "_original_stdstream_copy" ):
562569 stdout .close ()
563570 if self ._blackhole :
564571 self ._blackhole .close ()
@@ -735,9 +742,6 @@ def init_pdb(self):
735742 @catch_config_error
736743 def initialize (self , argv = None ):
737744 """Initialize the application."""
738- self .closed = False
739- self ._blackhole = None
740- self ._original_io = sys .stdout , sys .stderr , sys .displayhook
741745 self ._init_asyncio_patch ()
742746 super ().initialize (argv )
743747 if self .subapp is not None :
0 commit comments