Is there such thing as application-scope python variables in Flask? I'd like to implement some primitive messaging between users, and shared data cache. Of course, it is possible to implement this via a database, but I wanted to know maybe there is a db-free and perhaps faster approach. Ideally, if the shared variable would be a live python object, but my needs would be satisfied with strings and ints, too.
Edit: complemented with (non-working) example
from flask import g
#app.route('/store/<name>')
def view_hello(name=None):
g.name = name
return "Storing " + g.name
#app.route("/retrieve")
def view_listen():
n = g.name
return "Retrieved: " + n
At trying to retrieve g.name, this triggers error:
AttributeError: '_RequestGlobals' object has no attribute 'name'
I'm unsure whether this is a good idea or not, but I've been using this to share data easily between requests:
class MyServer(Flask):
def __init__(self, *args, **kwargs):
super(MyServer, self).__init__(*args, **kwargs)
#instanciate your variables here
self.messages = []
app = MyServer(__name__)
#app.route("/")
def foo():
app.messages.append("message")
Since flask 0.10 flask.g would be the way to go.
In earlier versions flask.g is stored in the request context and is cleared between requests. If you're using an older version you should store your app level stuff in flask.current_app
Related
I'm switching from Bottle to Tornado. On Bottle I can easily define paths that has multiple variable parts. Like this:
#app.get('/api/applications/<resource>/running_actions/<action_id>')
def get_application_running_action(resource, action_id):
# Return running action(<action_id>) of the application (<resource>)
On Tornado I would like to have something like this:
app = tornado.web.Application([
(r"/api", ApiRootHandler),
(r"/api/applications/(.*)", ApiApplicationHandler),
(r"/api/applications/(.*)/running_actions/(.*)", ApiRunningActionsHandler),
])
Then ApiRunningActionsHandler would search the application and running actions for the application. But on ApiRunningActionsHandler Get() there is only one path parameter. Is there any way to do this on Tornado or do I just need to parse the path again on ApiRunningActionsHandler? Which actually might not even be possible because I want to direct requests to /api/applications/(.*) to another handler.
I figured it out. Main problem was that my regex was catching everything. So
r"/api/applications/(.*)/running_actions/(.*)"
actually results only one group. Thus action_id argument wasn't set.
Second issue was that most descriptive path must be defined first.
This works:
class ApiRootHandler(tornado.web.RequestHandler):
def get(self):
pass
class ApiApplicationHandler(tornado.web.RequestHandler):
def get(self, action_name):
pass
class ApiRunningActionsHandler(tornado.web.RequestHandler):
def get(self, action_name, action_id):
self.write("action_name: " + action_name + ", action_id: " + action_id)
app = tornado.web.Application([
(r"/api/applications/(\w+)/running_actions/([0-9]+)", ApiRunningActionsHandler),
(r"/api/(\w+)", ApiApplicationHandler),
(r"/api/", ApiRootHandler),
])
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
Just make the second argument to ApiApplicationHandler.get optional:
class ApiApplicationHandler(RequestHandler):
def get(self, resource, action_id=None):
pass
I am trying to make a custom JWT_required decorator that passes the request.headers. So far everything I have tried gives me the following error:
RuntimeError: 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.
Here is my decorator:
def jwt_required(headers):
def jwt_req(func):
#functools.wraps(func)
def function_that_runs_func(*args, **kwargs):
print(headers)
func(*args, **kwargs)
return function_that_runs_func
return jwt_req
and here is how I am trying to utilize the decorator:
class Cert(Resource):
#jwt_required(request.headers)
def get(self):
I understand what the error is saying; however, I am not sure on how to get around it. I was hoping to make a copied dictionary to pass to the jwt decorator but that did not work as well.
Thanks for any help.
This was fixed by adding #jwt_required(request) and then finding the headers in the decorator by request.headers
I am trying to make a list of pages that a user has visited recently, but I keep getting TypeError: store_visited_urls() takes no arguments (1 given).
I don't know how an argument is given with it.
Python/Flask code:
app.secret_key = '/r/xd8}q/xde/x13/xe5F0/xe5/x8b/x96A64/xf2/xf8MK/xb1/xfdA7x8c'
def recentsites():
session['urls'] = []
#app.after_request
def store_visited_urls():
session['urls'].append(request.url)
if(len[session['urls']]) > 3:
session['urls'].pop(0)
session.modified = True
#app.route('/')
def index():
data = []
if 'urls' in session:
data = session['urls']
return render_template('index.html', data=data)
I think that as a function, it automatically includes self as an argument. This argument is included as part of the call when you create a class.
make the definition def store_visited_urls(self): but continue to call it without an argument.
From the way it looks session must be defined in the class. Thus, you would reference self.session so that it will be picked up when the class is instantiated.
See What is the purpose of self? for an explanation.
I see that you are using a decorator See Decorators I: Introduction to Python Decorators and A guide to Python's function decorators or Python Decorators or Primer on Python Decorators
I'm using Python Flask and I got defined the following function:
def verify_session():
if not 'logged_in' in session:
flash("You are not logged in.<br/>Please, log in to use our application.", "warning")
return redirect(url_for('login_path'))
This is meant to be called in every controller. I know that I could use #app.before_request but on some places I dont want this function to be called (in the same Login page, for example) and I really dont want the function to check the excluded paths.
My problem is this: inside any Flask controller for each of the paths the first lines look like this:
#app.route('/web/account', methods=["GET"], endpoint="account_path")
def account():
verify_session()
return render_template('account')
But, despite I get the "You need to login" flashed message, it still returns the Account page, because the return inside verify_session just returns for this function.
What I need is something like return verify_session() but that doesn't end the controller flow unless it actually is necessary to return it.
Maybe this problem is only Python/Programming specific rather than Flask so I excuse myself and ask moderators to edit my Question accordingly. I mention Flask because it's the enviroment where I'm having the trouble.
IF more information is needed I'm willing to update. Thank you in advance.
result = verify_session()
if not result:
result = render_template("account")
return result
but really you should be using a decorator for this
def verify_session(fn):
def inner(*args,**kwargs):
if not 'logged_in' in session:
flash("You are not logged in.<br/>Please, log in to use our application.", "warning")
return redirect(url_for('login_path'))
return fn(*args,**kwargs)
return inner
then you would use it like
#app.route('/web/account', methods=["GET"], endpoint="account_path")
#verify_session #make sure to use any decorators after the route decorator
def account():
return render_template('account')
lastly ... I hope you are aware that you are reinventing the wheel and you should probably just use flask-login to manage this stuff(unless you have a pretty compelling reason not to)
To add to Joran's excellent answer. Instead of using #app.before_request, you can put your login required routes in a blueprint and then use #blueprint.before_request:
account = Blueprint('account', __name__)
#account.before_request
def verify_session():
...
#account.route('/')
def index():
...
Then in your app:
app = Flask(__name__)
app.register_blueprint(account, url_prefix='/web/account')
Background
So let's say I'm making app for GAE, and I want to use API Hooks.
BIG EDIT: In the original version of this question, I described my use case, but some folks correctly pointed out that it was not really suited for API Hooks. Granted! Consider me helped. But now my issue is academic: I still don't know how to use hooks in practice, and I'd like to. I've rewritten my question to make it much more generic.
Code
So I make a model like this:
class Model(db.Model):
user = db.UserProperty(required=True)
def pre_put(self):
# Sets a value, raises an exception, whatever. Use your imagination
And then I create a db_hooks.py:
from google.appengine.api import apiproxy_stub_map
def patch_appengine():
def hook(service, call, request, response):
assert service == 'datastore_v3'
if call == 'Put':
for entity in request.entity_list():
entity.pre_put()
apiproxy_stub_map.apiproxy.GetPreCallHooks().Append('preput',
hook,
'datastore_v3')
Being TDD-addled, I'm making all this using GAEUnit, so in gaeunit.py, just above the main method, I add:
import db_hooks
db_hooks.patch_appengine()
And then I write a test that instantiates and puts a Model.
Question
While patch_appengine() is definitely being called, the hook never is. What am I missing? How do I make the pre_put function actually get called?
Hooks are a little low level for the task at hand. What you probably want is a custom property class. DerivedProperty, from aetycoon, is just the ticket.
Bear in mind, however, that the 'nickname' field of the user object is probably not what you want - per the docs, it's simply the user part of the email field if they're using a gmail account, otherwise it's their full email address. You probably want to let users set their own nicknames, instead.
The issue here is that within the context of the hook() function an entity is not an instance of db.Model as you are expecting.
In this context entity is the protocol buffer class confusingly referred to as entity (entity_pb). Think of it like a JSON representation of your real entity, all the data is there, and you could build a new instance from it, but there is no reference to your memory-resident instance that is waiting for it's callback.
Monkey patching all of the various put/delete methods is the best way to setup Model-level callbacks as far as I know†
Since there doesn't seem to be that many resources on how to do this safely with the newer async calls, here's a BaseModel that implements before_put, after_put, before_delete & after_delete hooks:
class HookedModel(db.Model):
def before_put(self):
logging.error("before put")
def after_put(self):
logging.error("after put")
def before_delete(self):
logging.error("before delete")
def after_delete(self):
logging.error("after delete")
def put(self):
return self.put_async().get_result()
def delete(self):
return self.delete_async().get_result()
def put_async(self):
return db.put_async(self)
def delete_async(self):
return db.delete_async(self)
Inherit your model-classes from HookedModel and override the before_xxx,after_xxx methods as required.
Place the following code somewhere that will get loaded globally in your applicaiton (like main.py if you use a pretty standard looking layout). This is the part that calls our hooks:
def normalize_entities(entities):
if not isinstance(entities, (list, tuple)):
entities = (entities,)
return [e for e in entities if hasattr(e, 'before_put')]
# monkeypatch put_async to call entity.before_put
db_put_async = db.put_async
def db_put_async_hooked(entities, **kwargs):
ents = normalize_entities(entities)
for entity in ents:
entity.before_put()
a = db_put_async(entities, **kwargs)
get_result = a.get_result
def get_result_with_callback():
for entity in ents:
entity.after_put()
return get_result()
a.get_result = get_result_with_callback
return a
db.put_async = db_put_async_hooked
# monkeypatch delete_async to call entity.before_delete
db_delete_async = db.delete_async
def db_delete_async_hooked(entities, **kwargs):
ents = normalize_entities(entities)
for entity in ents:
entity.before_delete()
a = db_delete_async(entities, **kwargs)
get_result = a.get_result
def get_result_with_callback():
for entity in ents:
entity.after_delete()
return get_result()
a.get_result = get_result_with_callback
return a
db.delete_async = db_delete_async_hooked
You can save or destroy your instances via model.put() or any of the db.put(), db.put_async() etc, methods and get the desired effect.
†would love to know if there is an even better solution!?
I don't think that Hooks are really going to solve this problem. The Hooks will only run in the context of your AppEngine application, but the user can change their nickname outside of your application using Google Account settings. If they do that, it won't trigger any logic implement in your hooks.
I think that the real solution to your problem is for your application to manage its own nickname that is independent of the one exposed by the Users entity.