Flask uWSGI application structure and python3 imports - python-3.x

I have a basic flask-restful application with a structure that looks like this as recommended on the flask website.
/application
/application
/config.py
/__init__.py
/wsgi.ini
Slightly irrelevant, but config.py is generated by our CD server.
wsgi.ini looks likes this
[uwsgi]
module = application:app
master = true
processes =5
socket = /tmp/application.sock
chmod-socket = 660
vacuum = true
die-on-term = true
and __init__.py looks something like this
import config
from flask import Flask, request, g
from flask_restful import Resource, Api, abort
app = Flask(__name__)
api = Api(app)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
Now when I try to startup the application using uwsgi --ini wsgi.ini I get this error:
File "./application/__init__.py", line 2, in <module>
import config
Originally __init__.py was called main.py and I executed that to debug, which is why the import is now wrong. I'm guess I will need to change the import to be from .config import *
My question is two fold:
Could I have avoided the import problem completely. ie is there a way in python3 to import sibling modules that will work for both approaches
is my wsgi.ini in the correct place, or should it be in the inner application directory?

Python 3.x dropped support for infra-package relative imports. You need to use an absolute import:
from application import config
or the new spelling of relative imports:
from . import config
If you need to also support legacy versions of Python you can enable this behavior with:
from __future__ import absolute_import

Related

Python Flask app is not running on heroku servers

I am trying to deploy my flask app on heroku but it shows a runtime error on the heroku server, but when i test it on my end, AKA localhost, it seems to work fine
My Code:
import flask
from flask import request
from flask import jsonify
from GoogleNews import GoogleNews
from apscheduler.schedulers.background import BackgroundScheduler
import multiprocessing
googlenews = GoogleNews()
news_latest = []
googlenews.set_lang('en')
googlenews.set_period('1d')
googlenews.set_encode('utf-8')
def get_latest_news():
global news_latest
googlenews.get_news('TECHNOLOGY')
news_latest = googlenews.result()
my_scheduler = BackgroundScheduler()
my_scheduler.add_job(func=get_latest_news, trigger="interval", seconds=5)
my_scheduler.start()
app=flask.Flask(__name__)
#app.route('/', methods=["GET"])
def home():
return jsonify(news_latest[0: 3])
app.run()
requirements.txt:
gunicorn
GoogleNews
APScheduler
PROCFILE:
web: gunicorn app:appweb: gunicorn app:app
runtime.txt:
python-3.9.4
But the server seems to crash when you open it,
And what is remarkable is in the logs, Flask says it is running on a DEVELOPMENT server. It prints the location where it has started the app as 127.0.0.0.5000
I was able to overcome this problem, The right way of doing this is:
import flask
from flask import request
from flask import jsonify
from GoogleNews import GoogleNews
from apscheduler.schedulers.background import BackgroundScheduler
import multiprocessing
googlenews = GoogleNews()
news_latest = []
googlenews.set_lang('en')
googlenews.set_period('1d')
googlenews.set_encode('utf-8')
def get_latest_news():
global news_latest
googlenews.get_news('TECHNOLOGY')
news_latest = googlenews.result()
my_scheduler = BackgroundScheduler()
my_scheduler.add_job(func=get_latest_news, trigger="interval", seconds=5)
my_scheduler.start()
app=flask.Flask(__name__)
#app.route('/', methods=["GET"])
def home():
return jsonify(news_latest[0: 3])
The change was to remove app.run() since heroku servers will already be running your code, if you put the app.run() heroku will consider this as default code and will run that too, hence the interpretation process will stop at app.run() and will never complete the interpretation. Hence the app will crash with no return response.
On localhost is fine to use the default 5000 port but on Heroku you need to use the one provided by the platform in the $PORT env variable
server_port = int(os.environ.get("PORT", 5000))
app.run(debug=False, port=server_port, host='0.0.0.0')

current_app application context in flask. Get working instance of flask

I am trying to setup simple flask application to perceive app_context() feature.
This is my code:
# config.py
UPDATE_PERIOD = 100.0
# init.py
from flask import Flask
import config
app = Flask(__name__)
app.config.from_object(config)
app.config['DEBUG'] = True
#app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == "__main__":
app.run()
# ex.py
from flask import current_app
from flask import Flask
app = Flask(__name__)
with app.app_context() as app:
print(current_app.config['DEBUG'])
print(current_app.config['UPDATE_PERIOD'])
Now, I am running my init.py:
python3 init.py
* Serving Flask app "init" (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://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 666-659-182
which is okay, how it should be.
Here I expect that app.config['DEBUG'] = True and app.config['UPDATE_PERIOD'] = 100.0
And I am trying to extract this vars in ex.py.
The problem is: when I execute: python3 ex.py I expect this:
True
100.0
but eventually I am getting this:
False
Traceback (most recent call last):
File "ex.py", line 10, in <module>
print(current_app.config['UPDATE_PERIOD'])
KeyError: 'UPDATE_PERIOD'
so I cannot get how app_context() feature is working whereas I think I am doing the same things as written in docs.
There is an option to import in ex.py:
from init import app
but I want to get working instance without complex import since my application is quite big.
Can anyone please help me with this..?
Thank you in advance!

Not able to import module server from my testing folder

I am writing a flask app which follows the following folder structure.
backend
server.py
__init__.py
test
__init__.py
servertest.py
"""Server ping test for flask"""
import flask
import pytest
from server import app
#pytest.fixture()
def client():
yield testing.TestClient(app)
def test_ping_resource(client):
doc = "Flask GET service is working"
result = client.simulate_get("/api/ping")
assert result.status_code == 200
assert result.json == doc
And this is my test file. When I am running the file. it gives
from server import app
E ImportError: No module named 'server'
What am I doing wrong, which is making the server module invisible to test module?
When you run a python file, its parent folder is added to the python path, but the parent of its parent (here, your root folder) is not!
What you could do is:
running your tests from the root folder (preferred)
Using relative imports, here: from ..server import app
Modify your python path (not advised)
Python imports modules from a list of path:
import sys
sys.path
You have to provide Python a way to find server.py:
you can run your code from the backend directory, because the current path is automatically happened to sys.path (cd backend; pytest)
you can add the full path to backend to PYTHONPATH
At some point, you will need to read the doc about import.
Also, to use pytest naturally, your test files must start with test.

Import issues Python3: import from package for flask project with api modules

I have my code structured as follows:
src/
--- api/
--- --- __init__.py
--- example_app.py
the init.py contains the following code:
from flask_restplus import Api
from api.about_api import api as about_api
from api.types_api import api as types_api
stackl_api = Api(<Snip>)
stackl_api.add_namespace(about_api)
stackl_api.add_namespace(types_api)
In example_app.py, I try to do this:
import stackl_api
app = Flask(__name__)
blueprint = Blueprint('stackl_api', __name__)
stackl_api.init_app(blueprint)
app.register_blueprint(blueprint)
But this gives the error
from .api import api │
ImportError: attempted relative import with no known parent package
if doing "from api import api" it gives "ModuleNotFoundError: No module named 'api' "
I'm probably forgetting something. Can you help?
In example_app.py, you need to replace
from api import api
By
import api

How to deploy flask backend with waitress server to the internet?

I programmed a flask backend, and made it work on my local network (wifi, ethernet etc). However I can't manage to expand it so external searches reach it. The code for the backend looks like this:
import os
from flask import Flask, flash, request, redirect, url_for, send_from_directory
from waitress import serve
other imports...
app = Flask(__name__)
app.secret_key = os.urandom(24)
.....
if __name__ == '__main__':
serve(app,host='0.0.0.0',port=5000)
How should I give the server an external IP?
If I can make a suggestion, did you try using gevent? It provides a WSGI standalone server for you to replace the built-in option shipped with Flask.
It is very straightforward to use it:
pip install gevent
And you can plug into your app like this:
import os
from gevent.pywsgi import WSGIServer # Imports the WSGIServer
from gevent import monkey; monkey.patch_all()
from flask import Flask, flash, request, redirect, url_for, send_from_directory
app = Flask(__name__)
app.secret_key = os.urandom(24)
if __name__ == '__main__':
LISTEN = ('0.0.0.0',5000)
http_server = WSGIServer( LISTEN, app )
http_server.serve_forever()
Gevent also provides support for SSL
You can use it on its own or along with gunicorn or circusd
I hope it helps you!

Resources