Flask deprecated before_first_request How to update - python

I'm learning web developing for simple applications and I've created one that uses before_first_request decorator. According with the new release notes, the before_first_request is deprecated and will be removed from Flask 2.3:
Deprecated since version 2.2: Will be removed in Flask 2.3. Run setup
code when creating the application instead.
I don't understand how I can update my code to be complacent with flask 2.3 and still run a function at first request without using before_first_request. Could some kind soul give me an example ?

I don't know if this is answered but for anyone looking for the answer:
in place of the #app.before_first_request decorated function use the app instance like this:
i.e.
# In place of something like this
#app.before_first_request
def create_tables():
db.create_all()
...
# USE THIS INSTEAD
with app.app_context():
db.create_all()

Related

Hot reloading properties in a Python Flask/Django app

Gurus, Wizards, Geeks
I am tasked with providing Python Flask apps (more generally, webapps written in python) a way to reload properties on the fly.
Specifically, my team and I currently deploy python apps with a {env}.properties file that contains various environment specific configurations in a key value format (yaml for instance). Ideally, these properties are reloaded by the app when changed. Suppose a secondary application existed that updates the previously mentioned {env}.properties file, the application should ALSO be able to read and use new values.
Currently, we read the {env}.properties at startup and the values are accessed via functions stored in a context.py. I could write a function that could periodically update the variables. Before starting an endeavor like this, I thought I would consult the collective to see if someone else has solved this for Django or Flask projects (as it seems like a reasonable request for feature flags, etc).
One such pattern is the WSGI application factory pattern.
In short, you define a function that instantiates the application object. This pattern works with all WSGI-based frameworks.
The Flask docs explain application factories pretty well.
This allows you to define the application dynamically on-the-fly, without the need to redeploy or deploy many configurations of an application. You can change just about anything about the app this way, including configuration, routes, middlewares, and more.
A simple example of this would be something like:
def get_settings(env):
"""get the (current, updated) application settings"""
...
return settings
def create_app(env: str):
if env not in ('dev', 'staging', 'production'):
raise ValueError(f'{env} is not a valid environment')
app = Flask(__name__)
app.config.update(get_settings(env))
return app
Then, you could set FLASK_APP environment variable to something like "myapp:create_app('dev')" and that would do it. This is also the same way you could specify this for servers like gunicorn.
The get_settings function should be written to return the newest settings. It could even do something like retrieve settings from an external source like S3, a config service, or anything.

How do I replace a decorator at runtime?

I'm trying to adapt another StackOverflow answer on conditionally applying a decorator to only require login for a specific environment (eventually a staging environment, but development until I get this working). Toward that end, I started with the following
auth = HTTPDigestAuth()
def login_required(dec, condition):
def decorator(func):
if not condition:
return func
return dec(func)
return decorator
#bp.route('/auth')
#login_required(auth.login_required, current_app.config['ENV'] != 'development')
def auth_route():
return current_app.config['ENV']
When I launch the server, I get a RuntimeError: Working outside of application context error. After trying a few suggestions from an earlier version of this question, I got the RuntimeError to disappear, but the decorator still isn't being correctly applied when I want. Here's the current version:
def login_required(dec):
def decorator(func):
if not os.environ.get('ENV') != 'development':
return func
return dec(func)
return decorator
#bp.route('/auth')
#login_required(auth.login_required)
def auth_route():
return current_app.config['ENV']
This never returns the auth.login_reqired function. It always lets the browser in without authentication.
So, I tried changing the condition to
if not os.environ.get('ENV') is not None:
and then the authentication shows up.
Yes, I've done an export ENV=development in the shell and confirmed it with the env command. But even then it's not reading the environment variable as I would expect.
Perhaps this is simply the wrong way to go about it? My final goal is to require authentication on one particular environment. Is this possible with the path I'm on? Is it possible at all?
current_app is a context local proxy that only has meaning during a request. This means you can't use it before a request, i.e. as part of a decorator.
Using current_app is generally good practice because Flask allows multiple apps to be configured. In your specific case however, it isn't actually necessary. For instance, the following would work, because it uses the app object directly instead of the current_app proxy:
from yourpackage import app
#bp.route('/auth')
#login_required(auth.login_required, app.config['ENV'] != 'development')
def auth():
return current_app.config['ENV']
Let me paste something from documentation of Flask
Lifetime of the Context
The application context is created and destroyed as necessary. When a Flask application begins handling a request, it pushes an application context and a request context. When the request ends it pops the request context then the application context. Typically, an application context will have the same lifetime as a request.
Now let’s consider how decorators work. It is just a syntactic sugar see this answer.
So the login_required decorator is called while the module is loaded and the current app is not available yet because it’s not handling request.
I would do this way, move condition to the decorator function (relating to your example). It will be called while the request will be handled so you should have access to current_app.

How to run custom code at login with flask-security

I am new to flask, but moderately proficient in python - I have a flask app that uses flask-security for user authentication. I would like to add some additional functionality to the user login process. Specifically, I need to save the user's auth_token (which I have set up to be a one-time-use token) to the db when they login, and remove it when they log out. The issue comes because flask-security does not (to my knowledge) expose the machinery of logging in directly to the developer. As far as I can tell from the code, it imports flask-login, which uses a login_user function.
I started out by trying to override this function by importing flask.ext.login (which normally, I would not need to do) and redefining the function as follows:
import flask.ext.login as a
def new_login_user():
...copy of existing function goes here...
...Plus new stuff with current_user.get_auth_token()...
a.login_user = new_login_user
however, I got hit with all sorts of namespace issues, and it seems like a really ugly way to do it.
I was thinking there might be a way to do it with a decorator, but I am new to flask, and have not used decorators much regardless.
Any ideas on what the best way to approach this might be? for context, I want the auth_token in the db, because I need to pass off the website authentication to another process, which also accesses the db. The other process is an API server using websockets. I don't want to combine the processes.
I think using a signal decorator seems to be the easiest-- in the following example on_user_logged_in should be called when a user logs into your app. More info in the docs.
from flask.ext.login import user_logged_in
#user_logged_in.connect_via(app)
def on_user_logged_in(sender, user):
log_auth_token(user.get_auth_token()) # or whatever.
Best keep it clean, write your own new_login_user function and use that whenever you would otherwise use flask.ext.login.login_user. You could put your new_login_user into its own file and import it from there.
You could even call it login_user, and never import flask.ext.login.login_user directly.

WebApp needs to do something first time only, where to put that logic? Flask or django

The web app I am working on needs to perform a first-time setup or initialization,
where is a good place to put that logic? I dont want to perform the check if a configuration/setup exists on each request to / or before any request as thats kind of not performant.
I was thinking of performing a check if there is a sane configuration when the app starts up, then change the default route of / to a settings/setup page, and change it back. But thats like self-changing code a bit.
This is required since the web app needs settings and then to index stuff based on those settings which take a bit of time. So after the settings have been made, I still need to wait a while until the indexing is done. So even after the settings/setup has been made, any requests following, will need to see a "wait indexing" message.
Im using flask, but this is relevant for django as well I think.
EDIT: Im thinking like this now;
When starting up, check the appconfig.py for MY_SETTINGS, if it is not there
add a default from config.py and put a status=firstrun object on the app.config, also
change the / route to setup view function.
The setup view function will then check for the app.config.status object and perform
The setup of settings as necessary after user input, when the settings are okay,
remove app.config.status or change it to "indexing", then I can have a before_request function to check for the app.config.status just to flash a message of it.
Or I could use the flask.g instead of app.config to store the status?
The proper way is creating a CLI script, preferably via Flask-Script if you use Flask (in Django it would be the default manage.py where you can easily add custom commands, too) and defining a function such as init or install:
from flaskext.script import Manager
from ... import app
manager = Manager(app)
#manager.command
def init():
"""Initialize the application"""
# your code here
Then you mention it in your documentation and can easily assume that it has been run when the web application itself is accessed.

Stubs for local Django unittests with Google App Engine

I'd like to run local Django unit tests for a Google App Engine project. GAE recently received some python unit testing utilities that allow one to create stubs for e.g. memcache, the datastore, the task queue, etc.
I'd like to be able to use Django's unit testing framework. My first thought is to overload DjangoTestSuiteRunner to do the following for each test case:
# setUp
self.testbed = testbed.Testbed()
# Then activate the testbed, which prepares the service stubs for use.
self.testbed.activate()
# Next, declare which service stubs you want to use.
self.testbed.init_datastore_v3_stub()
self.testbed.init_memcache_stub()
# ... after tests:
#
# Teardown
self.testbed.deactivate()
I'd like to know if anyone else has tried to run Django's testing framework with the new unittests that can be run from the command line for GAE, and if so what pitfalls they've encountered. For example, are there any issues with calling Django's django.test.utils.setup_test_environment and teardown_test_environment? What other issues might come up?
Incidentally, I'm not using any Django-GAE helpers such as google-app-engine-django.
Thank you for reading.
Just wanted to mention: standard django unit testing worked very nice for me with django-nonrel and GAE Test Bed, including task-queues, memcache, etc. I think it is the same python unit testing code that you mentioned.

Categories

Resources