Flask autoreload not reloading or picking up changes - python

I have an app.py flask application, that I want to enable auto-reloading for. This is the entry point:
APP = Flask(__name__)
APP.config.from_object(os.environ['APP_SETTINGS'])
# a lot of configurations ommited
if __name__ == "__main__":
APP.run(debug=True, port=5005)
When I run the app, I get this in the terminal:
/Users/George/myproject/venv/bin/python /Users/George/myproject/app.py
* Running on http://127.0.0.1:5005/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: 338-825-330
and when I modify one of my controllers it picks up that a change has occurred:
* Detected change in '/Users/George/myproject/web_endpoints/user.py', reloading
but the change doesn't occur, and if I do another change, it never gets picked up (not reported in the terminal).

Flask is not recommended to use app.run() with automatic reloading as this is badly supported
Here's the comments in source code of Flask
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
"""Runs the application on a local development server.
...
If you want to run the application in debug mode, but disable the
code execution on the interactive debugger, you can pass
``use_evalex=False`` as parameter. This will keep the debugger's
traceback screen active, but disable code execution.
It is not recommended to use this function for development with
automatic reloading as this is badly supported. Instead you should
be using the :command:`flask` command line script's ``run`` support.
...
"""
pass
But you can force to use reloader like this:
if __name__ == '__main__':
app.run(host=config.HOST, port=config.PORT, debug=True)
Take care, the app.run() must be wrapped with if __name__ == '__main__'.

Related

Flask app is not destroyed when server exits? [duplicate]

This question already has answers here:
__del__ on exit behavior
(1 answer)
I don't understand this python __del__ behaviour
(8 answers)
Closed 2 years ago.
I have the following, seemingly easy, issue which I cannot figure out.
I made a short, self-containing example below:
from flask import Flask
class MyFlask(Flask):
def __init__(self, name):
super().__init__(name)
print(f'Initialising Flask app {id(self)}')
def __del__(self):
print(f'Deleting Flask app {id(self)}')
if __name__ == "__main__":
app = MyFlask(__name__)
app.run(host='0.0.0.0', port=5000, debug=True)
When one runs this, you will see two instances of MyFlask being initialized, but only one being destroyed. I know why there are two calls to the init method (the way Werkzeug works), but why is only one destroyed?
See the sample output below:
(venv) D:\Onedrive\Documents\Projects\FlaskReloader>python example.py
Initialising Flask app 1944027544880
* Serving Flask app "example" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Restarting with stat
Initialising Flask app 2213899877680
* Debugger is active!
* Debugger PIN: 247-475-647
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Deleting Flask app 1944027544880
Any ideas? Thanks!
I think it cause by the override of Flask.__del__
Call super on that __del__ or don't override
print(f'Deleting Flask app {id(self)}')
super().__del__(self)

Python Flask - How to start python server using flask and execute it multiple times using multiple argumens

I have tested basic Flask script (hello.py) and it is working fine. I have commented out the main function routing part and just executed the script.
from flask import Flask
app = Flask(__name__)
''' #Commenting the Main function part
#app.route("/")
def main():
return "Welcome!"
'''
if __name__ == "__main__":
app.run(host= '0.0.0.0')
As expected, the server is started and I got the following message as well :
C:\>python hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Now my requirement is once this python server is started, how to execute another python script and route to this python server.
For example I have the following script which needs to be executed via browser (since the python server is already up and running) by accessing http://127.0.0.1:5000/arg1/arg2
import .....
from flask import Flask
app = Flask(__name__)
#app.route('/<string:arg1>/<string:arg2>')
def main():
do something ........
call sub-function(arg1, arg2)
do something ........
if __name__ == '__main__':
arg1 = 100
arg2 = 50
#app.run(debug=True) **#I should not run this again as server is already started.So commented it out**
main(arg1, arg2) #Calling Main function using two IDs as arguments.
Note : If i keep app.run() in the actual program script which needs to be executed, then it is working fine. But my requirement is server start script actual program script should be different but somehow interlinked via app. I am not sure how to achieve this.
Here it seems that you want the same API(with the same port number all the time) to be called when you run the python script. that can be done by addingapp.run(port=50000, debug=True) at the end.
And place all #app.route() in that same python script (App.py) by migrating body of the Def methodName(): to a different Python script in the same directory and calling that by addingfrom .SubScript import *
The SubScript.py files has to have classes to be called in App.py as objects. and in those classes methods needs to be called def methodName(self): in order to be run as an object
This way you have clean and organized code base to use with python flask. If you can use the Pycharm editor the process will be much easier.

How can I run two flask servers in two threads/processes on two ports under one python program?

I'm writing a python debugging library which opens a flask server in a new thread and serves information about the program it's running in. This works fine when the program being debugged isn't a web server itself. However if I try to run it concurrently with another flask server that's running in debug mode, things break. When I try to access the second server, the result alternates between the two servers.
Here's an example:
from flask.app import Flask
from threading import Thread
# app1 represents my debugging library
app1 = Flask('app1')
#app1.route('/')
def foo():
return '1'
Thread(target=lambda: app1.run(port=5001)).start()
# Cannot change code after here as I'm not the one writing it
app2 = Flask('app2')
#app2.route('/')
def bar():
return '2'
app2.run(debug=True, port=5002)
Now when I visit http://localhost:5002/ in my browser, the result may either be 1 or 2 instead of consistently being 2.
Using multiprocessing.Process instead of Thread has the same result.
How does this happen, and how can I avoid it? Is it unavoidable with flask/werkzeug/WSGI? I like flask for its simplicity and ideally would like to continue using it. If that's not possible, what's the simplest library/framework that I can use that won't interfere with any other web servers running at the same time? I'd also like to use threads instead of processes if possible.
The reloader of werkzeug (which is used in debug mode by default) creates a new process using subprocess.call, simplified it does something like:
new_environ = os.environ.copy()
new_environ['WERKZEUG_RUN_MAIN'] = 'true'
subprocess.call([sys.executable] + sys.argv, env=new_environ, close_fds=False)
This means that your script is reexecuted, which is usually fine if all it contains is an app.run(), but in your case it would restart both app1 and app2, but both now use the same port because if the OS supports it the listening port is opened in the parent process, inherited by the child and used there directly if an environment variable WERKZEUG_SERVER_FD is set.
So now you have two different apps somehow using the same socket.
You can see this better if you add some output, e.g:
from flask.app import Flask
from threading import Thread
import os
app1 = Flask('app1')
#app1.route('/')
def foo():
return '1'
def start_app1():
print("starting app1")
app1.run(port=5001)
app2 = Flask('app2')
#app2.route('/')
def bar():
return '2'
def start_app2():
print("starting app2")
app2.run(port=5002, debug=True)
if __name__ == '__main__':
print("PID:", os.getpid())
print("Werkzeug subprocess:", os.environ.get("WERKZEUG_RUN_MAIN"))
print("Inherited FD:", os.environ.get("WERKZEUG_SERVER_FD"))
Thread(target=start_app1).start()
start_app2()
This prints for example:
PID: 18860
Werkzeug subprocess: None
Inherited FD: None
starting app1
starting app2
* Running on http://127.0.0.1:5001/ (Press CTRL+C to quit)
* Running on http://127.0.0.1:5002/ (Press CTRL+C to quit)
* Restarting with inotify reloader
PID: 18864
Werkzeug subprocess: true
Inherited FD: 4
starting app1
starting app2
* Debugger is active!
If you change the startup code to
if __name__ == '__main__':
if os.environ.get("WERKZEUG_RUN_MAIN")) != 'true':
Thread(target=start_app1).start()
start_app2()
then it should work correctly, only app2 is reloaded by the reloader. However it runs in a separate process, not in a different thread, that is implied by using the debug mode.
A hack to avoid this would be to use:
if __name__ == '__main__':
os.environ["WERKZEUG_RUN_MAIN"] = 'true'
Thread(target=start_app1).start()
start_app2()
Now the reloader thinks it's already running in the subprocess and doesn't start a new one, everything runs in the same process. Reloading won't work and I don't know what other side effects that may have.

Replacing flask internal web server with Apache

I have written a single user application that currently works with Flask internal web server. It does not seem to be very robust and it crashes with all sorts of socket errors as soon as a page takes a long time to load and the user navigates elsewhere while waiting. So I thought to replace it with Apache.
The problem is, my current code is a single program that first launches about ten threads to do stuff, for example set up ssh tunnels to remote servers and zmq connections to communicate with a database located there. Finally it enters run() loop to start the internal server.
I followed all sorts of instructions and managed to get Apache service the initial page. However, everything goes wrong as I now don't have any worker threads available, nor any globally initialised classes, and none of my global variables holding interfaces to communicate with these threads do not exist.
Obviously I am not a web developer.
How badly "wrong" my current code is? Is there any way to make that work with Apache with a reasonable amount of work? Can I have Apache just replace the run() part and have a running application, with which Apache communicates? My current app in a very simplified form (without data processing threads) is something like this:
comm=None
app = Flask(__name__)
class CommsHandler(object):
__init__(self):
*Init communication links to external servers and databases*
def request_data(self, request):
*Use initialised links to request something*
return result
#app.route("/", methods=["GET"]):
def mainpage():
return render_template("main.html")
#app.route("/foo", methods=["GET"]):
def foo():
a=comm.request_data("xyzzy")
return render_template("foo.html", data=a)
comm = CommsHandler()
app.run()
Or have I done this completely wrong? Now when I remove app.run and just import app class to wsgi script, I do get a response from the main page as it does not need reference to global variable comm.
/foo does not work, as "comm" is an uninitialised variable. And I can see why, of course. I just never thought this would need to be exported to Apache or any other web server.
So the question is, can I launch this application somehow in a rc script at boot, set up its communication links and everyhing, and have Apache/wsgi just call function of the running application instead of launching a new one?
Hannu
This is the simple app with flask run on internal server:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
To run it on apache server Check out fastCGI doc :
from flup.server.fcgi import WSGIServer
from yourapplication import app
if __name__ == '__main__':
WSGIServer(app).run()

Is there any way of detecting an automatic reload in flask's debug mode?

I have a flask app where I'd like to execute some code on the first time the app is run, not on the automatic reloads triggered by the debug mode. Is there any way of detecting when a reload is triggered so that I can do this?
To give an example, I might want to open a web browser every time I run the app from sublime text, but not when I subsequently edit the files, like so:
import webbrowser
if __name__ == '__main__':
webbrowser.open('http://localhost:5000')
app.run(host='localhost', port=5000, debug=True)
You can set an environment variable.
import os
if 'WERKZEUG_LOADED' in os.environ:
print 'Reloading...'
else:
print 'Starting...'
os.environ['WERKZEUG_LOADED']='TRUE'
I still don't know how to persist a reference that survives the reloading, though.
What about using Flask-Script to kick off a process before you start your server? Something like this (cribbed from their documentation and edited slightly):
# run_devserver.py
import webbrowser
from flask.ext.script import Manager
from myapp import app
manager = Manager(app)
if __name__ == "__main__":
webbrowser.open('http://localhost:5000')
manager.run(host='localhost', port=5000, debug=True)
I have a Flask app where it's not really practical to change the DEBUG flag or disable reloading, and the app is spun up in a more complex way than just flask run.
#osa's solution didn't work for me with flask debug on, because it doesn't have enough finesse to pick out the werkzeug watcher process from the worker process that gets reloaded.
I have this code in my main package's __init__.py (the package that defines the flask app). This code is run by another small module which has from <the_package_name> import app followed by app.run(debug=True, host='0.0.0.0', port=5000). Therefore this code is executed before the app starts.
import ptvsd
import os
my_pid = os.getpid()
if os.environ.get('PPID') == str(os.getppid()):
logger.debug('Reloading...')
logger.debug(f"Current process ID: {my_pid}")
try:
port = 5678
ptvsd.enable_attach(address=('0.0.0.0', port))
logger.debug(f'========================== PTVSD waiting on port {port} ==========================')
# ptvsd.wait_for_attach() # Not necessary for my app; YMMV
except Exception as ex:
logger.debug(f'PTVSD raised {ex}')
else:
logger.debug('Starting...')
os.environ['PPID'] = str(my_pid)
logger.debug(f"First process ID: {my_pid}")
NB: note the difference between os.getpid() and os.getppid() (the latter gets the parent process's ID).
I can attach at any point and it works great, even if the app has reloaded already before I attach. I can detach and re-attach. The debugger survives a reload.

Categories

Resources