Flask with SQLAlchemy working outside of application context - flask

I have a Flask app and I use SQLAlachemy(without Flask extension cause I need to create my own class based SQLAlchemy and so on).
My app has a connection to its database over engine and it works fine but now I need to make my engine dynamically and get db_name from Flask.g
Engine is declared in models.py
models.py
engine = create_engine(f"postgresql://postgres:postgres#localhost:5434/{g['tenant']}", convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
For the start app I use wsgi.py:
from app import app
if __name__ == "__main__":
app.run(port=5002)
when I type python wsgi.py I receive an error.
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
In general I understand that I use an engine which is outside the context. The issue is - I cannot figure out how to pass my engine variable to context.
I try to make create app func:
def create_app():
app = Flask(__name__)
with app.app_context():
engine = create_engine(f"postgresql://postgres:postgres#localhost:5434/{g['tenant']}", convert_unicode=True)
return app
Also I tried app.app_context().push(engine)
But it doesn't work. How I can solve this issue?

The problem is that the flask object g only ever exists when a request is currently in progress on flask. (Without a request, there is no flask g, because g is specifically a global for individual requests)
what you'd have to do is to create that engine after the request starts, which slows down the route a bit. The #app.before_request decorator might help you here:
#app.before_request
def create_engine_for_request():
engine = create_engine(f"postgresql://postgres:postgres#localhost:5434/{g['tenant']}", convert_unicode=True)
("before_request" is already "during a request" - its just the first thing that flask does "when a request starts")

Related

How do I access Flask Session inside a slack_bolt handler?

I have a Slack App that handles commands and actions, that follows the documented way of handling requests using a SlackRequestHandler for flask. However, I would like to use the flask session inside the slack_bolt function, and understandably it won't let me because it has no access to the request at that point in the code, and sessions don't exist without a request. However, I should be able to access the flask session somehow, given that the slack_bolt function is called by the SlackRequestHandler inside the flask view, which does have a request context. My question is, how can I access the session within the slack_bolt handler below?
from flask import Flask, request, Response, session
from flask_session import Session
import slack
from slackeventsapi import SlackEventAdapter
from slack_bolt import App
from slack_bolt.adapter.flask import SlackRequestHandler
flask_app = Flask(__name__)
SESSION_TYPE = "filesystem"
flask_app.config.from_object(__name__)
Session(flask_app)
bolt_app = App(token=os.environ['SLACK_TOKEN'], signing_secret=os.environ['SIGNING_SECRET'])
handler = SlackRequestHandler(bolt_app)
#flask_app.route('/route1', methods=['POST'])
def route1():
return handler.handle(request)
session['test] = 'value1' # This works fine
#bolt_app.command('/route1')
def handle_route1(body, ack, respond, client, logger):
ack()
session['test'] = 'value2' # This is what I am trying to do without success
The error I get is:
Failed to run listener function (error: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.)
I tried using:
with app.request_context(####):
session['test']= 'value2'
But I don't know how to get the context object to pass to request_context, or even if this is the right thing to do. Thank you very much for any help!

Setting Flask app instance to configuration

I'm using blueprints with an application factory, so I cannot import the app instance. Do you guys see anything wrong with setting app to your config?
def create_app():
app = Flask(__name__)
app.config['app'] = app
with app.app_context():
configure_app(app)
configure_blueprints(app)
...
Now app can be accessed from a different module via current_app.config['app']
app = current_app.config['app']
with app.app_context():
...
Here it is in a real example:
from flask import current_app
def send_async_email(current_app, msg):
with current_app.app_context():
mail.send(msg)
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
Thread(target=send_async_email,
args=(current_app.config['app'], msg)).start()
Using current_app alone in the Thread arguments, I get an error saying I'm working outside of the application context. Using current_app.config['app'] does work, I just want to know if there is a different way, or if there is anything wrong with doing it this way?
That's because current_app is just a proxy to the thread local app. This should solve it:
app= current_app._get_current_object()
This hands you back the original app object. Your config example worked because it also uses the original app not the proxy.
Now you can pass it on the your new thread as such:
Thread(target=send_async_email, args=(app, msg)).start()
That being said, it's a bad idea setting your app as an item of your app.config as it's recursive.

Flask-Restful powered API returning 404 errors

I used Flask-Restful in a project where i also use the Factory pattern to create Flask objects. The problem now is that Flask give me 404 error when i try to reach http://localhost:5000/api/v1/user/ but when i explore (via the debugger) the Flask app object's url_map, my API rule is there. So, if someone ever had the same issue, i'm taking whatever possible solution.
I have the following function creating the API app:
def create_app(settings_override=None):
"""
Returns the API :class:`Flask` instance.
:param settings_override: dictionary of settings to override.
"""
app = factory.create_app(__name__, __path__, settings_override)
api = Api(app, prefix='/api/v1', catch_all_404s=True)
# API endpoints connected to the User model.
api.add_resource(UserAPI, '/user/', endpoint='user')
return app
The code of UserAPI class (used by Flask-Restful):
class UserAPI(Resource):
"""
API :class:`Resource` for returning the details of a user.
This endpoint can be used to verify a user login credentials.
"""
def get(self):
return {'hello': 'world'}, 200
def post(self):
pass
The factory.create_app function:
def create_app(package_name, package_path, settings_override=None):
"""
Returns an instance of Flask configured with common functionnalities for
Cubbyhole.
:param package_name: application package name
:param package_path: application package path
:param settings_override: a dictionnary of settings to override
"""
app = Flask(package_name, instance_relative_config=True)
app.config.from_object('cubbyhole.settings')
app.config.from_pyfile('settings.cfg', silent=True)
if settings_override is not None:
app.config.update(settings_override)
db.init_app(app)
register_blueprints(app, package_name, package_path)
return app
Python version 2.7
Flask v.
Flask-Restful version
After some investigations and some questions on Flask's IRC channel, i found that when using custom domain name, the port number should be set via the SERVER_NAME config variable. So, the issue was not coming from the factory code.
If you want to access the server via http://myserver.io:5000/, you set the port, here 5000, in SERVER_NAME as SERVER_NAME = myserver.io:5000.
This single modification in my settings worked for me :) Thanks !

Unique field in pymongo

What is the simplest way to avoid field collisions working with pymongo? I have a very simple structure for a Location class (name, slug, description and geolocation) and I would like to ensure that no duplicate names are allowed. I am using flask and pymongo?
I was trying this:
from flask import Flask
from flask.ext.pymongo import PyMongo
app = Flask(__name__)
mongo = PyMongo(app)
mongo.db.court.ensureIndex( { "name": 1, "slug": 1 } )
but it gives me an error: RuntimeError: working outside of application context.
use unique indexes and you'll have no two documents that have same values for a field. this doesn't have to be flask-specific, but it is rather mongodb-specific.
if you're lazy or indexes give you headache, just use _id field as the location name. in this case you have to make sure your documents don't get overwritten.
The best place to put your calls to ensure_index is someplace before you call run() on your flask app. You want to make sure your indexes are in place before you attempt to service any requests, because building the index while the site is live will make it pretty unresponsive. The error you are getting is because you need the application context. Try:
app = Flask(__name__)
mongo = PyMongo(app)
if __name__ == '__main__':
with app.app_context():
mongo.db.court.ensure_index( [("name", ASCENDING), ("slug", ASCENDING)], unique=True )
app.run()
As #thkang said, you should use a unique index to enforce that no two documents have the same value for a field or set of fields taken together. See more about this and pymongo's ensure_index syntax at the pymongo docs.
ensure_index has been deprecated. Use create_index instead.
from flask import Flask
from flask_pymongo import PyMongo
import pymongo
app = Flask(__name__)
mongo = PyMongo(app)
with app.app_context():
mongo.db.court.create_index([("name", pymongo.ASCENDING), ("slug", pymongo.ASCENDING)], unique=True)

Django + Selenium test hangs - deadlock?

I've been working in a Django project for a while and am starting on a new app, trying to do more automated testing with Selenium at the same time. I'm using http://www.tdd-django-tutorial.com/ as a guide.
I'm trying to test the ability to log in to my application. My test can pull up the page and fill in text fields without trouble, but when it clicks on the submit button, it hangs - Firefox keeps trying to load the new page but it never happens. It looks like deadlock to me, but I don't understand it well enough to know what's going on.
Other details: I'm using Django's built-in login view. I have another test that successfully logs in to the admin site. I can log in to my application just fine when I test manually. The application accesses a remote MySQL database.
Here's my test:
from django.test import TestCase, LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys
class BucloudTest(LiveServerTestCase):
"""Tests shared functionality (login, network and app selection)."""
fixtures = ['24aug2012_dev_auth.json']
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(5)
def tearDown(self):
self.browser.quit()
def test_good_login(self):
"""Tests that a user can log in using valid credentials."""
self.browser.get(self.live_server_url + "/login/")
user_css = "[placeholder=Username]"
user_field = self.browser.find_element_by_css_selector(user_css)
user_field.send_keys("test_user1")
pw_css = "[placeholder=Password]"
pw_field = self.browser.find_element_by_css_selector(pw_css)
pw_field.send_keys("test")
button = self.browser.find_element_by_css_selector("[value='Sign in']")
button.click()
WebDriverWait(self.browser, 30).until(
lambda driver: driver.find_element_by_tag_name('body'))
body = self.browser.find_element_by_tag_name("body")
self.assertIn("Properties", body.text)
print "ran tests YAY!!"
I run the test with manage.py test functests --liveserver=localhost:8080-8090.
Thanks very much for any suggestions!
It might be due to the fact that the content of your test_good_login() function is not indented