AppEngine + Python - 29.03.2012 Python Web Frameworks & App Engine
AppEngine + Python - 29.03.2012
Python Web Frameworks&
App Engine
AppEngine + Python - 29.03.2012
Python Web Development
● Web Server Gateway Interface (WSGI): Standard Ufficiale (PEP 333) formalizzato nel 2003 definisce il modo con cui un applicazione Python deve comunicare con il webserver.
def simple_app(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return ['Hello world!\n']
● WSGI Request and Response Objects (WebOb): Standard de facto, definisce un oggetto Request ed uno Response come astrazione su WSGI.
from webob import Request, Response
def simple_app(environ, start_response): req = Request(environ) resp = Response() resp.content_type = 'text/plain' resp.body = 'Hello World' return resp(environ, start_response)
AppEngine + Python - 29.03.2012
Serving WSGI Applications
● Python include il modulo wsgiref che implementa un webserver compatibile WSGI. Python da solo sarebbe quindi già autosufficiente per lo sviluppo web
from wsgiref.util import setup_testing_defaultsfrom wsgiref.simple_server import make_server
# A relatively simple WSGI application. It's going to print out the# environment dictionary after being updated by setup_testing_defaultsdef simple_app(environ, start_response): setup_testing_defaults(environ) status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) ret = ["%s: %s\n" % (key, value) for key, value in environ.iteritems()] return ret
httpd = make_server('', 8000, simple_app)print "Serving on port 8000..."httpd.serve_forever()
AppEngine + Python - 29.03.2012
Python Web Frameworks
WebOb Based● Pylons: Un tempo il secondo
webframework Python più famoso dopo Django è ora in legacy mode.
● Pyramid: Successore di Pylons è un framework di medio/basso livello per applicazioni web ad alte performance.
● TurboGears2: Nato come layer di alto livello su Pylons è ora un framework indipendente per lo sviluppo rapido. Cerca di mantenere comunque una propensione alle customizzazioni
● AppEngine
Others● Django: E' il framework più
famoso su Python ed è totalmente orientato allo sviluppo rapido.
● Flask: Assieme a Pyramid è il framework più usato per applicazioni custom di medio/basso livello. Basato su Werkzeug che è il principale antagonista di WebOb
Altri: Bottle, Web2Py, Web.Py, etc: http://wiki.python.org/moin/WebFrameworks
https://www.djangoproject.com
The Web framework for perfectionists with deadlines
● Framework completamente custom● Incentiva fortemente il riutilizzo di componenti ready made tramite l'uso di un sistema di
applicazioni pluggable● La velocità non è il suo principale focus, tuttavia si difende bene battendo in velocità soluzioni
come Ruby On Rails.● Dispatch: Regular Expressions● Template Engine: Custom, non XML● ORM: Custom, molto facile da usare ha il difetto di rendere impossibili query molto complesse.
Di default l'orm non è transazionale.● Forms: Custom, supportano generazione automatica dal modello● Validazione: Custom, Builtin solo per i form● Feature Builtin: Django Admin (autogenerazione sezioni ammnistrative), Caching, Sessions,
Load Balancing, Identificazione, Autorizzazione e Autenticazione
AppEngine + Python - 29.03.2012
Django
http://www.pylonsproject.org
Web Development with style your way.
● Nato come riscrittura di Pylons● Totalmente incentrato sulle performance, flessibilità e potenza di sviluppo● Piccole applicazioni sono rapidamente sviluppabili, per quelle grandi molto lavoro è lasciato al
programmatore.● E' attualmente uno dei framework più discussi per le sua incredibile flessibilità e performance
che superano quelle della maggior parte delle tecnologie web disponibili● Dispatch: Regular Expressions o Traversal● Template Engine: Default ZPT e Mako● ORM: SQLAlchemy o ZODB● Forms: Nessuno● Validazione: Nessuno● Feature Builtin: Autenticazione e Autorizzazione● L'assenza di Forms, Validazione etc di default non vuole dire che non si possano fare, ma solo
che bisogna usare librerie esterne.● In Pyramid esistono gli Scaffold che sono "preconfigurazioni" del framework con specifici
ORM, Templates ed altre librerie. I più famosi sono Khufu, Akhet, etc...
AppEngine + Python - 29.03.2012
Pyramid
http://www.turbogears.org
The next generation web framework that scales with you
● Nato come framework di alto livello per Pylons● Come Django il principale obiettivo di TurboGears è permettere il rapido sviluppo di
applicazioni web complesse, tuttavia fornisce anche una grande attenzione agli utenti avanzati permettendo di customizzare a basso livello quasi tutto.
● Dispatch: Object Dispatch● Template Engine: Genshi e Mako. Supporta nativamente anche Jinja e Kajiki. Di default è
scelto Genshi che è XML compliant● ORM: SQLAlchemy configurato con Unit of Work in modalità transazionale● Forms: ToscaWidgets● Validazione: Builtin per tutto con validatori FormEncode o ToscaWidgets● Feature Builtin: JSON output, Caching, Sessioni, Identificazione, Autenticazione,
Autorizzazione, TurboGears Admin e tgext.crud per autogenerazione CRUD, Database Migrations, MongoDB Support.
AppEngine + Python - 29.03.2012
TurboGears2
http://flask.pocoo.org
web development one drop at time
● Come Pyramid il suo focus principale è la flessibilità e performance.● Nasce con poche cose builtin nel framework, ma è dotato di estensioni di ogni genere.● Dispatch: Regular Expressions● Template Engine: Jinja● ORM: Nessuno, ma flask_sqlalchemy (SQLAlchemy) è praticamente lo standard.● Forms: Nessuno, ma flask_wtf (WTForms) è praticamente lo standard● Validazione: Nessuno, ma flask_wtf fornisce anche validazione● Feature Builtin: Praticamente nessuna, ma come Pyramid la filosofia orientata alla flessibilità
ha creato un notevole numero di estensioni già pronte all'uso per molte funzionalità.
AppEngine + Python - 29.03.2012
Flask
AppEngine + Python - 29.03.2012
AppEngine + Python - 29.03.2012
Perché Google App Engine
1. Semplicità di deploy:a. scrivo il codice;b. effettuo il deploy lanciando un comando o premendo
un pulsante nel launcher (win o osx);c. il versioning permette di gestire gli ambienti di test;
2. Gratis per webapp di discrete dimensioni:a. 1GB stored data;b. 1GB/day outgoing & incoming bandwidthc. 28 instance hours/day;
3. Affidabilità:a. L'HRD ha chiuso il 2011 con il 99,999% di uptime;
4. Dashboard;
AppEngine + Python - 29.03.2012
Perché Python su GAE
1. Performances:a. le JVM basate sul JIT soffrono di lunghi tempi di
startup. Su App Engine il costo di startup è pagato molto spesso (le istanze vengono accese, spente, spostate in modo trasparente);
b. JDO e JPA sono più lente di 3-5 volte rispetto alla Datastore API Python (crud test: http://gaejava.appspot.com/)
2. Runtime più avanzato:a. Threads e Concurrent Requests (esclusiva di python2.
7)b. Google Cloud Storage, NDB, MapReduce, protoRPC e
LogService APIs3. "The Python Paradox"
AppEngine + Python - 29.03.2012
GAE Python SDKPython 2.5 CGI interface Python 2.7 WSGI interface
main.py main.py
app.yaml app.yaml
AppEngine + Python - 29.03.2012
Request Handler & Url Dispatch
AppEngine + Python - 29.03.2012
Templating Jinja2
http://dl.dropbox.com/u/7050474/gtug_app.zip
Usando python27 è necessario dichiarare nell'app.yaml le librerie che si intendono utilizzare: https://developers.google.com/appengine/docs/python/python27/using27#Configuring_Libraries
AppEngine + Python - 29.03.2012
Templating Jinja2
mai
n.py
para
ms_
hand
ler.h
tml
AppEngine + Python - 29.03.2012
Storing Datafrom google.appengine.ext import dbimport webapp2import jinja2import os
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class Message(db.Model): title = db.StringProperty() msg = db.StringProperty() when = db.DateTimeProperty(auto_now=True)
class MainHandler(webapp2.RequestHandler): def get(self): self.response.out.write('Hello world!')
class ParamsHandler(webapp2.RequestHandler): def get(self): title = self.request.get('title') msg = self.request.get('msg') #store the data stored_msg = Message(title=title, msg=msg) ## or we can use: #stored_msg = Message() #message.title = title #message.msg = msg ## --- stored_msg.put()
template = jinja_env.get_template('params_handler.html') self.response.out.write(template.render({'title': title, 'message': msg}))
AppEngine + Python - 29.03.2012
Querying the Datastore
class RetrieveParams(webapp2.RequestHandler): def get(self): #query using the query object interface messages = db.Query(Message).order('-when')
#query using GQL messages2 = db.GqlQuery('select * from Message order by when desc')
self.response.headers['Content-Type'] = 'text/plain' self.response.out.write('\n'.join([' | '.join((msg.title, msg.msg, str(msg.when))) for msg in messages2]))
application = webapp2.WSGIApplication([('/', MainHandler), ('/params_handler[0-9]?', ParamsHandler), ('/retrieve_params', RetrieveParams)], debug=True)
AppEngine + Python - 29.03.2012
AppEngine + Python - 29.03.2012
Perché TurboGears21. Object Dispatch:
a. Il sistema di routing è molto chiaro, guardando un URL si sa subito dove è implementata e non bisogna "litigare" con le regular expressions
2. Rapidità di Sviluppo:a. Il framework fornisce immediatamente login,
permessi, validazione, debugging etc.b. tgext.crud e turbogears admin permettono di creare
applicazioni web semplici in automatico.c. Il supporto nativo a ToscaWidgets permette di creare
al volo componenti e Widgets riusabili.3. Gestione Errori:
a. L'uso di un template XML previene errori di HTMLb. Il framework fornisce debugging interattivo del codice
in caso di 500 e post mortem report in produzione.c. La unit of work transazionale impedisce di mettere in
stato inconsistente il database in caso di crash.
AppEngine + Python - 29.03.2012
TurboGears2 Overview
CONTROLLERclass RootController(BaseController): error = ErrorController()
@expose('wiki20.templates.index') def index(self): return dict(page='index')
MODELLIclass Page(DeclarativeBase): __tablename__ = 'pages' id = Column(Integer, primary_key=True) pagename = Column(Text, unique=True) data = Column(Text)
TEMPLATE<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="master.html" />
<head> <title>My Title</title></head>
<body> <h1>${page}</h1> <div py:for="entry in entries">${entry.name}</div></body></html>
AppEngine + Python - 29.03.2012
Object Dispatchclass BlogEntryController(BaseController): @expose() def index(self, post): pass
@expose() def edit(self, post): pass
@expose() def update(self, post): pass
class RootController(BaseController): blog = BlogEntryController()
@expose() def index(self): pass
@expose() def about(self): pass
@expose() def more(self, *args, **kw): pass
URL CONTROLLER
/index RootController.index
/ RootController.index
/blog/3 BlogEntryController.index (post = 3)
/blog/update?post=3 BlogEntryController.update (post = 3)
/about RootController.about
/more/1/2/3 RootController.more(args[0]=1, args[1]=2, args[3]=3)
/more?data=5 RootController.more(kw['data']=5)
AppEngine + Python - 29.03.2012
Deploy1. Paste non richiede configurazioni particolari, ma non è
proprio veloce
2. Apache fornisce supporto nativo per TurboGears2 tramite mod_wsgi.
3. Bello, ma faticoso...a. RedHat OpenShift!b. Git come sistema di deploy: "git push"c. Cloud Solution simile ad AppEngined. La soluzione Express è gratuita.e. TurboGears2 è largamente usato dal progetto Fedora
per molti dei suoi siti, quindi è supportato nativamente da OpenShift. Le uniche due guide ufficiali passo passo esistenti per openshift con Python sono proprio per TurboGears2 e Pyramid.
f. https://openshift.redhat.com/app/express
AppEngine + Python - 29.03.2012
Hands On, quickstarting a TG2 Application