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
Related
I have a flask application, in one of its script commands I want to know what's the args passed to the Manager (not the command itself), how can I do that?
$ cat manage.py
#!/usr/bin/env python
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
manager.add_option("-d", "--debug", dest="debug", action="store_true")
#manager.option('-n', '--name', dest='name', default='joe')
def hello(name):
# how can I know whether "-d|--debug" is passed in command line
print("hello", name)
if __name__ == "__main__":
manager.run()
If I run:
$ python manage.py --debug hello
I want to detect whether '--debug' is passed via command line args within the func of hello. I can't just change
manager.add_option("-d", "--debug", dest="debug", action="store_true")
to the decorator verion of:
#manager.option('-d', '--debug', action='store_true', dest='debug')
#manager.option('-n', '--name', dest='name', default='joe')
def hello(name, debug=False):
because '-d|--debug' is shared by many commands.
Global options are passed not to command, but to app-creating function.
See add-option docs.
For this to work, the manager must be initialized with a factory function rather than a Flask instance. Otherwise any options you set will be ignored.
So you need to do something like
app = Flask(__name__)
def init_manager(debug):
app.debug = debug
return app
manager = Manager(init_manager)
And then access app.debug
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()
I am using Flask to build a tool to view data locally in a browser. I want to pass the directory containing the data as a command line argument, and then pass it to the appropriate routing function to do the rendering.
This does what I want, but with global variables:
dataDir = None
def initializeData(pathname):
global dataDir
dataDir = pathname
#app.route('/')
def home():
# Use dataDir as desired
if __name__ == '__main__':
initializeData(sys.argv[1])
app = Flask(__name__)
app.run()
Is there a better way to communicate between the command line and my routes?
Your flask app has a config property. Also, this code will fail with a NameError. You want something like this:
import sys
from flask import Flask
app = Flask(__name__)
#app.route('/')
def home():
return 'You wanted {!r} directory'.format(app.config.get('some_setting'))
if __name__ == '__main__':
app.config['some_setting'] = sys.argv[1]
app.run()
Consider using app.config.from_json('config.json') so that you can configure your env parameters in a json file.
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. :-)
I am trying to break my app into separate scripts. Part of this effort meant breaking the api calls into it's own file. However the calls to the api (like http://example.com/api/game/new no longer work).
My app.yaml contains this:
- url: /api.*
script: api.py
which seems to be redirecting properly because this configuration works:
def main():
application = webapp.WSGIApplication([('/.*', TestPage)], debug=True)
util.run_wsgi_app(application)
however this one doesn't:
def main():
application = webapp.WSGIApplication([('/game/new$', CreateGame),
('/game/(d+)$', GameHandler)],
debug=True)
util.run_wsgi_app(application)
The URL patterns you use in the WSGI application have to be the full path - eg, /api/game/.... The App Engine infrastructure uses the regular expressions in app.yaml to route requests, but it does not modify the request path based on them.
My guess is you are trying to pass some arguments to your handler.
Try this. It will give you a hint.
#!/usr/bin/env python
import wsgiref.handlers
from google.appengine.ext import webapp
class MyHandler(webapp.RequestHandler):
def get(self, string=None):
if string:
self.response.out.write("Hello World!! %s" % string)
else:
self.response.out.write("Hello World!! (and no word)")
def main():
app = webapp.WSGIApplication([
(r'/word/(\w+)/?$', MyHandler),
(r'.*', MyHandler),
], debug=True)
wsgiref.handlers.CGIHandler().run(app)
if __name__ == "__main__":
main()
Hope it helps. Cheers.