Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pyramid, not only an architectural wonder

Rach Belaid
September 21, 2013

Pyramid, not only an architectural wonder

7 great features of Pyramid

Rach Belaid

September 21, 2013
Tweet

More Decks by Rach Belaid

Other Decks in Programming

Transcript

  1. Hello, Bonjour Rach Belaid Vim Enthusiast, Python Developer, Postgres Fan,

    Git Lover, Belgian Erlang Hobbyist, rach @rachbelaid rachbelaid.com [email protected] Wednesday, 1 January 14
  2. Example: Imperative Configuration from wsgiref.simple_server import make_server from pyramid.config import

    Configurator from pyramid.response import Response def hello_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.add_route('home', '/') config.add_view(hello_world, route_name='home') app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever() Wednesday, 1 January 14
  3. Example: Declarative Configuration from wsgiref.simple_server import make_server from pyramid.config import

    Configurator from pyramid.response import Response from pyramid.view import view_config @view_config(route_name='home') def hello_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.add_route('home', '/') config.scan() #run the app app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever() Wednesday, 1 January 14
  4. What are Views? Pyramid views are callable objects and can

    be : Function Method Class Wednesday, 1 January 14
  5. Adding Views There is 2 ways to add views :

    - Via config method: Configurator.add_view(...) - Via decorator @view_config(...) Wednesday, 1 January 14
  6. View ≠ Route - Routes match urls - Views match

    routes Wednesday, 1 January 14
  7. From Request to View home profile / /username welcome welcome

    home welcome profile Requests Routes Views GET POST USER? GET GET Route Matching route matching View Lookup Wednesday, 1 January 14
  8. View lookup configs Pyramid allow you to configure a view

    to be matched using many parameters - route name - request method : POST, GET, ... - xhr - request params - match params - custom predicates function Wednesday, 1 January 14
  9. Example - View Lookup route name ... def hello_world(request): return

    Response('Hello world!') def hi_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.add_route('test1', '/test1') config.add_route('test2', '/test2') config.add_view(hello_world, route_name='test1') config.add_view(hi_world, route_name='test2') ... Wednesday, 1 January 14
  10. Example - View Lookup request method ... @view_config(route_name='test', request_method='GET') def

    hello_world(request): return Response('Hello world!') @view_config(route_name='test', request_method='POST') def thanks_you(request): return Response('Thanks you') if __name__ == '__main__': config = Configurator() config.add_route('test', '/test') config.scan() ... Wednesday, 1 January 14
  11. Example - View Lookup Xhr ... @view_config(route_name='test') def hello_world(request): return

    Response('Hello world!') @view_config(route_name='test', xhr=True) def hello_world_xhr(request): val = json.dumps({'response':'Hello World'}) return Response(val) if __name__ == '__main__': config = Configurator() config.add_route('test', '/test') config.scan() ... Wednesday, 1 January 14
  12. Hooks everything - Events : Before Renderer, NewRequest, NewResponse, ApplicationCreated,

    ... custom - Callbacks : Response Callback, Finish Callbacks - Response Adaptor : teach how to represent object into Response Wednesday, 1 January 14
  13. Response adapter To allow views to return objects without requiring

    a renderer to convert def string_response_adapter(s): response = Response(s) return response config.add_response_adapter(string_response_adapter, str) Wednesday, 1 January 14
  14. Callbacks To allow views to return objects without requiring a

    renderer to convert def cache_callback(request, response): """Set the cache_control max_age for the response""" if request.exception is not None: response.cache_control.max_age = 360 request.add_response_callback(cache_callback) Wednesday, 1 January 14
  15. Extending Pyramid Pyramid allows you to extend its Configurator with

    custom directives. Custom directives can use other directives, they can add a custom action. Wednesday, 1 January 14
  16. Example extension def add_newrequest_subscriber(config, subscriber): config.add_subscriber(subscriber, NewRequest) def includeme(config): config.add_directive('add_newrequest_subscriber',

    add_newrequest_subscriber) Module: Conf: def mysubscriber(event): print(event.request) from pyramid.config import Configurator config = Configurator() config.include('pyramid_subscriberhelpers') config.add_newrequest_subscriber(mysubscriber) Wednesday, 1 January 14
  17. Renderers A view don’t always need to return a Response

    object. If not then Pyramid attempt to use a renderer to construct a response Wednesday, 1 January 14
  18. Built-in Renderers - string - JSON - JSONP - Chameleon

    Template : *.pt or *.txt - Mako Template : *.mak or *.mako Wednesday, 1 January 14
  19. Class base views - example with renderer ... @view_defaults(route_name='rest', renderer='JSON')

    class RESTView(object): def __init__(self, request): self.request = request @view_config(request_method='GET') def get(self): return {'method':'GET'} @view_config(request_method='POST') def post(self): return {'method':'POST'} @view_config(request_method='DELETE') def delete(self): return {'method':'DELETE'} Wednesday, 1 January 14
  20. Renderers & Templates - When the renderer is set to

    a Template. The view needs to return a dict to populate the context renderer='templates/home.pt' renderer='package:templates/home.mak' renderer='home.jinja2' Wednesday, 1 January 14
  21. Renderer adaptor - teach your renderer to render some type

    or object from pyramid.renderers import JSON import datetime def datetime_adapter(obj, request): return obj.isoformat() #in your config json_renderer = JSON() json_renderer.add_adapter(datetime.datetime, datetime_adapter) Wednesday, 1 January 14
  22. Auth’s setup from wsgiref.simple_server import make_server from pyramid.config import Configurator

    from pyramid.response import Response from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy def hello_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() authn_policy = AuthTktAuthenticationPolicy('seekrit') authz_policy = ACLAuthorizationPolicy() config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config.add_route('home', '/') config.add_view(hello_world, route_name='home') app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever() Wednesday, 1 January 14
  23. Resource Tree User Users Resources Repo Issue Wiki Org Billing

    Anonymous User User ACL ACL ACL A Wednesday, 1 January 14
  24. Assigning ACLs to your Resource Objects class Repo(Base): __acl__ =

    [ (Allow, 'jack', 'view')] class Billing(object): def __init__(self, request): matchdict = request.matchdict self.id = matchdict.get('id', None) if self.id == '1': self.__acl__ = [ (Allow, 'henry', 'view'), (Allow, 'jack', 'view') ] On the class On the instance Wednesday, 1 January 14
  25. ACL Inheritance if a resource object does not have an

    ACL when it is the context, its parent is consulted for an ACL. class Repo(Base): __acl__ = [ (Allow, 'jack', 'view') ] class Wiki(Base): __name__ = 'wiki' __parent__ = Repo Wednesday, 1 January 14
  26. So much more! Events Tweens View predicates Subscriber predicates Callbacks

    View Mapper Renderer adapter Special permission Permission with Traversal Special Action Default permission Traversal Wednesday, 1 January 14