Pyramid

Gael Pasgrimaud @gawel_

python-nantes 2015

About me

Quoi c’est ?

Python

images/pyramid_mommie.jpg

.

Comment que c’est ?

Hello world

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()
    make_server('0.0.0.0', 8080, app).serve_forever()

Dispatch d’url

On déclare une route que l’on associe à un callable:

config.add_route('hello', '/hello/{name}')
config.add_view(hello_world, route_name='hello')

Traversing

On traverse un mapping clé/prochaine valeur:

class Parent:

    def __init__(self, request):
        self.request = request

    def __getitem__(self, item):
        return Children(self.request)


config.add_route('home', 'traversable/*traverse',
                 factory=root_factory')
config.add_view('mypackage.views.myview', route_name='home')

Résolution de routes

Recontruire des urls à partir de route nommées:

request.route_url('home', name='francois')

Exceptions

Moins on a de if mieux on se porte:

from pyramid import httpexceptions as exc

def view(request):
     raise exc.HTTPFound(location='/')

Contexte de vue

Une factory permet de retrouver un objet:

def view_with_context(context, request):
     return {}

config.add_view(view_with_context, route_name='home',
                factory=Context)

Authentification

request.authentidated_user

Authorisations

config.add_view(edit_view, route_name='edit',
                permission=Edit)
class Context:
    def __acl__(self):
        return [
            (Allow, 'admin', Edit),
            (Allow, Everyone, View),
        ]
request.has_permission(Edit, context)

Rendering

Une vue retourne un dictionnaire, le renderer est responsable du rendu:

config.add_view(view, renderer='json')
config.add_view(view, renderer='template/index.html')

Il en existe pour Chameleon, Jinja, Mako, json, text ...

Renderers

Mais on peut ajouter le sien:

class TSVRenderer(object):
    def __init__(self, info):
        pass

    def __call__(self, value, system):
        fout = StringIO()
        writer = csv.writer(fout, delimiter='\t', quotechar='"',
                            quoting=csv.QUOTE_MINIMAL)
        writer.writerow(value['header'])
        writer.writerows(value['rows'])
        filename = value['filename']
        resp = system['request'].response
        resp.content_type = 'text/csv'
        resp.content_disposition = 'attachment;filename=' + filename + '.tsv'
        return fout.getvalue()

config.add_renderer('tsv', TSVRenderer)

Tweens

Evénements

NewRequest, BeforeRender

Modulaire / extensible

La magie du includemémé:

def includeme(config):
    config.include('mymodule', route_prefix='/foo')

Etendre l’objet request:

config.add_request_method(*args)

Et encore...

Ecosystème