@@ -105,6 +105,37 @@ def buildProtocol(self, addr):
105105 return EvalProtocol (self .repl )
106106
107107
108+ class TwistedEventLoop (urwid .TwistedEventLoop ):
109+
110+ """TwistedEventLoop modified to properly stop the reactor.
111+
112+ urwid 0.9.9 and 0.9.9.1 crash the reactor on ExitMainLoop instead
113+ of stopping it. One obvious way this breaks is if anything used
114+ the reactor's thread pool: that thread pool is not shut down if
115+ the reactor is not stopped, which means python hangs on exit
116+ (joining the non-daemon threadpool threads that never exit). And
117+ the default resolver is the ThreadedResolver, so if we looked up
118+ any names we hang on exit. That is bad enough that we hack up
119+ urwid a bit here to exit properly.
120+ """
121+
122+ def handle_exit (self , f ):
123+ def wrapper (* args , ** kwargs ):
124+ try :
125+ return f (* args , ** kwargs )
126+ except urwid .ExitMainLoop :
127+ # This is our change.
128+ self .reactor .stop ()
129+ except :
130+ # This is the same as in urwid.
131+ # We are obviously not supposed to ever hit this.
132+ import sys
133+ print sys .exc_info ()
134+ self ._exc_info = sys .exc_info ()
135+ self .reactor .crash ()
136+ return wrapper
137+
138+
108139class Statusbar (object ):
109140
110141 """Statusbar object, ripped off from bpython.cli.
@@ -753,7 +784,7 @@ def main(args=None, locals_=None, banner=None):
753784 sys .stderr .write ('Reactor %s does not exist\n ' % (
754785 options .reactor ,))
755786 return
756- event_loop = urwid . TwistedEventLoop (reactor )
787+ event_loop = TwistedEventLoop (reactor )
757788 else :
758789 # None, not urwid.SelectEventLoop(), to work with
759790 # screens that do not support external event loops.
0 commit comments