Set a variable before importing module __init.py__ - python

My Python application structure is thus:
run.py
app/__init.py__
app/config.py
app/<other modules in app>
In my app/__init.py, I'd like to check a variable DEBUG_MODE and depending on its value, start a python Logger if DEBUG_MODE == False, and simply print to console if it is True. My currently attempted (and not working) solution is to have three files:
app/config.py
DEBUG_MODE = False
app/__init__.py
app = MyApp()
from config import DEBUG_MODE
app.debug = DEBUG_MODE
if not app.debug:
import logging
...
run.py
from app import config
config.DEBUG_MODE = True
from app import app
The problem, of course, is that by the time my code reaches config.DEBUG_MODE=True, the app module's init code has already been called because my config file is part of the app module.
How can I tell the module that I want to enable debugging at run time from my run.py script?

The cause of this problem is config.py being part of the app module and namespace - any reference to it and its variables requires the app/__init__.py to be evaluated first.
One way around it is to hijack the Python __builtin__ "module", which is available to all Python modules, and add our own variable:
run.py
import __builtin__
__builtin__.myapp_debug = True
from app import app
And then in the module __init__.py:
# app is instantiated as an Object
import __builtin__
if hasattr(__builtin__, "myapp_debug"):
app.debug = __builtin__.myapp_debug
else:
app.debug = False
# If debugging is off, use file-based logging:
if not app.debug:
print "Setting up logging..."
import logging
...

Related

ModuleNotFoundError using Flask

I'm trying to make a Flask api :
app.py
routes
-> __init__.py
-> myobject.py
# app.py
from flask import Flask
from flask_restful import Api
from routes import MyObject
app = Flask(__name__)
api = Api(app)
api.add_resource(MyObject, '/')
if __name__ == '__main__':
app.run()
# __init__.py
from myobject import MyObject
# myobject.py
from flask_restful import Resource
class MyObject(Resource):
def get(self):
return {'hello': 'world'}
When I run my application (python app.py), I get a ModuleNotFoundError: No module named 'myobject'
I don't understand why python can't find my module myobject. Is there something i'm missing in my __init__.py
For __init__.py, it also needs the relative import or absolute import path in order to work correctly.
# __init__.py
# relative import
from .myobject import MyObject
# absolute import
from routes.myobject import MyObject
In another approach, you can write to import MyObject more specifically like this and leave __init__.py an empty file.
# app.py
# ...
from routes.myobject import MyObject
# ...
I believe the problem is due to your app running in the "main" directory and your import residing in a sub directory. Basically your app thinks you are trying to import "/main/myobject.py" instead of "/main/routes/myobject.py"
Change your import in __init__ to from .myobject import MyObject
The . means "this directory" (essentially).

Unit testing Flask app running under uwsgi

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.

Flask, WSGI, and Global Variables to Hold Database Pool

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.

Configurator Scan not picking up views

New to Py and Python. I'm trying to get pyramid Configurator scan to find my views, but I seem to be missing something, it's not picking up my "view" index here are my files:
app.py
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
if __name__ == '__main__':
config = Configurator()
config.add_route('home', '/')
config.scan()
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 6543, app)
server.serve_forever()
and index.py
from pyramid.view import view_config
from pyramid.response import Response
#view_config(route_name='home')
def index(request):
print'Incoming request'
return Response('<body><h1>Home</h1></body>')
Its returning a 404. However, if I remove config.scan() and add the view manually it works fine.
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from index import index
if __name__ == '__main__':
config = Configurator()
config.add_route('home', '/')
config.add_view(index, route_name='home')
From Pyramid documentation
scan(package=None, categories=None, onerror=None, ignore=None, **kw)[source]
Scan a Python package and any of its subpackages for objects marked with configuration decoration such as pyramid.view.view_config. Any decorated object found will influence the current configuration state.
The package argument should be a Python package or module object (or a dotted Python name which refers to such a package or module). If package is None, the package of the caller is used. In this case it is looking for decorations in app package or app.py file.
To fix this add
config.scan(package='index')
or rename app.py to __init__.py

Tumblelog Application with Flask and MongoEngine example does not work - Complete Novice

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()

Categories