好的,所以这花了一段时间,但我想出了如何不使用subprocess(主要是因为还有另一个关于不使用python的问题,所以唯一的方法是将flask应用程序转换为.exe然后使用subprocess,但我发现了如何只使用python来做到这一点),主要问题(简单修复,但在使用subprocess.Popen时也必须解决)是flask重新启动服务器启动另一个进程所以你必须使用use_reloader=False 在.run() 方法中。 cmets中的解释:
app.py
# import what's necessary
from flask import Flask, render_template_string, url_for
from flask import request
app = Flask(__name__)
# sample route
@app.route('/')
def home():
return render_template_string('<a href="{{ url_for("about") }}">To About Page</a>'
'<h1>Home Page</h1>')
# sample route
@app.route('/about')
def about():
return render_template_string('<a href="{{ url_for("home") }}">To Home Page</a>'
'<h1>About Page</h1>')
# important route that will do the stopping part since that was a requirement in the question
# link to this in the answer at the bottom
@app.route('/kill_server', methods=['GET'])
def kill_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server. Could not shut down server.')
func()
return 'Server shutting down...'
# to prevent this from running when importing
if __name__ == '__main__':
app.run(debug=True)
run.py
# import all that is necessary
from tkinter import Tk, Text, Button, Frame
from for_so_dir.app import app as server
from threading import Thread
from queue import Queue, Empty
import requests
import logging.handlers
# simple dictionary to avoid using `global`, just a preference of mine
info = {'server_is_running': False}
# the function that starts server (multiprocessing is not possible with flask as far as I know)
# basically checks if the server is not running already and if it is not then starts a thread
# with the server (which is the same as `app` in the app.py) and sets that server is running
def start_server():
if info['server_is_running']:
return
Thread(target=server.run, kwargs={'debug': True, 'use_reloader': False}, daemon=True).start()
info['server_is_running'] = True
# function from stopping server, again in the answer at the bottom, but basically
# this sends a request to the server and that request executes a function
# that stops the server
def stop_server():
if not info['server_is_running']:
return
requests.get('http://127.0.0.1:5000/kill_server')
# function for showing the logs in the Text widget, it simply tries to get data from
# the queue (if there is nothing it simply loops again) and then inserts that data into
# the text widget
def update_text_log():
try:
data = queue.get(block=False)
except Empty:
pass
else:
log.config(state='normal')
log.insert('end', data.msg + '\n')
log.config(state='disabled')
finally:
root.after(100, update_text_log)
# this `if statement` is not that necessary in the current code but it might as well
# stay here
if __name__ == '__main__':
# initialise the Queue
queue = Queue()
# now the main part, to get the info from flask you need to use `logging`
# since that is what it uses for all the messages, and use the `QueueHandler`
# to put the messages in the queue and then update them using the above
# function
logging.basicConfig(handlers=(logging.handlers.QueueHandler(queue), ))
# simple `tkinter` stuff
root = Tk()
# this part can be removed or made toggleable but it allows to easier see how
# this works in action
root.attributes('-topmost', True)
log = Text(root, state='disabled')
log.pack(expand=True, fill='both')
update_text_log()
button_frame = Frame(root)
button_frame.pack(fill='x')
Button(button_frame, text='Start Server', command=start_server).pack(expand=True, fill='x', side='left')
Button(button_frame, text='Stop Server', command=stop_server).pack(expand=True, fill='x', side='right')
root.mainloop()
来源:
唯一的问题是关于在控制台中显示启动消息,有一种方法可以通过添加import os 然后将os.environ['WERKZEUG_RUN_MAIN'] = 'true' 添加到app.py 文件中来删除它,但是有一个小问题然后停止服务器使用该按钮将执行此操作:Process finished with exit code 15(至少在 Windows 上)因此您必须找到解决此问题的方法,因为我还不能这样做