How do I add code to my pyramid app that is executed after the code in the view?
I need to do something to my beaker session before and after the view code. Before is no problem, I use a #subscriber(NewRequest). All the ways I tried so far seem to happen too late (values I write to the session do not seem to be saved, although code is executed, as I can see in the log).
I tried putting it in a #subscriber(BeforeRender), a #subscriber(NewResponse), and in a finished callback I add in the NewRequest: event.request.add_finished_callback(finished_callback) – None of the values I write to the session stick. Only the one I added as last line in the view handler does (but I will not write that line in all of my views).
The pyramid docs on NewResponse state:
Postprocessing a response is usually better handled in a WSGI middleware component than in subscriber code that is called by a pyramid.interfaces.INewResponse event. [...]
But I'm lost on that, since I don't know wsgi that well and trying to find a spot to enter via google did not point my anywhere.
Got my solution from the answer by #MikkoOhtamaa, but I wanted the code to be on this page, so here is what I did with some explanation:
This can be achieved with a tween. That is a function (or other callable), that is called instead of the view and gets the job of calling the view, so you can do stuff just before and after the call. Using this I got rid of the #subscriber(NewRequest) as well and put it all in one place. Imagine this in your projects main init.py, where you create the wsgi-app. The project's name would be myapp.
def values_tween_factory(handler, registry):
"""
Factory for creating the tween that wraps around the view.
"""
def values_tween(request):
"""
This is called in stead of the view with the view as param.
"""
# do stuff before view code with request and session
request.some_values = request.session.get('stored_values', [])
# execute the view, creates the response
response = handler(request)
# do stuff after the view code with request and session
request.session['stored_values'] = request.some_values
# return the response returned by the view
return response
# return the new tween
return state_tween
# [... other module level stuff ...]
def main(global_config, **settings):
"""
The main function creating the wsgi-app.
"""
config = Configurator(settings=settings)
# [...] other stuff, like DB
# register the tween - must be done by dotted name
config.add_tween('myapp.values_tween_factory')
# ... do more other stuff
application = config.make_wsgi_app()
# done - return created application object:
return application
Tweens (be-tween) allow you to execute code before and after each request.
Related
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')
I want to create a directive on a pyramid configurator that allows an application importing my library to add a view connected to a specific route with certain defaults.
My first attempt (modeled off of the examples given in the pyramid docs):
def status_view_directive(config, view, **view_config_kwargs):
def register_status_view():
config.add_view(
view=view,
route_name='status',
**view_config_kwargs
)
config.action('a_discriminator', register_status_view)
if __name__ == '__main__':
config = Configurator()
config.add_route('status', '/status')
config.add_directive('add_status_view', status_view_directive)
config.add_status_view('some_view', **some_kwargs)
return config.make_wsgi_app()
It doesn't work. Whenever I try to access the view I get a 404 back.
If I modify the code to the following, it works as expected:
def status_view_directive(config, view, **view_config_kwargs):
config.add_view(
view=view,
route_name='status',
**view_config_kwargs
)
if __name__ == '__main__':
config = Configurator()
config.add_route('status', '/status')
config.add_directive('add_status_view', status_view_directive)
config.add_status_view('some_view', **some_kwargs)
return config.make_wsgi_app()
I just lost a couple hours trying to figure this out. Does anyone know why the first snippet doesn't work?
This is what's happening:
A register_status_view action is registered when your directive is called.
When Pyramid executes actions, it executes this action.
However, this action calls a directive that itself registers an action. But action execution is not recursive. Actions that are registered as the result of an action execution are dropped on the floor.
We have some plans to resolve this in an upcoming Pyramid release. However, for now, you can probably just do this instead:
def status_view_directive(config, view, **view_config_kwargs):
config.add_view(
view=view,
route_name='status',
**view_config_kwargs
)
I'm looking for a way to have all requests going inside a function foo() before going into the routes.
That way I'll be able to read the request.environ before doing the real work.
I'm trying to do this so that I don't repeat code, but cannot find a way to do such a thing in BottlyPy...
My setup is: nginx -> uwsgi -> bottlepy.
That's what plugins are used for.
Here's an example:
import bottle
from bottle import request, response
def foo(callback):
def wrapper(*args, **kwargs):
# before view function execution
print(request.environ) # do whatever you want
body = callback(*args, **kwargs) # this line basically means "call the view normally"
# after view function execution
response.headers['X-Foo'] = 'Bar' # you don't need this, just an example
return body # another 'mandatory' line: return what the view returned (you can change it too)
return wrapper
bottle.install(foo)
My goal: In Pyramid, to call another view-callable, and to get a Response object back without knowing any details about that view-callable.
In my Pyramid application, say I have a view "foo" which is defined using a view_config decorator:
#view_config(route_name="foo",
renderer="foo.jinja2")
def foo_view(request):
return {"whereami" : "foo!"}
Now say that I want to route "bar" to a view that does the same thing for the time being, so it internally calls foo_view and returns its Response:
#view_config(route_name="bar")
def bar_view(request):
return foo_view(request)
...but wait! That doesn't work, since foo_view doesn't return a Response, its renderer does.
So, this will work:
#view_config(route_name="bar",
renderer="foo.jinja2")
def bar_view(request):
return foo_view(request)
as it will apply the same renderer as foo_view did. But this is bad, as I now must repeat myself by copying the renderer value AND having to know the renderer of the view being called.
So, I am going to hope that there is some function available in Pyramid that allows calling another view-callable and getting a Response object back without knowing or caring how it was rendered:
#view_config(route_name="bar")
def bar_view(request):
response = some_function_that_renders_a_view_callable(foo_view, request)
return response
What would some_function_that_renders_a_view_callable be?
pyramid.views.render_view appears to search for a view by name; I don't want to give my views names.
(Note: Returning HTTPFound to cause the client to redirect to the target route is what I am trying avoid. I want to "internally" redirect).
Yep. There is some concerns
doesn't return a Response
predicates/renderer
permissions
request properties associated to old request
Thats why you should not call view from view as function, unless you know what you doing
Pyramid creators did awesome tool for server side redirect - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html
You can invoking a view with using request.invoke_subrequest:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.request import Request
def view_one(request):
subreq = Request.blank('/view_two')
response = request.invoke_subrequest(subreq)
return response
def view_two(request):
request.response.body = 'This came from view_two'
return request.response
if __name__ == '__main__':
config = Configurator()
config.add_route('one', '/view_one')
config.add_route('two', '/view_two')
config.add_view(view_one, route_name='one')
config.add_view(view_two, route_name='two')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()`
When /view_one is visted in a browser, the text printed in the
browser pane will be "This came from view_two". The view_one view
used the pyramid.request.Request.invoke_subrequest() API to obtain a
response from another view (view_two) within the same application
when it executed. It did so by constructing a new request that had a
URL that it knew would match the view_two view registration, and
passed that new request along to
pyramid.request.Request.invoke_subrequest(). The view_two view
callable was invoked, and it returned a response. The view_one view
callable then simply returned the response it obtained from the
view_two view callable.
I was struggling with this as well. I have a solution using the render_to_response method, though I'm sure there's a "more correct" way to do it. Until someone posts it, however, here is how I handled this:
from pyramid.renderers import render_to_response
#view_config(route_name="foo", renderer="foo.mak")
def foo_view(request):
return {'stuff':'things', '_renderer':'foo.mak')
def bar_view(request):
values = foo_view(request)
renderer = values['_renderer']
return render_to_response(renderer,values)
(Pyramid 1.3)
This requires a renderer to be used, but by declaring that renderer in the original view's return values, you can retrieve it in another view without knowing what it is. I'm suspecting the need to do this isn't easily findable because there's other, better methods for accomplishing tasks solved by this solution.
Another shortcoming is that it relies on direct import of the view callable. It would be nice if it could be looked up directly by route.
The Pyramid documentation here indicates that leaving the name key word argument out of view_config will cause the view to be registered by the function itself (rather than a string):
Such a registration... implies that the view name will be *my_view*
So, in your case you should be able to use pyramid.view.render_view or pyramid.view.render_view_to_response referencing foo_view directly:
#view_config(route_name="bar")
def bar_view(request):
return pyramid.views.render_view_to_response(None, request, name=foo_view)
Update:
Yep, your right, passing the view function does not work.
It's interesting, but taking your example code and applying the route_name to the config
did not work for me. However, the following example, just giving the view a name sets the route url
and gives the view a name. In this fashion render_view_to_response works as advertised. Naming,
your views may not be what you want, but this configuration accomplishes the same thing as your
example code without added configuration.
#view_config(name="foo")
def foo_view(request):
# returning a response here, in lieu of having
# declared a renderer to delegate to...
return Response('Where am i? `{0[whereami]}'.format({"whereami" : "foo!"}))
#view_config(name="bar")
def bar_view(request):
# handles the response if bar_view has a renderer
return render_view_to_response(None, request, name='foo')
#view_config(name="baz")
def baz_view(request):
# presumably this would not work if foo_view was
# not returning a Response object directly, as it
# skips over the rendering part. I think you would
# have to declare a renderer on this view in that case.
return foo_view(request)
if __name__ == '__main__':
config = Configurator()
config.scan()
app = config.make_wsgi_app()
serve(app, host='127.0.0.1', port='5000')
Not the precise solution you asked for, but a solution to the problem you describe:
Create a view class, of which both foo and bar are methods. Then bar can call self.foo()
Common view_configuration, such as the template name can be applied to the class, and then you can decorate each method with just the view name.
In short, the following should meet your needs, if I understand the problem correctly.
#view_defaults(renderer="foo.jinja2")
class WhereaboutsAreFoo(object):
#view_config(route-name="foo")
def foo_view(self):
return {"whereami" : "foo!"}
#view_config(route-name="bar")
def bar_view(self):
return self.foo_view()
can't you do something like that:
#view_config(name="baz")
def baz_view(request):
return HTTPFound(location=self.request.route_path('foo'))
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.