Skip to content Skip to sidebar Skip to footer

Running Flask Api Without Cmd

I'm working on a company that deploy their system on local computer and servers. The task given to me is to create a python application which communicates with a plc and display ga

Solution 1:

Ok, so this took a while but I figured out how to not use subprocess (mainly because there was another question regarding not using python so the only way would be to convert flask app to .exe and then use subprocess but I found out how to do this using just python), the main issue (simple fix but has to be resolved when using subprocess.Popen too) is that flask restarts the server which starts another process so you have to use use_reloader=False in .run() method. Explanation in comments:

app.py

# import what's necessaryfrom flask import Flask, render_template_string, url_for
from flask import request


app = Flask(__name__)


# sample route@app.route('/')defhome():
    return render_template_string('<a href="{{ url_for("about") }}">To About Page</a>''<h1>Home Page</h1>')


# sample route@app.route('/about')defabout():
    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'])defkill_server():
    func = request.environ.get('werkzeug.server.shutdown')
    if func isNone:
        raise RuntimeError('Not running with the Werkzeug Server. Could not shut down server.')
    func()
    return'Server shutting down...'# to prevent this from running when importingif __name__ == '__main__':
    app.run(debug=True)

run.py

# import all that is necessaryfrom 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 runningdefstart_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 serverdefstop_server():
    ifnot 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 widgetdefupdate_text_log():
    try:
        data = queue.get(block=False)
    except Empty:
        passelse:
        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 hereif __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()

Sources:

The only issue is about displaying the starting message in console, there is a way to remove it by adding import os and then os.environ['WERKZEUG_RUN_MAIN'] = 'true' to the app.py file but there is a slight issue then that stopping the server using the button will do this: Process finished with exit code 15 (at least on Windows) so you will have to find a way to workaround this since I am not able yet to do so

Post a Comment for "Running Flask Api Without Cmd"