Cannot exit Python script using Ctrl-C if thread executed webbrowser.open ()

I am using the Bottle application framework for Python ( pip install bottle) and want to run a web application that can only be accessed from the local computer (this is essentially a desktop application that uses a browser for the GUI). To start the bottle app, I need to call bottle.run(), but this blocks until the script is executed. You stop it by pressing Ctrl-C.

However, I also want this application to open a web browser for localhost by calling webbrowser.open(). The problem is that I cannot call webbrowser.open()first because the web application will not start, but if I call bottle.run(), it will not return first while the web application is running, and I cannot continue to call webbrowser.open().

My solution was to put a call webbrowser.open()inside a thread:

import bottle
import threading
import webbrowser
import time

class BrowserOpener(threading.Thread):
  def run(self):
    time.sleep(1) # waiting 1 sec is a hack, but it works
    webbrowser.open('http://localhost:8042')
    print('Browser opened')

@bottle.route('/')
def index():
  return 'hello world!'

BrowserOpener().start()
bottle.run(host='localhost', port=8042)

The problem with this now is that pressing Ctrl-C in the terminal does not work, so I cannot stop the web application other than closing the terminal. I am not sure why this is so: it 'Browser opened'is printed on the screen, so I know that it is webbrowser.open()returning.

I am on Windows 7.

, webbrowser python self._running = False, . , join() .

os.system('python openbrowser.py') script, -, Ctrl-C.

threading.Timer(1, webbrowser.open, ['http://localhost:8042']).start(), Ctrl-C.

, ?

+4
1

:

  • , , , . , , .
  • Windows , Ctrl-C. , Windows Python, .

:

, , , () . , , . , .

import ctypes
import threading
import webbrowser
import bottle


class SimpleExampleApp():
    def __init__(self):
        self.app = bottle.Bottle()

        #define all of the routes for your app inside the init method
        @self.app.get('/')
        def index():
            return 'It works!'

        @self.app.get('/other_route')
        def alternative():
            return 'This Works Too'

    def run(self):
        self.start_server_thread()
        #depending upon how much configuration you are doing
        #when you start the server you may need to add a brief
        #delay before opening the browser to make sure that it
        #is ready to receive the initial request
        webbrowser.open('http://localhost:8042')

    def start_server_thread(self):
        self.server_thread = threading.Thread(
            target = self.app.run, 
            kwargs = {'host': 'localhost', 'port': 8042}
        )
        self.server_thread.start()

    def stop_server_thread(self):
        stop = ctypes.pythonapi.PyThreadState_SetAsyncExc(
            ctypes.c_long(self.server_thread.get_ident()), 
            ctypes.py_object(KeyboardInterrupt)
        )
        #adding a print statement for debugging purposes since I
        #do not know how well this will work on Windows platform
        print('Return value of stop was {0}'.format(stop))
        self.server_thread.join()


my_app = SimpleExampleApp()
my_app.run()

#when you're ready to stop the app, simply call
#my_app.stop_server_thread()

, , , , . !

+1

Source: https://habr.com/ru/post/1674778/


All Articles