I'm having issues with deploying a Flask Application with WSGI and PythonAnywhere. I assume I have done something wrong but I wasn't able to find exactly what I did do wrong.
Here's my WSGI config file
import sys
# add your project directory to the sys.path
project_home = u'/home/{redacted}/src'
if project_home not in sys.path:
sys.path = [project_home] + sys.path
from start import run as application
Here's start.py
from bin import app
run = app.register().run()
Although if I try it this way it still does not work
from bin import app
run = app.register()
And here's what I'm doing in bin/main.py
class Application():
# Some required code redacted, although not necessary for this example
def __init__(self):
self.app = Flask(__name__, instance_relative_config=True)
def register(self):
""" Starts Flask App """
try:
self.configure_app()
self.register_blueprints()
except Exception as e:
print(f"Error configuring Application: {e}")
return self.app
app = Application()
Just in case you're interested, here's how it's imported through bin/__ init __.py
from .main import app
I do understand that the method in which I am doing this is over complicating it a little bit, and that I could get it working with a more normal method. Although I want it done this way and I'm fairly sure it can work this way, because the example I've shown 100% works on my machine.
Help is very appreciated. I am 100% aware I am doing something wrong here I just need help figuring out what it is.
Related
I'm converting a cli application to use a REST api and I've read up on flask and I thought I understood things but apparently not :-D. based on this: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
I have a directory structure:
--myApp
myApp.py
--APIService
__init__.py
WebService.py
myApp.py:
from APIService import app
app.run(debug = True )
init:
from flask import Flask
app = Flask(__name__)
from app import routes
WebService.py:
from APIService import app
class WebService(object):
'''
classdocs
'''
def __init__(self,):
'''
Constructor
'''
#app.route('/')
#app.route('/index')
def index():
return "Hello, World!"
I've tried this a few different ways like renaming app to APIService but I keep circling back to the same error: APIService\__init__.py", line 5, in <module> from app import routes ImportError: No module named app
I just don't get what I'm doing wrong here. I did pip install flask so the module is there. I skipped the environment part but that's because I wasn't bothered with running globally for now. anyone have a clue as to what I messed up?
In the following line insideAPIService\__init__.py:
from app import routes
the keyword routes is referencing a separate Python Module inside the APIService folder that is named "routes.py" in the Flask Mega Tutorial. It seems like you have renamed the "routes.py" file to "WebService.py" so you can solve the import issue by changing the import line insideAPIService\__init__.pyto:
from app import WebService
I’m relatively new to python and am looking for a pythonic way to handle this practice.
I’ve inherited a fairly trivial Python 2.7 Flask app that runs under uwsgi that I want to add some unit tests to. It does some initialization at indentation level 0 that is required when it’s running in uwsgi but needs to be skipped when under test.
I’m given to understand that often python apps use the
if __name__ == '__main__':
pattern to isolate code that should run when the script is run on its own and should not run when it’s imported. In this case, however, both when the script is run under uwsgi and when the script is imported into the unit tests, __name__ is the same; the name of the script, so I can’t use that to differentiate between uwsgi and unit-testing environments.
This sample code illustrates what I'm working with.
In the Flask application (flask_app.py):
import logging
import bcrypt
from flask import Flask, jsonify, abort, make_response, request
from ConfigParser import SafeConfigParser
# some initialization that only makes sense when running from the uwsgi context on the server
PARSER = SafeConfigParser()
PARSER.read('config.ini')
LOG_FILE = PARSER.get('General', 'logfile')
APP = Flask(__name__)
#APP.route('/', methods=['GET'])
def index
...
#APP.route('/<p1>/<p2>', methods=['PUT'])
def put(p1, p2):
...
if __name__ == '__main__':
APP.run(debug = True, host='0.0.0.0')
In the unit tests (tests.py):
import os
import unittest
from flask import json
from flask_app import APP
class FlaskAppTestCase(unittest.TestCase):
def setUp(self):
self.APP = APP.test_client()
def test_GET(self):
resp = self.APP.get('/')
assert 'Some Html' in resp.data
def test_PUT(self):
resp = self.APP.put('/1/2')
assert 'Got 1, 2' in resp.data
if __name__ == '__main__':
unittest.main()
What I was thinking of doing was to move the initialization so that it only runs when flask_app is being executed by uwsgi and not when it's running via tests.py, perhaps by checking name and determining which path to execute based on that, but when I examine the output of print(name) either when running flask_app under uwsgi or by executing tests.py the output is "flask_app", so I can't seem to use that as a discriminator.
Is there an idiomatic way in python to handle this?
As it turns out the Python module for uWSGI actually offers a mechanism to determine if the app is being run under uWSGI. The uwsgi module is available for import if you are in a uWSGI context, so I ended up checking whether i could import that module and only executing the initialization code if I could.
# detect if we're running under uWSGI; only init if we are, not if we're testing
try:
import uwsgi
IN_UWSGI = True
except ImportError:
IN_UWSGI = False
Then wrap the init code with
if IN_UWSGI:
This seems much more reliable then checking the module name of the module that's doing the import, which was the only other thing I could think of to do.
I'm using WSGI/Apache2 and am trying to declare my database pool on init, to be accessible via a global var from my endpoints. I'm using Redis and Cassandra (DSE, specifically). It's my understanding that both the Redis and DSE libs offer pool management so this shouldn't be an issue.
My folder structure for my WSGI app looks something akin to
folder/
tp.wsgi
app/
__init__.py
decorators/
cooldec.py
mod_api/
controllers.py
tp.wsgi looks like the following
#! /usr/bin/env python2.7
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, "/opt/tp")
from app import app
def application(environ, start_response):
return app(environ, start_response)
__init__.py looks like the following
#! /usr/bin/env python2.7
from flask import Flask
from cassandra.cluster import Cluster
# Import our handlers
from app.mod_api.files import mod_files
# Setup routine
def setup():
# Instantiate Flask
app = Flask('app')
# Set up a connection to Cassandra
cassandraSession = Cluster(['an ip address', 'an ip address']).connect('keyspace')
cassandraSession.default_timeout = None
# Register our blueprints
app.register_blueprint(mod_files)
...
return app, cassandraSession
app, cassandraSession = setup()
I'm calling a decorator defined in cooldec.py that handles authentication (I use that term loosely, for a reason. I ask that we not go down the path of using Flask extensions for authentication, that's out of scope for this question and isn't applicable in my use-use [see: loose usage of the term 'authentication'])
In cooldec.py and controllers.py I'm trying to access the cassandraSession global but I keep getting global name 'cassandraSession' is not defined. I know what the error means, but I'm not sure why I'm seeing this. It's my understanding that the way I've set my WSGI app up allows for cassandraSession to be accessible within the scope of the app, no?
I found Preserving state in mod_wsgi Flask application but .. it hasn't really shed any light on to what I'm doing wrong.
My issue was the location of my imports. I made a few changes to tp.wsgi and __init__.py and I've got what I need working. That is, calling from app import cassandraSession from within cooldec.py and controllers.py
Below is how I've set up the aforementioned.
tp.wsgi
#! /usr/bin/env python2.7
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, "/opt/tp")
from app import app as application
__init__.py
#! /usr/bin/env python2.7
# API Module
from flask import Flask, jsonify
from cassandra.cluster import Cluster
# Create our API
app = Flask('app')
# Define a cassandra cluster/session we can use
cassandraSession = Cluster(['an ip address' 'an ip address']).connect('keyspace')
cassandraSession.default_timeout = None
... Register blueprints
These are overly simplified edits, but it gives the idea of what I was doing wrong (eg: declaring in wrong file and trying to import improperly.
In both cooldec.py and controllres.py we can now do
from app import cassandraSession
rows = cassandraSession.execute('select * from table')
Tip for new WSGI developers: Continue to think "in python".
+ WARNING +
I have yet to find an absolute answer on whether or not this is safe to do. Doing this using sqlalchemy is perfectly OK due to how sqlalchemy handles connection pooling. I am, as of yet, unaware if this is safe to do with Cassandra/DSE, so proceed with caution if you utilize this post.
I want to make a docstring for my router module in gae. I also know it must be the first thing in the module (after the file encoding type).
The thing is, if you run this module alone you get nothing but an import error (No module named webapp2). What I wanted is to print the docstring when running just the file but this import error just don't let me. Is there any way to do this?
I tried:
if __name__ == "__main__":
print help(self)
And other combinations, but no success.
[EDIT]
No specific code. Could be appengine's example:
# coding: utf-8
""" docstring """
import webapp2
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, webapp World!')
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
The ImportError happens when you run it as a standalone because it won't include any of the 'magic' that is included when run as an app. For instance, if you look at dev_appserver.py (just the basic one you use to run a dev server), you'll see this function:
def fix_sys_path(extra_extra_paths=()):
"""Fix the sys.path to include our extra paths."""
extra_paths = EXTRA_PATHS[:]
extra_paths.extend(extra_extra_paths)
sys.path = extra_paths + sys.path
Here you can see that sys.path is being modified to include some 'extra' paths, and if we take a look at one of them, you'll see webapp2 (as well as additional libraries provided in the SDK):
EXTRA_PATHS = [
# ...other similar setups...
os.path.join(DIR_PATH, 'lib', 'webapp2'),
# ...other similar setups...
]
You can see GAE is performing some additional steps behind the scenes to let you say import webapp2 without issue. Therefore when you try to run it on its own, you will get that error because your system is just checking the standard paths for webapp2 (which you likely don't have installed).
And that doesn't really answer your question at all :) As for that, I'm sure there are definitely more elegant/appropriate ways of handling this, but one thing you could try is wrapping your import(s) in a try/except block and on ImportError, checking if you're running the module directly. If so, call the module docstring and exit. Note this is just an example - you would want to make this more refined if you were to actually use it:
"""Module information."""
import sys
try:
import webapp2
except ImportError:
if __name__ == '__main__':
print __doc__
else:
print 'Webapp2 not found'
sys.exit(1)
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, webapp World!')
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
This will print Module information if you run it directly.
The Tumblelog app on the MongoDB site does not work .
I've followed the example absolutely and I get a 404 error when I run it in my local host. I'm using Eclipse Indigo (3.7.2) with pyDev on Ubuntu 12.0.4.
I'm not sure if it's because of the register_blueprints, which I included in the __init__.py
I did it like this as in the tutorial:
from flask import Flask
from flask.ext.mongoengine import MongoEngine
app = Flask(__name__)
app.config["MONGODB_DB"] = "my_tumble_log"
app.config["SECRET_KEY"] = "KeepThisS3cr3t"
db = MongoEngine(app)
if __name__ == '__main__':
app.run()
def register_blueprints(app):
# Prevents circular imports
from tumblelog.views import posts
app.register_blueprint(posts)
register_blueprints(app)
Otherwise I have followed the tutorial exactly.
register_blueprints is never called - app.run blocks until you kill the script (at which point there is no point to adding routes).
Change the order and everything will run:
def register_blueprints(app):
# Prevents circular imports
from tumblelog.views import posts
app.register_blueprint(posts)
register_blueprints(app)
if __name__ == '__main__':
app.run()
regist_blueprints is not actually preventing circular imports - the pattern to avoid circular imports is to create the app in a different file and import both app and blueprint into a third file to run everything:
# application.py
from flask import Flask # etc.
app = Flask("your_package_name")
# tumblelog/views.py
from flask import Blueprint, current_app # etc.
posts = Blueprint("tumblelog")
#posts.route("/")
def index():
# use current_app rather than app here
# run_server.py (use the same pattern for .wsgi files)
from application import app
from tumblelog.views import posts
app.register_blueprint(posts)
if __name__ == "__main__":
app.run()