Python file runs using python command but not using Flask - python

I have a small application built using Flask and Flask-restx. I can run the app using python app.py and the flask server runs on port 8888. I try to run the file using set FLASK_APP=app.py and run using flask run which seems to run, but doesnt open my swagger page. Please advice.
app.py
import logging.config
import os
from flask import Flask, Blueprint
from flask_cors import CORS
from werkzeug.middleware.proxy_fix import ProxyFix
from src.config import default
from src.api.controllers.endpoints.users import ns as users_namespace
from src.api.controllers.endpoints.statuses import ns as status_namespace
from src.api import api
from src.database import db
app = Flask(__name__)
CORS(app)
app.wsgi_app = ProxyFix(app.wsgi_app)
logging_conf_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '../logging.conf'))
logging.config.fileConfig(logging_conf_path)
log = logging.getLogger(__name__)
def configure_app(flask_app):
flask_app.config['SERVER_NAME'] = default.FLASK_SERVER_NAME
flask_app.config['SQLALCHEMY_DATABASE_URI'] = default.SQLALCHEMY_DATABASE_URI
flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = default.SQLALCHEMY_TRACK_MODIFICATIONS
flask_app.config['SWAGGER_UI_DOC_EXPANSION'] = default.RESTPLUS_SWAGGER_UI_DOC_EXPANSION
flask_app.config['RESTPLUS_VALIDATE'] = default.RESTPLUS_VALIDATE
flask_app.config['RESTPLUS_MASK_SWAGGER'] = default.RESTPLUS_MASK_SWAGGER
flask_app.config['ERROR_404_HELP'] = default.RESTPLUS_ERROR_404_HELP
def initialize_app(flask_app):
configure_app(flask_app)
blueprint = Blueprint('CovidAPI', __name__, url_prefix='/')
api.init_app(blueprint)
api.add_namespace(users_namespace)
api.add_namespace(status_namespace)
flask_app.register_blueprint(blueprint)
db.init_app(flask_app)
def main():
initialize_app(app)
log.info('>>>>> Starting development server at http://{}/ <<<<<'.format(app.config['SERVER_NAME']))
app.run(debug=default.FLASK_DEBUG)
if __name__ == "__main__":
main()
Flask Settings:
# Flask settings
FLASK_SERVER_NAME = 'localhost:8888'
FLASK_DEBUG = True # Do not use debug mode in production
# Flask-Restplus settings
RESTPLUS_SWAGGER_UI_DOC_EXPANSION = 'list'
RESTPLUS_VALIDATE = True
RESTPLUS_MASK_SWAGGER = False
RESTPLUS_ERROR_404_HELP = False
Output using python command:
2020-04-29 10:25:42,519 - __main__ - INFO - >>>>> Starting development server at http://localhost:8888/ <<<<<
* Serving Flask app "app" (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
2020-04-29 10:25:42,610 - werkzeug - INFO - * Restarting with stat
2020-04-29 10:25:45,398 - __main__ - INFO - >>>>> Starting development server at http://localhost:8888/ <<<<<
2020-04-29 10:25:45,426 - werkzeug - WARNING - * Debugger is active!
2020-04-29 10:25:45,458 - werkzeug - INFO - * Debugger PIN: 258-749-652
2020-04-29 10:25:45,530 - werkzeug - INFO - * Running on http://localhost:8888/ (Press CTRL+C to quit)
Running through flask run:
* Serving Flask app "src\app.py" (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
* Debugger is active!
* Debugger PIN: 313-115-045
* Running on http://localhost:6000/ (Press CTRL+C to quit)

The flask run command works by importing an app object from your app.py module.
Therefor the stuff in this function is never executed in that case:
def main():
initialize_app(app)
log.info('>>>>> Starting development server at http://{}/ <<<<<'.format(app.config['SERVER_NAME']))
app.run(debug=default.FLASK_DEBUG)
When running with the python app.py command it is, because this gets executed:
if __name__ == "__main__":
main()
I'm not sure how it runs fully in your case with python, as neither the configure_app or initialize_app functions return the app object. However, you may wish to change the code to something like:
# ...
def configure_app(flask_app):
# ...
return flask_app
def initialize_app(flask_app):
# ...
return flask_app
app = initialize_app(app)
Now that (fully configured) app object is avaialable to flask run. You shouldn't need to set the FLASK_ENV environment variable, as it looks for an object called app by default.
If you still want the ability to run with the interpreter, then add this block to the end, although this is kinda defunct if using the flask command.
if __name__ == "__main__":
log.info('>>>>> Starting development server at http://{}/ <<<<<'.format(app.config['SERVER_NAME']))
app.run(debug=default.FLASK_DEBUG)

Related

I can't post to localhost what I see in the terminal

I want to monitor .hprof files in the system using Grafana, so I wrote a small Flask app. I am able to access localhost, I am able to see the number of hprof files on terminal, but I cannot see the number of hprof files on my localhost. Here is my code:
import fnmatch,os
app = Flask(__name__)
#app.route('/')
def hprof():
num_files = len(fnmatch.filter(os.listdir("/home/ubuntu/files"),'*.hprof'))
return("Total hprof files: ", num_files)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
ubuntu#ubuntu-virtual-machine:~/hprof$ python3 hprof.py
* Serving Flask app "hprof" (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
* Running on http://0.0.0.0:8000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 284-945-814
127.0.0.1 - - [15/Aug/2022 11:58:05] "GET / HTTP/1.1" 3 -
What I see on localhost:
Total hprof files:
Can anyone briefly explain how to solve my problem?
I had the same issue.
I solved it by entering
localhost:8000
In the browser search bar.
In a view function, returning a tuple like this:
return("Total hprof files: ", num_files)
means that Flask treats it as a (response, status) tuple, so num_files is used for the HTTP status code.
In order to return your intended response, you need to return a single string:
return "Total hprof files: " + str(num_files)
See the relevant Flask docs for more info.

Run flask application with uWSGI [duplicate]

This question already has answers here:
Run code after flask application has started
(7 answers)
Closed last year.
I have a flask application and I would like to run it in a "production" way using uwsgi.
I have my launcher.py:
from app import app
import db
if __name__ == "__main__":
db.init()
app.run()
If I run the application with simply python launcher.py it's all ok. Especially, the db.init() is called correctly.
However, if I run using uwgsi with uwsgi app.ini , db.init() is not called.
Here is app.ini:
[uwsgi]
wsgi-file = launcher.py
callable = app
socket = :8080
I'm new with flask and uwsgi so probably I missed something but I could not find the solution in the different tutorials I read.
Also, in case you need it to understand the project, here is app.py:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def index():
return "hello from flask"
if __name__ == "__main__":
db.init()
app.run()
All files are in the same level in my project:
webserver/
- app.ini
- launcher.py
- app.py
- db.py
So, what am I doing wrong here?
Your code under if __name__ == "__main__": is not executed because uwsgi does not run your script like python app.py. Instead it imports the module specified in wsgi-file and looks for an object specified as callable (app in our case). You can test it by using the following script:
from flask import Flask
app = Flask(__name__)
print(__name__)
if __name__ == '__main__':
app.run()
If you run it with python ./flask_app.py then the output will be
$ python ./flask_app.py
__main__
* Serving Flask app 'app' (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: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
(notice __main__ - it means we're running the script). However if you run it with uwsgi the __name__ will be app (it will be the name of your file, so app in my case):
$ uwsgi --http 127.0.0.1:5000 --module app:app
...
*** Operational MODE: single process ***
app
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x7fb2d0c067b0 pid: 46794 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 46794, cores: 1)
Similar output will be if you run your app with FLASK_APP=app flask run - it does not execute script, it just imports it and uses app object from it.
So, in order to initialize database you should either move your db initialization out of if __name__ == "__main__":
from flask import Flask
app = Flask(__name__)
class DB:
def init(self):
self.data = 'Hello, World'
db = DB()
#app.route("/")
def hello_world():
return db.data
db.init()
if __name__ == '__main__':
app.run()
Or add a before_first_request handler:
# replace db.init() with
#app.before_first_request
def init_db():
db.init()
Notice the difference between them - if you put db.init() as a top-level statement it will be executed once you load app.py. If you register a before_first_request callback it will be executed once first request arrives to your application. Pick the one that works best for you.

Not getting web output

I used Flask command in my program for first time. Following was the bit of code I wrote:
from flask import Flask,jsonify, request
app = Flask(__name__)
#app.route("/")
def hello_world():
return "Hello World!"
if (__name__ == "__main__"):
app.run(debug=True)
This code was written by me in IDLE Shell 3.8-32 bit and the output should had come in a web browser. But it didn't came. I just got the following output from IDLE:
* Serving Flask app "sa" (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
app.run(host=0.0.0.0, port=5000, debug=True)
You can change your port number to your convenience.

How do you customize the launching message for Flask?

I'm running a Flask app in Cloud9. Whenever I start my Flask app, it says this message:
* Serving Flask app "app" (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: off
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
Is there a way to change this message? I'd like it to say something like this:
Connect to me at http://0.0.0.0:80/!
I've searched stack overflow and the web but couldn't find anything. I'm starting my app with app.run().
Also, is it possible to make the URL cyan?
You can change everything besides Running on http://0.0.0.0:80/ (Press CTRL+C to quit) by changing show_server_banner of flask.cli:
from flask import Flask
import sys
cli = sys.modules['flask.cli']
# put your own message here
cli.show_server_banner = lambda *x: click.echo("My nice message")
app = Flask(__name__)
app.run(host='0.0.0.0', port='80')
To get rid of the Running on http://0.0.0.0:80/ ... message, you can use unittest.mock:
from unittest import mock
from werkzeug._internal import _log
def my_startup_log(*args):
# log all messages except for the * Running on message
if not args[1].startswith(" * Running on"):
return _log(*args)
app = Flask(__name__)
with mock.patch('werkzeug.serving._log') as mocked:
# patch the logger object and replace with own logger
mocked.side_effect = my_startup_logger
app.run(host='0.0.0.0', port='8000')
This is very hacky and depends on the internal implementation of flask. Be careful when using this in production code, as this could easily break.

How to enable logging of Flask app with `gevent.pywsgi.WSGIServer` and `WebSocketHandler`?

The issue should be reproducible with the following two minimal examples:
Minimal example with app.run()
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return 'Hello'
app.run()
Minimal example with gevent.pywsgi.WSGIServer
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return 'Hello'
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()
The first 5 lines are identical, so both examples only differ in the way they start the server. Both servers do work, I get "Hello" in the browser. The first example prints:
* Serving Flask app "1" (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: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [20/Jun/2019 23:43:15] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/Jun/2019 23:43:19] "GET / HTTP/1.1" 200 -
So the console output shows some information about every request which is handled by the server.
However, with the second example, I don't get any logging output in the console anymore. How do I enable logging for gevent.pywsgi.WSGIServer and WebSocketHandler?
Background (which doesn't matter regarding the issue, I think)
I'm running a Flask app which uses flask_sockets. Because
Werkzeug development server cannot provide the WSGI environ with a websocket interface
I am not able to use the server with app.run() and I'm using gevent.pywsgi.WSGIServer instead. The code of my example above is taken directly from the module's examples at https://github.com/heroku-python/flask-sockets without any modifications.
Logging works differently with gevent.pywsgi.WSGIServer. It uses python logging and is much more sophisticated and flexible.
Here's an example:
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
import logging
logging.basicConfig(level=logging.INFO)
server = pywsgi.WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()
And now wherever you want output, you can do:
logging.info("You can see me now...")
If you want to see startup info from WSGIServer, then set the log level to DEBUG and you can see tons of output.
It should work like that, but it's a bug in WebSocketHandler from the geventwebsocket module which has already been reported: https://gitlab.com/noppo/gevent-websocket/issues/16

Categories