Flask-Script How to get to the current app? - python

I'm trying to get access to the current app instance from a Flask-Script manager.command.
This errors out (url_map is a property of flask.app)
#manager.command
def my_function():
x = app.url_map # this fails, because app is a callable
print "hi"
This works, but I don't like having to add parens next to app.
#manager.command
def my_function():
x = app().url_map
print "hi"
The debugger shows that app is a callable. That has to do with the way that I'm creating the app instance. I'm following this pattern:
def create_app(settings=None, app_name=None, blueprints=None):
...lots of stuff...
app = flask.Flask(app_name)
...lots of stuff...
return app
def create_manager(app):
manager = Manager(app)
#manager.command
def my_function():
x = app.url_map
print "hi"
def main():
manager = create_manager(create_app)
manager.run()
if __name__ == "__main__":
main()
The docs from flask-script say about the app parameters on Manager(app):
app – Flask instance, or callable returning a Flask instance.
I'm comfortable with putting a callable in there because the docs say it's OK. :-) Plus I've seen others do it like that.
But now I have this peripheral command that I'd like to add and it's forcing me to use the app with parens and that smells wrong. What am I doing wrong?
EDIT: I did some experiments. This is definitely wrong. By adding the parens, the app instance is getting recreated a second time.

Use flask.current_app
This works:
import flask
... other stuff ...
#manager.command
def my_function():
x = flask.current_app.url_map
print "hi"
I 'overthunk' it. :-)

Related

how to run the code before the app.run() in flask?

I'm new on flask.I configured a server with flask+gunicorn.
the code file called test.py like this:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def test():
return aa+"world!"
if __name__ == '__main__':
aa = "hello"
app.run()
run it using:gunicorn -b 0.0.0.0:8080 test:app
I got a mistake:NameError: name 'aa' is not defined.
I want some codes like variable aa runing before gunicorn.
How to do that?
Put in a small block just before your #app.route and you dont need the last block in the question
#app.before_first_request
def _declareStuff():
global aa
aa='hello'
Just declare aa outside of "__main__", in the global scope of the file.
from flask import Flask
app = Flask(__name__)
#app.route('/')
def test():
return aa+"world!"
aa = "hello"
if __name__ == '__main__':
app.run()
The code in the if __name__ == '__main__': block executes only if the Python code is run as a script, e.g., from the command line. Gunicorn imports the file, so in that case the code in __main__ will not be executed.
Note that if it is your intention to modify the value of aa then different requests can produce different results depending on how many requests each gunicorn worker process has handled. e.g.:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def test():
global counter
counter += 1
return "{} world! {}".format('aa', counter)
counter = 0
if __name__ == '__main__':
app.run()
Run the above script with more than one worker (gunicorn -w 2 ...) and make several requests to the URL. You should see that the counter is not always contiguous.
As of Flask 2.2, the #app.before_first_request decorator suggested by Vipluv in their answer is deprecated and will be removed in 2.3.
Deprecated since version 2.2: Will be removed in Flask 2.3. Run setup code when creating the application instead.
The equivalent can be done by manually pushing the app context, as suggested by Enkum :
# 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()

How does flask know which function to call for a specific web adress?

In the populair web framework flask a basic web page looks like this:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
I am pretty new to python and i was wondering how this exactly works. I get that # is a decorator that decorates the hello function but how does flask that is has to call the underlying hello funtion or even knows it exists, because the code does not run the hello function like this:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
hello()
When i am coding i like to know how something works before i just randomly accept anything. I searched my but off looking for an answer but could not find a pleasent answer. Also i looked in the source code but i was not able to find out how it works
So now the real question: How can i recreate something similair in plain python? So running a function without really calling it in the main code first.
Ps. Sorry for my bad english, it is not my main language.
app.route() remembers the URL ("/") and the function associated with it (hello). Later, app.run() can query that association and invoke hello.
How can i recreate something similair in plain python?
This program might give you an understanding of how hello() is invoked:
class Flask:
def __init__(self):
self.routes = {}
def route(self, path):
def wrapper(fn):
self.routes[path] = fn
return fn
return wrapper
def run(self):
# Networking code goes here.
# Suppose "/" comes in as a request, then this happens:
self.routes["/"]()
app = Flask()
#app.route("/")
def hello():
print("Inside hello")
return "Hello World!"
app.run()
Alternatively, you can examine the flask source: https://github.com/pallets/flask Specifically, app.route() is defined here: https://github.com/pallets/flask/blob/0.12.2/flask/app.py#L1054 and the call to hello() is here: https://github.com/pallets/flask/blob/0.12.2/flask/app.py#L1052

How to pass an arbitrary argument to Flask through app.run()?

I would like to pass an object to a newly initiated flask app. I tried following the solution from the question: how-can-i-make-command-line-arguments-visible-to-flask-routes
Edit
I would like to take a value that I pick up from initiating the python script from the command line.
ie.
$ run python flaskTest.py -a goo
I am not seeing the difference between this and the solution to the question I am trying to replicate.
Edit
Thus, I tried the following:
from flask import Flask
app = Flask(__name__)
print('Passed item: ', app.config.get('foo'))
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-a')
args = parser.parse_args()
val = args.a
app.config['foo'] = val
app.run()
Hoping to get the result...
'Passed item: Goo'
Is there a method for passing an arbitrary object through the initialization with app.run()?
Well the script is executing from top to bottom, so you can't print something you don't have yet. Putting the print statement inside a classic flask factory function allow you to first parse command line, then get your object and then use it:
from flask import Flask
def create_app(foo):
app = Flask(__name__)
app.config['foo'] = foo
print('Passed item: ', app.config['foo'])
return app
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-a')
args = parser.parse_args()
foo = args.a
app = create_app(foo)
app.run()
So, the problem is that you're trying to access the value before you define it. You would need to do something like this in your case:
from flask import Flask
app = Flask(__name__)
app.config['foo'] = 'Goo'
print('Passed item: ', app.config['foo'])
if __name__ == '__main__':
app.run()
If you're trying to access that value while loading some third module, you'll need to define the value somewhere ahead of time.
An update for more recent versions of Flask: when running through flask run you can now invoke an app factory and even pass arguments (docs).
Example code:
from flask import Flask
def create_app(foo=None):
app = Flask(__name__)
app.config["foo"] = foo
return app
# if __name__ == "__main__": ... not necessary
Assuming it is saved as flaskTest.py, you can run it using:
export FLASK_APP="flaskTest:create_app('value of foo')"
flask run

Is it possible to use the "app factory" pattern from Flask with Click CLI applications?

Imagine I have a big CLI application with many different commands (think, for example image-magick).
I wanted to organize this application into modules and etc. So, there would be a master click.group somewhere:
#main.py file
#click.group()
def my_app():
pass
if __name__ == "__main__":
my_app()
that can be imported in each module that define a command:
from main import my_app
# command_x.py
#my_app.command()
def command_x():
pass
The problem is that I run into a circular import problem, since the main.py file knows nothing about command_x.py and I would have to import it before calling the main section.
This happens in Flask too and is usually dealt with the app factory pattern. Usually you would have the app being created before the views:
app = Flask("my_app")
#my_app.route("/")
def view_x():
pass
if __name__ == "__main__":
app.run()
In the app factory pattern you postpone the "registration" of the blueprints:
# blueprints.py
blueprint = Blueprint(yaddayadda)
#blueprint.route("/")
def view_x():
pass
And make a factory that knows how to build the app and register the blueprints:
#app_factory.py
from blueprints import view_x
def create_app():
app = Flask()
view_x.init_app(app)
return app
And you can then create a script to run the app:
#main.py
from app_factory import create_app
if __name__ == "__main__":
app = create_app()
app.run()
Can a similar pattern be used with Click? Could I just create a "click app" (maybe extending click.Group) where I register the "controllers" which are the individual commands?
Maybe late, but I was also searching for a solution to put commands to separate modules. Simply use a decorator to inject commands from modules:
#main.py file
import click
import commands
def lazyloader(f):
# f is an instance of click.Group
f.add_command(commands.my_command)
return f
#lazyloader
#click.group()
def my_app():
pass
if __name__ == "__main__":
my_app()
The separated command can use the usual decorators from click.
#commands.py
import click
#click.command()
def my_command():
pass
Ok, so I thought a little and it seems that the following could work. It's probably not a final solution but it seems to be an initial step.
I can extend the MultiCommand class:
# my_click_classes.py
import click
class ClickApp(click.MultiCommand):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.commands = {}
def add_command(self, command_name, command):
self.commands.update({command_name: command})
def list_commands(self, ctx):
return [name for name, _ in self.commands.items()]
def get_command(self, ctx, name):
return self.commands.get(name)
And the Command class:
class MyCommand(click.Command):
def init_app(self, app):
return app.add_command(self.name, self)
def mycommand(*args, **kwargs):
return click.command(cls=MyCommand)
This allows you to have the commands defined in separated modules:
# commands.py
from my_click_classes import command
#command
def run():
print("run!!!")
#command
def walk():
print("walk...")
and the "app" in a separated module:
from my_click_classes import ClickApp
from commands import run, walk
app = ClickApp()
run.init_app(app)
walk.init_app(app)
if __name__ == '__main__':
app()
Or even use the "app factory" pattern.
It maybe not a definitive solution though. If you guys can see any way to improve it, please let me know.

Flask destructor

I'm building a web application using Flask. I've sub-classed the Flask object so that I can execute a chunk of code before the app exits (the Flask object get's destroyed). When I run this in my terminal and hit ^C, I'm not seeing the "Can you hear me?" message, so I assume that __del__() isn't getting called.
from flask import Flask
class MyFlask (Flask):
def __init__(self, import_name, static_path=None, static_url_path=None,
static_folder='static', template_folder='templates',
instance_path=None, instance_relative_config=False):
Flask.__init__(self, import_name, static_path, static_url_path,
static_folder, template_folder,
instance_path, instance_relative_config)
# Do some stuff ...
def __del__(self):
# Do some stuff ...
print 'Can you hear me?'
app = MyFlask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
I'd like this code to execute in the destructor so that it'll run no matter how the application is loaded. i.e, app.run() in testing, gunicorn hello.py in production. Thanks!
Maybe this is possible:
if __name__ == '__main__':
init_db() #or what you need
try:
app.run(host="0.0.0.0")
finally:
# your "destruction" code
print 'Can you hear me?'
I have, however, no clue if you can still use app in the finally block ...
It is not guaranteed that __del__() methods are called for objects that still exist when the interpreter exits. Also, __del__() methods may not have access to global variables, since those may already have been deleted. Relying on destructors in Python is a bad idea.

Categories