Pyramid Lighter/Faster/Better web apps

  • 9,697 views
Uploaded on

Gentle introduction to Pyramid. Where it comes from, how simple it, how fast, how flexible and why the future will be pyramid shaped. …

Gentle introduction to Pyramid. Where it comes from, how simple it, how fast, how flexible and why the future will be pyramid shaped.

Made for pyconau 2011

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
9,697
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
45
Comments
0
Likes
7

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Lighter/faster/better web apps Dylan Jay CTO PretaWeb.com SyPy.org twitter: djay75
  • 2. From the mind of Chris McDonough As seen in bearded of PyCon 2009 http://www.flickr.com/photos/termie/3392894269/
  • 3. Pyramid Family Tree Zope formally Principia (1996-) Zope2 (1998-) BlueBream formally Zope3 (2004-) ZTK (2009-) Repoze.bfg (2008 – 2010) Pylons (2005-2010) Pylons Project (2010-) Pyramid formally repoze.bfg ( Dec 2010 -) TurboGears (2005-) RoR (2004-) Django (2005-)
  • 4. Who uses it
    • It's still new
    • 5. Karl Project
    • 6. Aeterna Water – paperless sales system
      • “How to build complex web applications having fun”
      • 7. http://slidesha.re/mH9Lxa
      • 8. 1000 employees
      • 9. No ORM = easy integrate with Plone
      • 10. Less Magic. More simple
  • 11.  
  • 12. From the minds on PretaWeb... PloneFactory Web installer for the worlds favourite Python CMS Coming 2011...
  • 13. Differences...
    • Non opinionated framework
    • 14. Component Architecture
    • 15. Packages (eggs)
    • 16. Simpler and faster
    Pyramid Django Plone Not Opinionated Opinionated Structured (CMS) Very Simple Simple Complex No DB ORM Content Types Little Reuse Some Reuse Easy Reuse
  • 17. Performance http://blog.curiasolutions.com/the-great-web-framework-shootout/
  • 18. Performance http://plope.com/pyroptimization
  • 19. Install $ virtualenv -- no-site-packages -- distribute newproject $ cd newproject $ bin/pip install pyramid
  • 20. Hello World from paste.httpserver import serve from pyramid.configuration import Configurator from pyramid.response import Response def hello_world(context, request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.begin() config.add_view(hello_world) config.end() app = config.make_wsgi_app() serve(app, host='0.0.0.0')
  • 21.
      config.add_route('myroute', '/prefix/{one}/{two}') config.add_view(hello_world, route_name='myroute') foo/{baz}/{bar}*fizzle foo/{baz}/{bar}{fizzle:.*}
    • Also custom predicates
    Routes (URL Dispatch)
  • 22. View Callables from pyramid.response import Response def hello_world(request): return Response('Hello world!') from pyramid.httpexceptions import HTTPFound class MyView(object): def __init__(self, request): self.request = request def __call__(self): raise HTTPFound(location='http://example.com')
  • 23. Request / prefix/foo/bar?pref=red&pref=blue; def hello_world(request): assert 'blue' == request.params['pref'] assert ['red,'blue] == request.params.getall('pref') assert ['foo','bar'] == request.matchdict.values() return Response('Hello world!')
  • 24. Renderers from pyramid.view import view_config @view_config(renderer='json') def hello_world(request): return {'content':'Hello!'} @view_config(renderer='string') def hello_world(request): return {'content':'Hello!'} @ view_config(renderer='mypackage:templates/foo.mak') Add your own - config.add_renderer('.jinja2', 'mypackage.MyJinja2Renderer')
  • 25. Templates from pyramid.renderers import render_to_response def sample_view(request): return render_to_response('templates/foo.pt', {' foo':1, 'bar':2}, request=request)
  • 26. Templates from pyramid.renderers import render_to_response def sample_view(request): return render_to_response('templates/foo.pt', {' foo':1, 'bar':2}, request=request)
  • 27. BYO Templating from mako.template import Template from pyramid.response import Response def make_view(request): template = Template(filename='/templates/template.mak') result = template.render(name=request.params['name']) response = Response(result) return response
  • 28. Chameleon ZPT Templates
    • Compiled to python – really fast
    • 29. XHTML complaint
    • 30. .pt files
    <! DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot; http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;> < html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xmlns:tal=&quot;http://xml.zope.org/namespaces/tal&quot;> < head> < meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /> < title>${project} Application</title> </ head> < body> < h1 class=&quot;title&quot;>Welcome to <code>${project}</code>, an application generated by the <a Href=”http://...&quot; tal:attributes=”href mylink” > pyramid</a> web application framework.</h1> < ul > <li tal:repeat=”row rows”>${row}</li></ul> </ body> </ html>
  • 31. Static Assets config.add_static_view(name='static', path='/var/www/static') / static/main.css -> /var/www/static/main.css config.add_static_view(name='static', path='some_package:a/b/c/static') / static/foo.jpg -> ./src/some_package/a/b/c/static/foo.jpg
  • 32. Traversal
  • 33. Traversal (Resource Location) Pattern allowing transitive and indirect view loockup Simplifies view code for complex apps Great for content centric URLS config.add_view(photo_edit, context=Photo, name='edit') Class User(dict): pass Class Folder(dict): pass Class Photo(dict): pass def photo_edit(request): Return Response('editing %s', request.context.Ttile)
  • 34. Inside Traversal / joeschmoe/photos/photo1/edit psuedo code: context = get_root()['joeschmoe']['photos']['photo1'] view_callable = get_view(context,'edit') request.context = context view_callable(request)
  • 35. View Predicates
    • request_param (key in request.params)
    • 41. containment (class or interface)
    • 42. xhr
    • 43. accept (mimetypes)
    • 44. path_info (regex)
    • 45. custom_predicates
  • 46. Security - Protecting Authentication Policy – Extract principals from request Authorization Policy – Access based on Context, Principals and View's permissions config.add_view(myview, name='add_entry.html', context='mypackage.resources.Blog', permission='add')
  • 47. Security Configuration def auth(userid, request): return ['user:bob','group:editors'] if userid == 'bob' else None from pyramid.config import Configurator from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy authentication_policy = AuthTktAuthenticationPolicy('seekrit', callback=auth) authorization_policy = ACLAuthorizationPolicy() config = Configurator(authentication_policy=authentication_policy, authorization_policy=authorization_policy)
  • 48. Security - Context from pyramid.security import Everyone from pyramid.security import Allow class Blog(object): pass blog = Blog() blog.__acl__ = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ]
  • 49. Scaffolding $ bin/paster create -t pyramid_starter MyProject $ cd myproj $ ../ bin/python setup.py develop $ ../ bin/paster serve development.ini Starting server in PID 16601. serving on 0.0.0.0:6543 view at http://127.0.0.1:6543 MyProject/ |-- CHANGES.txt |-- development.ini |-- MANIFEST.in |-- myproject | |-- __init__.py | |-- resources.py | |-- static | | |-- favicon.ico | | |-- logo.png | | `-- pylons.css | |-- templates | | `-- mytemplate.pt | |-- tests.py | `-- views.py |-- production.ini |-- README.txt |-- setup.cfg `-- setup.py $ bin/paster create -t pyramid_zodb $ bin/paster create -t pyramid_routesalchemy $ bin/paster create -t pyramid_alchemy
  • 50. Customising
    • Designed Extensible
    • 51. Not “apps” like django
    • Plugpoints
  • 54. Customizing Example def configure_views(config): config.add_view('orig_app.views.theview', name='theview') from pyramid.config import Configurator from orig_app import configure_views if __name == '__main__': config = Configurator() config.include(configure_views) config.add_view('override_app.views.theview', name='theview')
  • 55. pyramid_socketio config.add_route('socket_io', 'socket.io/*remaining') config.add_view(socketio_service, route_name='socket_io') from pyramid.response import Response from pyramid_socketio.io import SocketIOContext, socketio_manage class ConnectIOContext(SocketIOContext): # self.io is the Socket.IO socket # self.request is the request def msg_connect(self, msg): print &quot;Connect message received&quot;, msg self.msg(&quot;connected&quot;, hello=&quot;world&quot;) def socketio_service(request): return Response( socketio_manage(ConnectIOContext(request)) )
  • 56. But wait, there's more!
  • 63.
    • Https://convore.com/pylons
    • 64. Http://docs.pylonsproject.org/docs/pyramid.html
    • 65. Https://github.com/Pylons
    • 66. Http://pylonsproject.org
    • 67. Dylan Jay
    • 68. http://www.pretaweb.com