alex conrad - pyramid tweens (ploneconf 2011)
DESCRIPTION
understanding Pyramid TweensTRANSCRIPT
Alex Conrad@alexconrad
Code Monkeyat SurveyMonkey
PloneConf 2011Nov 5, 2011
Tweens
What are Pyramid Tweens?
omg tweens r soooo, like, totally awesome!!!!!!1! lol
(totally friend me on twtr)
^^
They are NOTpre-teenager girls
(too old for toys, too young for boys)
Pyramid Tweens were namedafter the word “between”
Pyramid Tweensare middlewares
Pyramid Tweens live betweenPyramid code and your application views
Pyramid Tweens are NOTWSGI middlewares
REQUEST
REQUEST
So why use Tweens?
To apply a common behavioron all requests
Think of them as decoratorsapplied to each of your Pyramid views.
@foo@bardef useless_view(request): return {}
@foo@bardef useless_view(request): return {}
These are notTweens, but actualdecorators, ok?
Tweens can be stacked together
Pyramid Tweensvs.
WSGI Middlewares
WSGI middleware Tweens
Pipelining YES YES
Error catching YES YES
WSGI compliant YES NO
Access to application
(registry, template engine, ...)
NO YES
How does it work?
Create a tween factory: a function
A tween factory takes 2 arguments:
- handler- registry
A tween factory returns a function:a tween
(just like a decorator does)
The tween function takes 1 argument:- request
(just like a view would)
The tween function returns a response object
(just like a view would)
A tween factory is calledat application startup
A tween is calledper request
The tween factory decidesif the tween should be part of the tween stack
def useless_tween_factory(handler, registry): if registry.settings['useless'] == '1': def useless_tween(request): response = handler(request) return response return useless_tween return handler
handler: the next tween in the stackregistry: the pyramid registry
def useless_tween_factory(handler, registry): if registry.settings['useless'] == '1': def useless_tween(request): response = handler(request) return response return useless_tween return handler
handler: the next tween in the stackregistry: the pyramid registry
this is a tween
Tween positioning
REQUEST
REQUEST
REQUEST
---------------------- INGRESS ----------------------
------------------------ MAIN ------------------------
REQUEST
3 ways of positioning tweens
- implicit- implicit (hint)
- explicit
3 ways of positioning tweens
- implicit- implicit (hint)
- explicit
Implicit positioning
from pyramid.config import Configurator
# ... more imports
def main(global_config, **settings):
config = Configurator(...)
config.add_tween('useless.useless_tween_factory')
config.add_tween('useless.null_tween_factory')
# ... more stuff
return config.make_wsgi_app()
REQUEST
Implicit positioning
from pyramid.config import Configurator
# ... more imports
def main(global_config, **settings):
config = Configurator(...)
config.add_tween('useless.useless_tween_factory')
config.add_tween('useless.null_tween_factory')
# ... more stuff
return config.make_wsgi_app()
INGRESSuseless.null_tween_factory
useless.useless_tween_factorypyramid.tweens.excview_tween_factory
MAIN
REQUEST
INGRESSuseless.null_tween_factory
useless.useless_tween_factorypyramid.tweens.excview_tween_factory
MAIN
3 ways of positioning tweens
- implicit- implicit (hint)
- explicit
Suggested positioning (hint)
config.add_tween('useless.useless_tween_factory')
config.add_tween('useless.null_tween_factory',
over=pyramid.tweens.MAIN,
under='useless.useless_tween_factory')
Tween constants
pyramid.tweens.INGRESSpyramid.tweens.EXCVIEWpyramid.tweens.MAIN
You cannot position a tweenbefore INGRESS (over)nor after MAIN (under)
3 ways of positioning tweens
- implicit- implicit (hint)
- explicit
Explicit positioning
# development.ini
[app:main]
...
pyramid.tweens = useless.useless_tween_factory
useless.null_tween_factory
pyramid.tweens.excview_tween_factory
WARNING:
Explicit tween ordering(via the .ini file)
will ignore any calls toconfig.add_tween( … )
WARNING:
[app:main]...pyramid.includes = pyramid_debugtoolbarpyramid.tweens = useless.useless_tween_factory useless.null_tween_factory pyramid.tweens.excview_tween_factory
WARNING:
[app:main]...pyramid.includes = pyramid_debugtoolbarpyramid.tweens = useless.useless_tween_factory useless.null_tween_factory pyramid.tweens.excview_tween_factory
Explicitly tween positioning requiresthat you declare ALL tweens.
Listing tweens
$ paster ptweens development.ini#main
Position Name INGRESS0 useless.useless_tween_factory1 useless.null_tween_factory2 pyramid.tweens.excview_tween_factory MAIN
Tweens you might be using:
- pyramid_debugtoolbar- pyramid_tm
pyramid_debugtoolbar
Debug Toolbar renders and injects HTMLinto your response
Although it can decide whether or not it should render HTML depending on your host address
Transaction Manager(pyramid_tm)
For every request,it creates a new transactionand closes it on response.
Transaction Manageris NOT about database transactions
pyramid_tm relies on the transaction package
1
Register your commit / rollback action withthe transaction package (join() the transaction)
2pyramid_tm calls:
transaction.begin() on requestthen
transaction.commit() or transaction.rollback()
3
the transaction package will thencall subscribed callbacks
Why is this useful?
One single point of commit.
Avoid sending an email“Your account has been created! \o/”
when your DB write actually failed
Things you could do:
- commit your DB transaction- invalidate cache- send an email
...
I already have try/except blocks in my Pyramid views, I don't need pyramid_tm.
Until you get a stupid Exception outside your block (e.g., in the renderer) for whatever reason.
Also know as: a bug.
Pyramid registers SQLAlchemy automatically
extension=ZopeTransactionExtension()
Did you know?
pyramid_tm is responsiblefor the existence of Pyramid tweens.
It was the first use case for tweens.
Now you are tween experts!
Use wisely.
Thank you !!!
let's totally follow each other like,on twitter!!!1! LOOOL :D
@alexconrad