SlideShare uma empresa Scribd logo
1 de 27
Baixar para ler offline
Pyramid Framework
The good, the bad and why it's great.
Anatoly Bubenkov
@bubenkoff
Paylogic Groningen Office
2.09.2013
What is pyramid?
● Pyramid is a general, open source, Python
web application development framework.
● The first release of Pyramid (repoze.bfg) in
July of 2008.
● At the end of 2010, repoze.bfg ->Pyramid.
● And joined Pylons project.
Pyramid was inspired by Zope, Pylons (version
1.0) and Django.
So Pyramid gets best from several concepts,
combining them into a unique web framework.
Zope roots :)
● Many features of Pyramid trace their origins
back to Zope.
● Like Zope applications, Pyramid applications
can be easily extended
● The concepts of traversal and declarative
security in Pyramid were pioneered first in
Zope.
What Makes Pyramid Unique
Good equally for small and big applications.
Common case:
● You start from small app using some
framework, everything is ok
● App grows, you add features, and framework
is now not able to satisfy your needs
● You end up rewriting app/parts of it using
different framework
● Pyramid ‘is’ for both big and small apps.
Architected to build complex things from
simple, which always work.
I want minimal!
One-file app:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
def hello_world(request):
return Response('Hello %(name)s!' % request.matchdict)
if __name__ == '__main__':
config = Configurator()
config.add_route('hello', '/hello/{name}')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
Decorator-based views
Possible, but not required, that you configure
view as decorator for the view function:
from pyramid.view import view_config
from pyramid.response import Response
@view_config(route_name='fred')
def fred_view(request):
return Response('fred')
The huge difference with ‘other’ frameworks:
decorator actually does NOT change the view
function directly. This process is separated to a
stage named configuration scan, allowing the
override and customization of existing apps.
Class-based and function-based
views
Here’s a view callable defined as a function:
from pyramid.response import Response
from pyramid.view import view_config
@view_config(route_name='aview')
def aview(request):
return Response('one')
Here’s a few views defined as methods of a class instead:
from pyramid.response import Response
from pyramid.view import view_config
class AView(object):
def __init__(self, request):
self.request = request
@view_config(route_name='view_one')
def view_one(self):
return Response('one')
@view_config(route_name='view_two')
def view_two(self):
return Response('two')
Assets? Templates are also assets!
● Asset specifications are strings that contain
both a Python package name and a file or
directory name, e.g. MyPackage:
static/index.html.
● An asset specification can refer to a
template, a translation directory, or any other
package-bound static resource.
● Because asset specifications are used
heavily in Pyramid, they provided a way to
allow users to override assets easily and in
granular way.
Templating: pluggable
● Pyramid has a structured API that allows for
pluggability of “renderers”.
● Templating systems such as Mako, Genshi,
Chameleon, and Jinja2 can be treated as
renderers.
● Renderer bindings for all of these templating
systems already exist for use in Pyramid.
● But if you’d rather use another, it’s not a big
deal.
Views should be declared as views
Why the view function should return the
rendered stuff? It’s hard to cover it with tests.
Much better to separate logic.
For example, instead of:
from pyramid.renderers import render_to_response
def myview(request):
return render_to_response('myapp:templates/mytemplate.pt', {'a':1},
request=request)
You CAN do this:
from pyramid.view import view_config
@view_config(renderer='myapp:templates/mytemplate.pt')
def myview(request):
return {'a':1}
Event system
Pyramid provides (and uses itself internally) the
powerful event system.
It emits events during its request processing
lifecycle. You can subscribe any number of
listeners to these events. For example, to be
notified of a new request, you can subscribe to
the NewRequest event. To be notified that a
template is about to be rendered, you can
subscribe to the BeforeRender event, and so
forth.
Using event system
Imperative
from pyramid.events import NewRequest
from subscribers import mysubscriber
# "config" below is assumed to be an instance of a
# pyramid.config.Configurator object
config.add_subscriber(mysubscriber, NewRequest)
Decorator
from pyramid.events import NewRequest
from pyramid.events import subscriber
@subscriber(NewRequest)
def mysubscriber(event):
event.request.foo = 1
The big difference here, is that events are used even in the core, request
processing, so you can easily modify it during it’s life cycle!
What about speed?
Answer: fast enough
● Apache 2.2.14 was used. Just because it’s standard
● Python 2.6.5 and mod_wsgi 2.8 (embedded mode) were used.
No singletons
● Import of a Pyramid application needn’t have
any “import-time side effects”.
● Now try to import and and work with django
app without ‘settings’ :)
● Helps a lot deploying your system using an
asynchronous server.
● You can even run multiple copies of a similar
but not identically configured Pyramid
application within the same Python process.
View predicates and many views per
route
● Pyramid allows you to associate more than one view
per route.
● You can create a route with the pattern /items and when
the route is matched, you can shuffle off the request to
one view if the request method is GET, another view if
the request method is POST
● A system known as “view predicates” allows for this.
● Predicates: request_type, request_method,
request_param, match_param, and lot more, and
CUSTOM ones
Simple example:
config.add_view('my.package.GET_view', route_name='xhr_route',
xhr=True, permission='view', request_method='GET')
Transaction management
● stolen from Zope
● it’s potentially bad to have explicit commits
because you can accidentally change model
after commit
● no explicit commit (but it’s of course still up
to you)
● allows you to synchronize commits between
multiple databases, and allows you to do
things like conditionally send email if a
transaction commits, but otherwise keep
quiet.
Configuration: conflict detection and
custom directives
● Pyramid’s configuration system keeps track of your
configuration statements
● Identical, or ‘conflicting’ statements are complained
● You can have your custom constraints for configuration
directives
from pyramid.config import Configurator
def add_protected_xhr_views(config, module):
module = config.maybe_dotted(module)
for method in ('GET', 'POST', 'HEAD'):
view = getattr(module, 'xhr_%s_view' % method, None)
if view is not None:
config.add_view(view, route_name='xhr_route', xhr=True,
permission='view', request_method=method)
config = Configurator()
config.add_directive('add_protected_xhr_views', add_protected_xhr_views)
Configuration: conflict detection and
custom directives
Then instead of:
from pyramid.config import Configurator
config = Configurator()
config.add_route('xhr_route', '/xhr/{id}')
config.add_view('my.package.GET_view', route_name='xhr_route',
xhr=True, permission='view', request_method='GET')
config.add_view('my.package.POST_view', route_name='xhr_route',
xhr=True, permission='view', request_method='POST')
config.add_view('my.package.HEAD_view', route_name='xhr_route',
xhr=True, permission='view', request_method='HEAD')
you get this:
config.add_route('xhr_route', '/xhr/{id}')
config.add_protected_xhr_views('my.package')
Configuration: extensibility
● All the configuration statements that can be performed
in your “main” Pyramid application can also be
performed by included packages including the addition
of views, routes, subscribers, and even authentication
and authorization policies.
● You can even extend or override an existing application
by including another application’s configuration in your
own, overriding or adding new views and routes to it.
from pyramid.config import Configurator
if __name__ == '__main__':
config = Configurator()
config.include('pyramid_jinja2')
config.include('pyramid_exclog')
config.include('some.other.guys.package', route_prefix='/someotherguy')
Flexible authentication and authorization: the thing you
always missed
● Pyramid includes a flexible, pluggable
authentication and authorization system.
● Predefined Pyramid plugpoint to plug in your
custom authentication and authorization
code
● If you want to change these schemes later,
you can just change it in one place rather
than everywhere in your code.
Declarative security
from pyramid.security import Everyone
from pyramid.security import Allow
class Blog(object):
__acl__ = [
(Allow, Everyone, 'view'),
(Allow, 'group:editors', 'add'),
(Allow, 'group:editors', 'edit'),
]
from pyramid.config import Configurator
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
authn_policy = AuthTktAuthenticationPolicy('seekrit', hashalg='sha512')
authz_policy = ACLAuthorizationPolicy()
config = Configurator()
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(authz_policy)
from pyramid.view import view_config
from resources import Blog
@view_config(context=Blog, name='add_entry.html', permission='add')
def blog_entry_add_view(request):
""" Add blog entry code goes here """
pass
Traversal
● Traversal is a concept stolen from Zope
● It allows you to create a tree of resources, each of which can be addressed
by one or more URLs
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
class Resource(dict):
pass
def get_root(request):
return Resource({'a': Resource({'b': Resource({'c': Resource()})})})
def hello_world_of_resources(context, request):
output = "Here's a resource and its children: %s" % context
return Response(output)
if __name__ == '__main__':
config = Configurator(root_factory=get_root)
config.add_view(hello_world_of_resources, context=Resource)
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
View response adapters
To follow DRY principle, often you don’t want to
repeat returning the Response object from the
view
def aview(request):
return "Hello world!"
from pyramid.config import Configurator
from pyramid.response import Response
def string_response_adapter(s):
response = Response(s)
response.content_type = 'text/html'
return response
if __name__ == '__main__':
config = Configurator()
config.add_response_adapter(string_response_adapter, basestring)
Programmatic Introspection
It’s good to have a well-defined mechanism to
get back what was registered earlier: views,
urls, etc
from pyramid.view import view_config
from pyramid.response import Response
@view_config(route_name='bar')
def show_current_route_pattern(request):
introspector = request.registry.introspector
route_name = request.matched_route.name
route_intr = introspector.get('routes', route_name)
return Response(str(route_intr['pattern']))
So what is bad then?
● Probably nothing
● People are worried by ‘complexity’
● You should always understand what are you
doing
● Traversal and security are not easy, but very
powerful
● Pyramid is not a monster like Django, you
get nothing if you don’t want
● Much less existing packages (but the quality
of existing is high)
Thanks for your attention!
Questions?
Reference:
● http://docs.pylonsproject.
org/projects/pyramid/en/latest/narr/introducti
on.html
● http://blog.curiasolutions.com/the-great-web-
framework-shootout/

Mais conteúdo relacionado

Mais procurados

Zookeeper big sonata
Zookeeper  big sonataZookeeper  big sonata
Zookeeper big sonata
Anh Le
 

Mais procurados (20)

Django Rest Framework - Building a Web API
Django Rest Framework - Building a Web APIDjango Rest Framework - Building a Web API
Django Rest Framework - Building a Web API
 
Introduction à Angular
Introduction à AngularIntroduction à Angular
Introduction à Angular
 
Angular routing
Angular routingAngular routing
Angular routing
 
Circuit breakers - Using Spring-Boot + Hystrix + Dashboard + Retry
Circuit breakers - Using Spring-Boot + Hystrix + Dashboard + RetryCircuit breakers - Using Spring-Boot + Hystrix + Dashboard + Retry
Circuit breakers - Using Spring-Boot + Hystrix + Dashboard + Retry
 
Angular Framework présentation PPT LIGHT
Angular Framework présentation PPT LIGHTAngular Framework présentation PPT LIGHT
Angular Framework présentation PPT LIGHT
 
Node js Introduction
Node js IntroductionNode js Introduction
Node js Introduction
 
Basic Python Django
Basic Python DjangoBasic Python Django
Basic Python Django
 
One More State Management in Angular (NGRX vs. NGXS vs. Akita vs. RXJS)
One More State Management in Angular (NGRX vs. NGXS vs. Akita vs. RXJS)One More State Management in Angular (NGRX vs. NGXS vs. Akita vs. RXJS)
One More State Management in Angular (NGRX vs. NGXS vs. Akita vs. RXJS)
 
REST Easy with Django-Rest-Framework
REST Easy with Django-Rest-FrameworkREST Easy with Django-Rest-Framework
REST Easy with Django-Rest-Framework
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
1. flutter introduccion v2
1.  flutter introduccion v21.  flutter introduccion v2
1. flutter introduccion v2
 
cours j2ee -présentation
cours  j2ee -présentationcours  j2ee -présentation
cours j2ee -présentation
 
Unit 4-apache pig
Unit 4-apache pigUnit 4-apache pig
Unit 4-apache pig
 
Zookeeper big sonata
Zookeeper  big sonataZookeeper  big sonata
Zookeeper big sonata
 
Nodejs presentation
Nodejs presentationNodejs presentation
Nodejs presentation
 
Swagger
SwaggerSwagger
Swagger
 
Clickstream & Social Media Analysis using Apache Spark
Clickstream & Social Media Analysis using Apache SparkClickstream & Social Media Analysis using Apache Spark
Clickstream & Social Media Analysis using Apache Spark
 
Django Introduction & Tutorial
Django Introduction & TutorialDjango Introduction & Tutorial
Django Introduction & Tutorial
 
De 0 à Angular en 1h30! (french)
De 0 à Angular en 1h30! (french)De 0 à Angular en 1h30! (french)
De 0 à Angular en 1h30! (french)
 
Java J2EE
Java J2EEJava J2EE
Java J2EE
 

Destaque (12)

Edited chapter5
Edited chapter5Edited chapter5
Edited chapter5
 
consumer behaviour learning
 consumer behaviour learning  consumer behaviour learning
consumer behaviour learning
 
Motivation-Techniques and Examples
Motivation-Techniques and ExamplesMotivation-Techniques and Examples
Motivation-Techniques and Examples
 
Motivation and Performance Appraisal
Motivation and Performance AppraisalMotivation and Performance Appraisal
Motivation and Performance Appraisal
 
Black box theory new
Black box theory newBlack box theory new
Black box theory new
 
Consumer learning
Consumer learningConsumer learning
Consumer learning
 
Relationship marketing
Relationship marketingRelationship marketing
Relationship marketing
 
Relationship Marketing
Relationship MarketingRelationship Marketing
Relationship Marketing
 
Motivation techniques
Motivation techniquesMotivation techniques
Motivation techniques
 
Presentation on 4 p's
Presentation on 4 p'sPresentation on 4 p's
Presentation on 4 p's
 
Marketing Mix
Marketing MixMarketing Mix
Marketing Mix
 
Attitudes and values
Attitudes and valuesAttitudes and values
Attitudes and values
 

Semelhante a Pyramid Framework

Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2
Alessandro Molina
 

Semelhante a Pyramid Framework (20)

Pyramid tutorial
Pyramid tutorialPyramid tutorial
Pyramid tutorial
 
Gephi Toolkit Tutorial
Gephi Toolkit TutorialGephi Toolkit Tutorial
Gephi Toolkit Tutorial
 
Pyramid patterns
Pyramid patternsPyramid patterns
Pyramid patterns
 
React django
React djangoReact django
React django
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
 
Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2Rapid Prototyping with TurboGears2
Rapid Prototyping with TurboGears2
 
Angular Intermediate
Angular IntermediateAngular Intermediate
Angular Intermediate
 
Voorhoede - Front-end architecture
Voorhoede - Front-end architectureVoorhoede - Front-end architecture
Voorhoede - Front-end architecture
 
Pyramid Deployment and Maintenance
Pyramid Deployment and MaintenancePyramid Deployment and Maintenance
Pyramid Deployment and Maintenance
 
بررسی چارچوب جنگو
بررسی چارچوب جنگوبررسی چارچوب جنگو
بررسی چارچوب جنگو
 
JMP103 : Extending Your App Arsenal With OpenSocial
JMP103 : Extending Your App Arsenal With OpenSocialJMP103 : Extending Your App Arsenal With OpenSocial
JMP103 : Extending Your App Arsenal With OpenSocial
 
IBM Connect 2014 - JMP103: Extending Your Application Arsenal With OpenSocial
IBM Connect 2014 - JMP103: Extending Your Application Arsenal With OpenSocialIBM Connect 2014 - JMP103: Extending Your Application Arsenal With OpenSocial
IBM Connect 2014 - JMP103: Extending Your Application Arsenal With OpenSocial
 
Introduction to django framework
Introduction to django frameworkIntroduction to django framework
Introduction to django framework
 
L04 base patterns
L04 base patternsL04 base patterns
L04 base patterns
 
Pyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsPyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web apps
 
Angular JS2 Training Session #2
Angular JS2 Training Session #2Angular JS2 Training Session #2
Angular JS2 Training Session #2
 
Akash rajguru project report sem v
Akash rajguru project report sem vAkash rajguru project report sem v
Akash rajguru project report sem v
 
AngularJs Crash Course
AngularJs Crash CourseAngularJs Crash Course
AngularJs Crash Course
 
Android architecture
Android architecture Android architecture
Android architecture
 
Angular performance slides
Angular performance slidesAngular performance slides
Angular performance slides
 

Último

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Último (20)

CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 

Pyramid Framework

  • 1. Pyramid Framework The good, the bad and why it's great. Anatoly Bubenkov @bubenkoff Paylogic Groningen Office 2.09.2013
  • 2. What is pyramid? ● Pyramid is a general, open source, Python web application development framework. ● The first release of Pyramid (repoze.bfg) in July of 2008. ● At the end of 2010, repoze.bfg ->Pyramid. ● And joined Pylons project. Pyramid was inspired by Zope, Pylons (version 1.0) and Django. So Pyramid gets best from several concepts, combining them into a unique web framework.
  • 3. Zope roots :) ● Many features of Pyramid trace their origins back to Zope. ● Like Zope applications, Pyramid applications can be easily extended ● The concepts of traversal and declarative security in Pyramid were pioneered first in Zope.
  • 4. What Makes Pyramid Unique Good equally for small and big applications. Common case: ● You start from small app using some framework, everything is ok ● App grows, you add features, and framework is now not able to satisfy your needs ● You end up rewriting app/parts of it using different framework ● Pyramid ‘is’ for both big and small apps. Architected to build complex things from simple, which always work.
  • 5. I want minimal! One-file app: from wsgiref.simple_server import make_server from pyramid.config import Configurator from pyramid.response import Response def hello_world(request): return Response('Hello %(name)s!' % request.matchdict) if __name__ == '__main__': config = Configurator() config.add_route('hello', '/hello/{name}') config.add_view(hello_world, route_name='hello') app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()
  • 6. Decorator-based views Possible, but not required, that you configure view as decorator for the view function: from pyramid.view import view_config from pyramid.response import Response @view_config(route_name='fred') def fred_view(request): return Response('fred') The huge difference with ‘other’ frameworks: decorator actually does NOT change the view function directly. This process is separated to a stage named configuration scan, allowing the override and customization of existing apps.
  • 7. Class-based and function-based views Here’s a view callable defined as a function: from pyramid.response import Response from pyramid.view import view_config @view_config(route_name='aview') def aview(request): return Response('one') Here’s a few views defined as methods of a class instead: from pyramid.response import Response from pyramid.view import view_config class AView(object): def __init__(self, request): self.request = request @view_config(route_name='view_one') def view_one(self): return Response('one') @view_config(route_name='view_two') def view_two(self): return Response('two')
  • 8. Assets? Templates are also assets! ● Asset specifications are strings that contain both a Python package name and a file or directory name, e.g. MyPackage: static/index.html. ● An asset specification can refer to a template, a translation directory, or any other package-bound static resource. ● Because asset specifications are used heavily in Pyramid, they provided a way to allow users to override assets easily and in granular way.
  • 9. Templating: pluggable ● Pyramid has a structured API that allows for pluggability of “renderers”. ● Templating systems such as Mako, Genshi, Chameleon, and Jinja2 can be treated as renderers. ● Renderer bindings for all of these templating systems already exist for use in Pyramid. ● But if you’d rather use another, it’s not a big deal.
  • 10. Views should be declared as views Why the view function should return the rendered stuff? It’s hard to cover it with tests. Much better to separate logic. For example, instead of: from pyramid.renderers import render_to_response def myview(request): return render_to_response('myapp:templates/mytemplate.pt', {'a':1}, request=request) You CAN do this: from pyramid.view import view_config @view_config(renderer='myapp:templates/mytemplate.pt') def myview(request): return {'a':1}
  • 11. Event system Pyramid provides (and uses itself internally) the powerful event system. It emits events during its request processing lifecycle. You can subscribe any number of listeners to these events. For example, to be notified of a new request, you can subscribe to the NewRequest event. To be notified that a template is about to be rendered, you can subscribe to the BeforeRender event, and so forth.
  • 12. Using event system Imperative from pyramid.events import NewRequest from subscribers import mysubscriber # "config" below is assumed to be an instance of a # pyramid.config.Configurator object config.add_subscriber(mysubscriber, NewRequest) Decorator from pyramid.events import NewRequest from pyramid.events import subscriber @subscriber(NewRequest) def mysubscriber(event): event.request.foo = 1 The big difference here, is that events are used even in the core, request processing, so you can easily modify it during it’s life cycle!
  • 13. What about speed? Answer: fast enough ● Apache 2.2.14 was used. Just because it’s standard ● Python 2.6.5 and mod_wsgi 2.8 (embedded mode) were used.
  • 14. No singletons ● Import of a Pyramid application needn’t have any “import-time side effects”. ● Now try to import and and work with django app without ‘settings’ :) ● Helps a lot deploying your system using an asynchronous server. ● You can even run multiple copies of a similar but not identically configured Pyramid application within the same Python process.
  • 15. View predicates and many views per route ● Pyramid allows you to associate more than one view per route. ● You can create a route with the pattern /items and when the route is matched, you can shuffle off the request to one view if the request method is GET, another view if the request method is POST ● A system known as “view predicates” allows for this. ● Predicates: request_type, request_method, request_param, match_param, and lot more, and CUSTOM ones Simple example: config.add_view('my.package.GET_view', route_name='xhr_route', xhr=True, permission='view', request_method='GET')
  • 16. Transaction management ● stolen from Zope ● it’s potentially bad to have explicit commits because you can accidentally change model after commit ● no explicit commit (but it’s of course still up to you) ● allows you to synchronize commits between multiple databases, and allows you to do things like conditionally send email if a transaction commits, but otherwise keep quiet.
  • 17. Configuration: conflict detection and custom directives ● Pyramid’s configuration system keeps track of your configuration statements ● Identical, or ‘conflicting’ statements are complained ● You can have your custom constraints for configuration directives from pyramid.config import Configurator def add_protected_xhr_views(config, module): module = config.maybe_dotted(module) for method in ('GET', 'POST', 'HEAD'): view = getattr(module, 'xhr_%s_view' % method, None) if view is not None: config.add_view(view, route_name='xhr_route', xhr=True, permission='view', request_method=method) config = Configurator() config.add_directive('add_protected_xhr_views', add_protected_xhr_views)
  • 18. Configuration: conflict detection and custom directives Then instead of: from pyramid.config import Configurator config = Configurator() config.add_route('xhr_route', '/xhr/{id}') config.add_view('my.package.GET_view', route_name='xhr_route', xhr=True, permission='view', request_method='GET') config.add_view('my.package.POST_view', route_name='xhr_route', xhr=True, permission='view', request_method='POST') config.add_view('my.package.HEAD_view', route_name='xhr_route', xhr=True, permission='view', request_method='HEAD') you get this: config.add_route('xhr_route', '/xhr/{id}') config.add_protected_xhr_views('my.package')
  • 19. Configuration: extensibility ● All the configuration statements that can be performed in your “main” Pyramid application can also be performed by included packages including the addition of views, routes, subscribers, and even authentication and authorization policies. ● You can even extend or override an existing application by including another application’s configuration in your own, overriding or adding new views and routes to it. from pyramid.config import Configurator if __name__ == '__main__': config = Configurator() config.include('pyramid_jinja2') config.include('pyramid_exclog') config.include('some.other.guys.package', route_prefix='/someotherguy')
  • 20. Flexible authentication and authorization: the thing you always missed ● Pyramid includes a flexible, pluggable authentication and authorization system. ● Predefined Pyramid plugpoint to plug in your custom authentication and authorization code ● If you want to change these schemes later, you can just change it in one place rather than everywhere in your code.
  • 21. Declarative security from pyramid.security import Everyone from pyramid.security import Allow class Blog(object): __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ] from pyramid.config import Configurator from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy authn_policy = AuthTktAuthenticationPolicy('seekrit', hashalg='sha512') authz_policy = ACLAuthorizationPolicy() config = Configurator() config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) from pyramid.view import view_config from resources import Blog @view_config(context=Blog, name='add_entry.html', permission='add') def blog_entry_add_view(request): """ Add blog entry code goes here """ pass
  • 22. Traversal ● Traversal is a concept stolen from Zope ● It allows you to create a tree of resources, each of which can be addressed by one or more URLs from wsgiref.simple_server import make_server from pyramid.config import Configurator from pyramid.response import Response class Resource(dict): pass def get_root(request): return Resource({'a': Resource({'b': Resource({'c': Resource()})})}) def hello_world_of_resources(context, request): output = "Here's a resource and its children: %s" % context return Response(output) if __name__ == '__main__': config = Configurator(root_factory=get_root) config.add_view(hello_world_of_resources, context=Resource) app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()
  • 23. View response adapters To follow DRY principle, often you don’t want to repeat returning the Response object from the view def aview(request): return "Hello world!" from pyramid.config import Configurator from pyramid.response import Response def string_response_adapter(s): response = Response(s) response.content_type = 'text/html' return response if __name__ == '__main__': config = Configurator() config.add_response_adapter(string_response_adapter, basestring)
  • 24. Programmatic Introspection It’s good to have a well-defined mechanism to get back what was registered earlier: views, urls, etc from pyramid.view import view_config from pyramid.response import Response @view_config(route_name='bar') def show_current_route_pattern(request): introspector = request.registry.introspector route_name = request.matched_route.name route_intr = introspector.get('routes', route_name) return Response(str(route_intr['pattern']))
  • 25. So what is bad then? ● Probably nothing ● People are worried by ‘complexity’ ● You should always understand what are you doing ● Traversal and security are not easy, but very powerful ● Pyramid is not a monster like Django, you get nothing if you don’t want ● Much less existing packages (but the quality of existing is high)
  • 26. Thanks for your attention! Questions?