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

Pyramid, le framework web extensible

Pyramid, le framework web extensible

Courte présentation introduisant le framework web pyramid, et plus particulièrement son système d'extensions.

Quelques liens :

Présentation des fonctionnalités : http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/narr/introduction.html
Défense des choix de conception : http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/designdefense.html
Sur le système d'extensions : http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html
La librairire pyramid_persona : https://github.com/madjar/pyramid_persona/

Georges Dubus

June 12, 2013
Tweet

More Decks by Georges Dubus

Other Decks in Technology

Transcript

  1. Présentation du framework Framework web : répondre à des requêtes

    web par des pages web Minimaliste : ne s’occupe que du cœur de problème (mapping url/code, templates, sécurité, i18n, . . . ) Non opinionated (n’impose pas beaucoup de choix) Rapide Super documenté (si c’est pas documenté, ça existe pas) Super solide (si c’est pas testé, c’est cassé) Python 3
  2. Exemple rapide @view_config(route_name=’hello’, renderer=’hello.jinja’) def hello_world(request): name = request.matchdict[’name’] return

    dict(name=name, message=awesome_message(name)) if __name__ == ’__main__’: config = Configurator() config.add_route(’hello’, ’/hello/{name}’) config.scan() app = config.make_wsgi_app() server = make_server(’0.0.0.0’, 8080, app) server.serve_forever() remarques : renderer, scan
  3. Deux manières de mapper des urls à du code URL

    Dispatch Requête /georges/photos/1 Route /{user}/photos/{id} Vue view_photo(request) request.matchdict = {’user’: ’georges’, ’id’: ’1’} Traversal Requête /georges/photos/1 Objet /georges -> <User name=georges> /georges/photos -> <PhotoContainer ...> /georges/photos/1 -> <Photo id=1> Vue view_photo(<Photo id=1>, request)
  4. Traversal /georges/photos/1 → get_root()[’georges’][’photos’][’1’] class PhotoContainer: # ... def __getitem__(self,

    item): try: return query(Photo).filter_by(owner=self.owner, id=int(item)).one() except (NoResultFound, ValueError): raise KeyError(item) @view_config(context=Photo) def view_photo(context, request): # ... (mon latex a mangé l’indentation)
  5. Authorization class Photo: @property def __acl__(self): return ([(Allow, self.owner.id, ’edit’),

    (Allow, self.owner.id, ’view’)] + [(Allow, f.id, ’view’) for f in self.owner.friends] + [(Deny, Everyone, ’access’)]) @view_config(context=Photo, permission=’view’) def view_photo(context, request): # ... @view_config(context=Photo, name=’edit’, permission=’edit’) def edit_photo(context, request): # ...
  6. Comparaison avec Django (différentes philosophies) Django fait tout : ORM,

    formulaires, interface d’admin, . . . Pyramid fournit pas grand chose et permet de facilement rajouter ce qu’on veut, ou remplacer des bouts : pleins de langages de template (jinja, mako, chameleon, . . . ) n’importe quoi pour le modèle (sqlalchemy, mongodb, fichiers, requêtes à un webservice, . . . ) librairies de validation de formulaires (avec ou sans génération du html) Django fournit plus de rails, ce qui rend la création d’applications pluggables plus simple. Les addons de pyramid sont plutôt là pour rajouter des fonctionnalités au framework.
  7. Extensibilité Un mot sur extensibilité, parce ce que c’est là

    que pyramid brille vraiment. J’ai utilisé ça pour implémenter pyramid_persona. [INSERT SHAMELESS PLUG HERE]
  8. Point d’entrée Un framework propose des points d’entrée, des manières

    de plugguer des choses. config = Configurator() authn_policy = AuthTktAuthenticationPolicy(’seekrit’) authz_policy = ACLAuthorizationPolicy() config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config.add_request_method(get_user, ’user’, reify=True) config.add_subscriber(add_global, BeforeRender) config.set_default_permission(’access’) On appelle ça des directives de configuration. L’ordre n’a pas d’importance.
  9. Vérification : validité config = Configurator() authz_policy = ACLAuthorizationPolicy() config.set_authorization_policy(authz_policy)

    config.make_wsgi_app() pyramid.exceptions.ConfigurationError : Cannot configure an authorization policy without also configuring an authentication policy (use the set_authorization_policy method)
  10. Vérification : conflits config = Configurator() authn_policy1 = AuthTktAuthenticationPolicy(’seekrit’) authn_policy2

    = SessionAuthenticationPolicy() config.set_authentication_policy(authn_policy1) config.set_authentication_policy(authn_policy2) config.make_wsgi_app() ConfigurationConflictError
  11. Include : composition et modularité def auth(config): authn_policy = AuthTktAuthenticationPolicy(’seekrit’)

    authz_policy = ACLAuthorizationPolicy() config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config = Configurator() authn_policy = SessionAuthenticationPolicy() config.set_authentication_policy(authn_policy) config.include(auth) Peuvent être imbriqués. Gestion des conflits avancé (ici, SessionAuthenticationPolicy écrase AuthTktAuthenticationPolicy). Pour faire des libs ou juste modulariser son code.
  12. Ajout de directives def set_site_name(config, site_name): # ... config.add_directive(’set_site_name’, set_site_name)

    config.set_site_name(’foo’) Gestion des conflits sur ces nouvelles directives. Et aussi sur add_directive.
  13. Écrire une lib Du coup, écrire une lib, c’est ça

    : (morceau de pyramid_persona) def includeme(config): authz_policy = ACLAuthorizationPolicy() config.set_authorization_policy(authz_policy) secret = settings.get(’persona.secret’, None) authn_policy = AuthTktAuthenticationPolicy(secret, hashalg=’sha512’) config.set_authentication_policy(authn_policy) # ... config.add_route(login_route, login_path) config.add_view(login, route_name=login_route, check_csrf=True, renderer=’json’, permission=NO_PERMISSION_REQUIRED) # ... config.add_forbidden_view(forbidden) config.add_request_method(button, ’persona_button’, reify=True)
  14. Utiliser une lib Et l’utiliser, c’est ça : config.include(’pyramid_persona’) et

    éventuellement config.set_authorization_policy(another_authz_policy) config.add_view(another_login_view, route_name=’login’)
  15. Pendant ce temps, dans django L’utilisateur de la librairie s’occupe

    de chaque point d’entrée à la main To use django-browserid, you’ll need to make a few changes to your settings.py file : # Add ’django_browserid’ to INSTALLED_APPS. INSTALLED_APPS = ( # ... ’django.contrib.auth’, ’django_browserid’, # Load after auth # ... ) # Add the django_browserid authentication backend. AUTHENTICATION_BACKENDS = ( # ... ’django_browserid.auth.BrowserIDBackend’, # ... ) # Add the django_browserid context processor. TEMPLATE_CONTEXT_PROCESSORS = ( # ... ’django_browserid.context_processors.browserid’, # ... ) Next, edit your urls.py file and add the following : urlpatterns = patterns(’’, # ... (r’^browserid/’, include(’django_browserid.urls’)), # ... )
  16. Conclusion Pyramid est un framework très sympa avec un système

    d’extension très bien foutu. Il lui manque les rails, la base commune, pour avoir un écosystème comme celui de django, mais il est parfait pour construire d’autres framework (khufu, ptah, . . . ) qui, eux, fournissent des rails. En attendant, Pyramid est approprié pour les gens qui veulent un contrôle fin sur ce qu’ils font, ou qui font d’autres choix que ceux qu’impose Django.