SlideShare a Scribd company logo
Advanced Flask Patterns
                      PyCon Russia 2013

    — a presentation by Armin Ronacher
                              @mitsuhiko
-1   Who am I?
That's me
✤ Armin Ronacher

✤ @mitsuhiko

✤ Creator of Flask/Werkzeug/Jinja2
0   Focus & Caveats
Interrupt me
✤ Assumes some sense of Flask knowledge

✤ If too fast, interrupt me

✤ If not detailed enough, let me know
1   State Management
Flask States


✤ Setup State

✤ Application Context Bound

✤ Request Context Bound
Setup State



>>> from flask import g
>>> g.foo = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: working outside of application context
Application Bound


>>>   ctx = app.app_context()
>>>   ctx.push()
>>>   g.foo = 42
>>>   g.foo
42

>>> from flask import request
>>> request.args
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: working outside of request context
Request Bound


>>> ctx = app.test_request_context()
>>> ctx.push()
>>> request.url
'http://localhost/'
>>> g.foo = 42
>>> g.foo
42
Lifetimes


✤ flask.current_app ⇝ application context

✤ flask.g ⇝ application context (as of 0.10)

✤ flask.request ⇝ request context

✤ flask.session ⇝ request context
Quick Overview


✤ Application contexts are fast to create/destroy

✤ Pushing request context pushes new application context

✤ Flask 0.10 binds g to the application context

✤ Bind resources to the application context
2   Resource Management
Basic Guide


✤ Create/Destroy Application Context == Task

✤ Bind resources task wise

✤ Resources: claimed database connections, caches
Teardown Illustrated
>>>   from flask import Flask
>>>   app = Flask(__name__)
>>>   @app.teardown_appcontext
...   def called_on_teardown(error=None):
...     print 'Tearing down, error:', error
...

>>> ctx = app.app_context()
>>> ctx.push()
>>>
>>> ctx.pop()
Tearing down, error: None

>>> with app.app_context():
... 1/0
...
Tearing down, error: integer division or modulo by zero
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero
Resource Management

def get_database_connection():
    con = getattr(g, 'database_connection', None)
    if con is None:
        g.con = con = connection_pool.get_connection()
    return con


@app.teardown_appcontext
def return_database_connection(error=None):
    con = getattr(g, 'database_connection', None)
    if con is not None:
        connection_pool.release_connection(con)
Responsive Resources


@app.teardown_appcontext
def return_database_connection(error=None):
    con = getattr(g, 'database_connection', None)
    if con is None:
        return
    if error is None:
        con.commit()
    else:
        con.rollback()
    connection_pool.release_connection(con)
Per-Task Callbacks



def after_commit(f):
    callbacks = getattr(g, 'on_commit_callbacks', None)
    if callbacks is None:
        g.on_commit_callbacks = callbacks = []
    callbacks.append(f)
    return f
Per-Task Callbacks

@app.teardown_appcontext
def return_database_connection(error=None):
    con = getattr(g, 'database_connection', None)
    if con is None:
        return
    if error is None:
        con.commit()
        callbacks = getattr(g, 'on_commit_callbacks', ())
        for callback in callbacks:
            callback()
    else:
        con.rollback()
    connection_pool.release_connection(con)
Per-Task Callbacks Example


def purchase_product(product, user):
    user.purchased_products.append(product)
    @after_commit
    def send_success_mail():
        body = render_template('mails/product_purchased.txt',
            user=user,
            product=product
        )
        send_mail(user.email_address, 'Product Purchased', body)
3   Response Creation
Response Object Passing


✤ One request object: read only

✤ Potentially many response objects, passed down a stack

✤ … can be implicitly created

✤ … can be replaced by other response objects

✤ there is no flask.response!
Implicit Response Creation



@app.route('/')
def index():
    return render_template('index.html')
Explicit Creation


from flask import make_response


@app.route('/')
def index():
    body = render_template('index.html')
    response = make_response(body)
    response.headers['X-Powered-By'] = 'Not-PHP/1.0'
    return response
Customized Creation


from flask import Flask, jsonify


class CustomFlask(Flask):

    def make_response(self, rv):
        if hasattr(rv, 'to_json'):
            return jsonify(rv.to_json())
        return Flask.make_response(self, rv)
Customized Creation Example
class User(object):

    def __init__(self, id, username):
        self.id = id
        self.username = username

    def to_json(self):
        return {
            'id': self.id,
            'username': self.username
        }


app = CustomFlask(__name__)

@app.route('/')
def index():
    return User(42, 'john')
4   Server Sent Events
Basic Overview


✤ Open Socket

✤ Sends "data: <data>rnrn" packets

✤ Good idea for gevent/eventlet, bad idea for kernel level concurrency
Subscribing
from redis import Redis
from flask import Response, stream_with_context


redis = Redis()


@app.route('/streams/interesting')
def stream():
    def generate():
        pubsub = redis.pubsub()
        pubsub.subscribe('interesting-channel')
        for event in pubsub.listen():
            if event['type'] == 'message':
                yield 'data: %srnrn' % event['data']
    return Response(stream_with_context(generate()),
                    direct_passthrough=True,
                    mimetype='text/event-stream')
Publishing


from flask import json, redirect, url_for


@app.route('/create-something', methods=['POST'])
def create_something():
    create_that_thing()
    redis.publish('interesting-channel', json.dumps({
        'event': 'created',
        'kind': 'something'
    }))
    return redirect(url_for('index'))
Don't be Afraid of Proxying


✤ gunicorn/uwsgi blocking for main app

✤ gunicorn gevent for SSE

✤ nginx for unification
5   Worker Separation
supervisor config



[program:worker-blocking]
command=gunicorn -w 4 yourapplication:app -b 0.0.0.0:8000

[program:worker-nonblocking]
command=gunicorn -k gevent -w 4 yourapplication:app -b 0.0.0.0:8001
nginx config

server {
    listen 80;
    server_name example.com;

    location /streams {
        proxy_set_header Host $http_host;
        proxy_pass http://localhost:8001/streams;
    }

    location / {
        proxy_set_header Host $http_host;
        proxy_pass http://localhost:8000/;
    }
}
6   Signing Stuff
Basic Overview


✤ Use itsdangerous for signing information that roundtrips

✤ Saves you from storing information in a database

✤ Especially useful for small pieces of information that need to stay
  around for long (any form of token etc.)
User Activation Example
from flask import abort
import itsdangerous


serializer = itsdangerous .URLSafeSerializer(secret_key=app.config['SECRET_KEY'])
ACTIVATION_SALT = 'x7fxfbxc2(;rxa8Ox16{'


def get_activation_link(user):
    return url_for('activate', code=serializer.dumps(user.user_id, salt=ACTIVATION_SALT))


@app.route('/activate/<code>')
def activate(code):
    try:
         user_id = serializer.loads(code, salt=ACTIVATION_SALT)
    except itsdangerous.BadSignature:
         abort(404)
    activate_the_user_with_id(user_id)
7   Customization
Simple Cache Busting

from hashlib import md5
import pkg_resources


ASSET_REVISION = md5(str(pkg_resources.get_distribution(
    'Package-Name').version)).hexdigest())[:14]


@app.url_defaults
def static_cache_buster(endpoint, values):
    if endpoint == 'static':
        values['_v'] = ASSET_REVISION
Disable Parsing


from flask import Flask, Request


class SimpleRequest(Request):
    want_form_data_parsed = False
    data = None


app = Flask(__name__)
app.request_class = SimpleRequest
8   Secure Redirects
Redirect Back
from urlparse import urlparse, urljoin

def is_safe_url(target):
    ref_url = urlparse(request.host_url)
    test_url = urlparse(urljoin(request.host_url, target))
    return test_url.scheme in ('http', 'https') and 
           ref_url.netloc == test_url.netloc

def is_different_url(url):
    this_parts = urlparse(request.url)
    other_parts = urlparse(url)
    return this_parts[:4] != other_parts[:4] and 
        url_decode(this_parts.query) != url_decode(other_parts.query)

def redirect_back(fallback):
    next = request.args.get('next') or request.referrer
    if next and is_safe_url(next) and is_different_url(next):
        return redirect(next)
    return redirect(fallback)
Q&A
 http://fireteam.net/ — Armin Ronacher — @mitsuhiko

More Related Content

What's hot (20)

PDF
Web develop in flask
Jim Yeh
 
PDF
Flask RESTful Flask HTTPAuth
Eueung Mulyana
 
PPTX
Build restful ap is with python and flask
Jeetendra singh
 
PDF
Flask Introduction - Python Meetup
Areski Belaid
 
PDF
Python RESTful webservices with Python: Flask and Django solutions
Solution4Future
 
PDF
Flask SQLAlchemy
Eueung Mulyana
 
PPTX
Flask restfulservices
Marcos Lin
 
PPT
Learn flask in 90mins
Larry Cai
 
PDF
BUILDING MODERN PYTHON WEB FRAMEWORKS USING FLASK WITH NEIL GREY
CodeCore
 
PDF
Quick flask an intro to flask
juzten
 
PDF
Bootstrat REST APIs with Laravel 5
Elena Kolevska
 
PDF
Getting Started-with-Laravel
Mindfire Solutions
 
PDF
Rest api with Python
Santosh Ghimire
 
PPTX
Laravel 5
Sudip Simkhada
 
PPTX
REST APIs in Laravel 101
Samantha Geitz
 
PDF
Building a Dynamic Website Using Django
Nathan Eror
 
PDF
8 Minutes On Rack
danwrong
 
PDF
Laravel Design Patterns
Bobby Bouwmann
 
PDF
Python Flask app deployed to OPenShift using Wercker CI
Bruno Rocha
 
PDF
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
Web develop in flask
Jim Yeh
 
Flask RESTful Flask HTTPAuth
Eueung Mulyana
 
Build restful ap is with python and flask
Jeetendra singh
 
Flask Introduction - Python Meetup
Areski Belaid
 
Python RESTful webservices with Python: Flask and Django solutions
Solution4Future
 
Flask SQLAlchemy
Eueung Mulyana
 
Flask restfulservices
Marcos Lin
 
Learn flask in 90mins
Larry Cai
 
BUILDING MODERN PYTHON WEB FRAMEWORKS USING FLASK WITH NEIL GREY
CodeCore
 
Quick flask an intro to flask
juzten
 
Bootstrat REST APIs with Laravel 5
Elena Kolevska
 
Getting Started-with-Laravel
Mindfire Solutions
 
Rest api with Python
Santosh Ghimire
 
Laravel 5
Sudip Simkhada
 
REST APIs in Laravel 101
Samantha Geitz
 
Building a Dynamic Website Using Django
Nathan Eror
 
8 Minutes On Rack
danwrong
 
Laravel Design Patterns
Bobby Bouwmann
 
Python Flask app deployed to OPenShift using Wercker CI
Bruno Rocha
 
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 

Viewers also liked (17)

PDF
Build website in_django
swee meng ng
 
PPTX
Quokka CMS - Desenvolvendo web apps com Flask e MongoDB - grupy - Outubro 2015
Bruno Rocha
 
PPTX
webアプリケーションフレームワークの話
Yoshihiro Ura
 
PDF
aiohttp intro
Anton Kasyanov
 
PDF
Rest in flask
Hamid Feizabadi
 
PPTX
Webアプリケーションフレームワーク flask
XMLProJ2014
 
PDF
Flask Full Stack - Desenvolvendo um CMS com Flask e MongoDB
Bruno Rocha
 
PDF
Python and GIS
Andrii Mishkovskyi
 
PDF
Writing your first web app using Python and Flask
Danielle Madeley
 
PPTX
Introduction to Google App Engine with Python
Brian Lyttle
 
PDF
Flask入門
aoshiman
 
PDF
Flask勉強会その1
Masato Kawamura
 
PDF
Making use of OpenStreetMap data with Python
Andrii Mishkovskyi
 
PPTX
Thermo Electric Converter
MakeNET
 
PPTX
Modes of transfer of heat
Kabir Kanha Arora
 
PPTX
Modes of heat transfer
RIFFAT_ZAHID
 
PPTX
OpenStreetMap in 3D using Python
Martin Christen
 
Build website in_django
swee meng ng
 
Quokka CMS - Desenvolvendo web apps com Flask e MongoDB - grupy - Outubro 2015
Bruno Rocha
 
webアプリケーションフレームワークの話
Yoshihiro Ura
 
aiohttp intro
Anton Kasyanov
 
Rest in flask
Hamid Feizabadi
 
Webアプリケーションフレームワーク flask
XMLProJ2014
 
Flask Full Stack - Desenvolvendo um CMS com Flask e MongoDB
Bruno Rocha
 
Python and GIS
Andrii Mishkovskyi
 
Writing your first web app using Python and Flask
Danielle Madeley
 
Introduction to Google App Engine with Python
Brian Lyttle
 
Flask入門
aoshiman
 
Flask勉強会その1
Masato Kawamura
 
Making use of OpenStreetMap data with Python
Andrii Mishkovskyi
 
Thermo Electric Converter
MakeNET
 
Modes of transfer of heat
Kabir Kanha Arora
 
Modes of heat transfer
RIFFAT_ZAHID
 
OpenStreetMap in 3D using Python
Martin Christen
 
Ad

Similar to Flask patterns (20)

PDF
Flask Web Development 1st Edition Miguel Grinberg
cjvsgfu2766
 
PPTX
Flask-Python
Triloki Gupta
 
PDF
Python Web Applications With Flask Handon Your Flask Skills2024 Jeffrey Leon ...
keyroreagan
 
PPTX
Flask & Flask-restx
ammaraslam18
 
PDF
Flask docs
Kunal Sangwan
 
PPTX
Intro to flask2
Mohamed Essam
 
PPTX
Intro to flask
Mohamed Essam
 
PDF
Introduction to Flask Micro Framework
Mohammad Reza Kamalifard
 
PPTX
Flask
Mamta Kumari
 
PDF
Flask jwt authentication tutorial
Katy Slemon
 
PPTX
Flask Application ppt to understand the flask
vijoho5545
 
PDF
Python and Flask introduction for my classmates Презентация и введение в flask
Nikita Lozhnikov
 
PDF
Introduction to rest using flask
Wekanta
 
PDF
Flask intro - ROSEdu web workshops
Alex Eftimie
 
PDF
Google app-engine-with-python
Deepak Garg
 
PDF
Asynchronous Architectures for Implementing Scalable Cloud Services - Evan Co...
Twilio Inc
 
PDF
The New And Improved Flask Mega-Tutorial Miguel Grinberg
bumpbgsyyy017
 
PDF
Python Load Testing - Pygotham 2012
Dan Kuebrich
 
ODP
Build and Deploy a Python Web App to Amazon in 30 Mins
Jeff Hull
 
Flask Web Development 1st Edition Miguel Grinberg
cjvsgfu2766
 
Flask-Python
Triloki Gupta
 
Python Web Applications With Flask Handon Your Flask Skills2024 Jeffrey Leon ...
keyroreagan
 
Flask & Flask-restx
ammaraslam18
 
Flask docs
Kunal Sangwan
 
Intro to flask2
Mohamed Essam
 
Intro to flask
Mohamed Essam
 
Introduction to Flask Micro Framework
Mohammad Reza Kamalifard
 
Flask jwt authentication tutorial
Katy Slemon
 
Flask Application ppt to understand the flask
vijoho5545
 
Python and Flask introduction for my classmates Презентация и введение в flask
Nikita Lozhnikov
 
Introduction to rest using flask
Wekanta
 
Flask intro - ROSEdu web workshops
Alex Eftimie
 
Google app-engine-with-python
Deepak Garg
 
Asynchronous Architectures for Implementing Scalable Cloud Services - Evan Co...
Twilio Inc
 
The New And Improved Flask Mega-Tutorial Miguel Grinberg
bumpbgsyyy017
 
Python Load Testing - Pygotham 2012
Dan Kuebrich
 
Build and Deploy a Python Web App to Amazon in 30 Mins
Jeff Hull
 
Ad

More from it-people (20)

PDF
«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co
it-people
 
PDF
«Scrapy internals» Александр Сибиряков, Scrapinghub
it-people
 
PDF
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains
it-people
 
PDF
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
it-people
 
PDF
«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс
it-people
 
PDF
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...
it-people
 
PDF
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr
it-people
 
PDF
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
it-people
 
PDF
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
it-people
 
PDF
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
it-people
 
PDF
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
it-people
 
PDF
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
it-people
 
PDF
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
it-people
 
PDF
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
it-people
 
PDF
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
it-people
 
PDF
«(Без)опасный Python», Иван Цыганов, Positive Technologies
it-people
 
PDF
«Python of Things», Кирилл Борисов, Яндекс
it-people
 
PDF
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
it-people
 
PDF
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
it-people
 
PDF
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
it-people
 
«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co
it-people
 
«Scrapy internals» Александр Сибиряков, Scrapinghub
it-people
 
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains
it-people
 
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
it-people
 
«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс
it-people
 
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...
it-people
 
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr
it-people
 
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
it-people
 
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
it-people
 
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
it-people
 
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
it-people
 
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
it-people
 
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
it-people
 
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
it-people
 
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
it-people
 
«(Без)опасный Python», Иван Цыганов, Positive Technologies
it-people
 
«Python of Things», Кирилл Борисов, Яндекс
it-people
 
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
it-people
 
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
it-people
 
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
it-people
 

Flask patterns

  • 1. Advanced Flask Patterns PyCon Russia 2013 — a presentation by Armin Ronacher @mitsuhiko
  • 2. -1 Who am I?
  • 3. That's me ✤ Armin Ronacher ✤ @mitsuhiko ✤ Creator of Flask/Werkzeug/Jinja2
  • 4. 0 Focus & Caveats
  • 5. Interrupt me ✤ Assumes some sense of Flask knowledge ✤ If too fast, interrupt me ✤ If not detailed enough, let me know
  • 6. 1 State Management
  • 7. Flask States ✤ Setup State ✤ Application Context Bound ✤ Request Context Bound
  • 8. Setup State >>> from flask import g >>> g.foo = 42 Traceback (most recent call last): File "<stdin>", line 1, in <module> RuntimeError: working outside of application context
  • 9. Application Bound >>> ctx = app.app_context() >>> ctx.push() >>> g.foo = 42 >>> g.foo 42 >>> from flask import request >>> request.args Traceback (most recent call last): File "<stdin>", line 1, in <module> RuntimeError: working outside of request context
  • 10. Request Bound >>> ctx = app.test_request_context() >>> ctx.push() >>> request.url 'http://localhost/' >>> g.foo = 42 >>> g.foo 42
  • 11. Lifetimes ✤ flask.current_app ⇝ application context ✤ flask.g ⇝ application context (as of 0.10) ✤ flask.request ⇝ request context ✤ flask.session ⇝ request context
  • 12. Quick Overview ✤ Application contexts are fast to create/destroy ✤ Pushing request context pushes new application context ✤ Flask 0.10 binds g to the application context ✤ Bind resources to the application context
  • 13. 2 Resource Management
  • 14. Basic Guide ✤ Create/Destroy Application Context == Task ✤ Bind resources task wise ✤ Resources: claimed database connections, caches
  • 15. Teardown Illustrated >>> from flask import Flask >>> app = Flask(__name__) >>> @app.teardown_appcontext ... def called_on_teardown(error=None): ... print 'Tearing down, error:', error ... >>> ctx = app.app_context() >>> ctx.push() >>> >>> ctx.pop() Tearing down, error: None >>> with app.app_context(): ... 1/0 ... Tearing down, error: integer division or modulo by zero Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: integer division or modulo by zero
  • 16. Resource Management def get_database_connection(): con = getattr(g, 'database_connection', None) if con is None: g.con = con = connection_pool.get_connection() return con @app.teardown_appcontext def return_database_connection(error=None): con = getattr(g, 'database_connection', None) if con is not None: connection_pool.release_connection(con)
  • 17. Responsive Resources @app.teardown_appcontext def return_database_connection(error=None): con = getattr(g, 'database_connection', None) if con is None: return if error is None: con.commit() else: con.rollback() connection_pool.release_connection(con)
  • 18. Per-Task Callbacks def after_commit(f): callbacks = getattr(g, 'on_commit_callbacks', None) if callbacks is None: g.on_commit_callbacks = callbacks = [] callbacks.append(f) return f
  • 19. Per-Task Callbacks @app.teardown_appcontext def return_database_connection(error=None): con = getattr(g, 'database_connection', None) if con is None: return if error is None: con.commit() callbacks = getattr(g, 'on_commit_callbacks', ()) for callback in callbacks: callback() else: con.rollback() connection_pool.release_connection(con)
  • 20. Per-Task Callbacks Example def purchase_product(product, user): user.purchased_products.append(product) @after_commit def send_success_mail(): body = render_template('mails/product_purchased.txt', user=user, product=product ) send_mail(user.email_address, 'Product Purchased', body)
  • 21. 3 Response Creation
  • 22. Response Object Passing ✤ One request object: read only ✤ Potentially many response objects, passed down a stack ✤ … can be implicitly created ✤ … can be replaced by other response objects ✤ there is no flask.response!
  • 23. Implicit Response Creation @app.route('/') def index(): return render_template('index.html')
  • 24. Explicit Creation from flask import make_response @app.route('/') def index(): body = render_template('index.html') response = make_response(body) response.headers['X-Powered-By'] = 'Not-PHP/1.0' return response
  • 25. Customized Creation from flask import Flask, jsonify class CustomFlask(Flask): def make_response(self, rv): if hasattr(rv, 'to_json'): return jsonify(rv.to_json()) return Flask.make_response(self, rv)
  • 26. Customized Creation Example class User(object): def __init__(self, id, username): self.id = id self.username = username def to_json(self): return { 'id': self.id, 'username': self.username } app = CustomFlask(__name__) @app.route('/') def index(): return User(42, 'john')
  • 27. 4 Server Sent Events
  • 28. Basic Overview ✤ Open Socket ✤ Sends "data: <data>rnrn" packets ✤ Good idea for gevent/eventlet, bad idea for kernel level concurrency
  • 29. Subscribing from redis import Redis from flask import Response, stream_with_context redis = Redis() @app.route('/streams/interesting') def stream(): def generate(): pubsub = redis.pubsub() pubsub.subscribe('interesting-channel') for event in pubsub.listen(): if event['type'] == 'message': yield 'data: %srnrn' % event['data'] return Response(stream_with_context(generate()), direct_passthrough=True, mimetype='text/event-stream')
  • 30. Publishing from flask import json, redirect, url_for @app.route('/create-something', methods=['POST']) def create_something(): create_that_thing() redis.publish('interesting-channel', json.dumps({ 'event': 'created', 'kind': 'something' })) return redirect(url_for('index'))
  • 31. Don't be Afraid of Proxying ✤ gunicorn/uwsgi blocking for main app ✤ gunicorn gevent for SSE ✤ nginx for unification
  • 32. 5 Worker Separation
  • 33. supervisor config [program:worker-blocking] command=gunicorn -w 4 yourapplication:app -b 0.0.0.0:8000 [program:worker-nonblocking] command=gunicorn -k gevent -w 4 yourapplication:app -b 0.0.0.0:8001
  • 34. nginx config server { listen 80; server_name example.com; location /streams { proxy_set_header Host $http_host; proxy_pass http://localhost:8001/streams; } location / { proxy_set_header Host $http_host; proxy_pass http://localhost:8000/; } }
  • 35. 6 Signing Stuff
  • 36. Basic Overview ✤ Use itsdangerous for signing information that roundtrips ✤ Saves you from storing information in a database ✤ Especially useful for small pieces of information that need to stay around for long (any form of token etc.)
  • 37. User Activation Example from flask import abort import itsdangerous serializer = itsdangerous .URLSafeSerializer(secret_key=app.config['SECRET_KEY']) ACTIVATION_SALT = 'x7fxfbxc2(;rxa8Ox16{' def get_activation_link(user): return url_for('activate', code=serializer.dumps(user.user_id, salt=ACTIVATION_SALT)) @app.route('/activate/<code>') def activate(code): try: user_id = serializer.loads(code, salt=ACTIVATION_SALT) except itsdangerous.BadSignature: abort(404) activate_the_user_with_id(user_id)
  • 38. 7 Customization
  • 39. Simple Cache Busting from hashlib import md5 import pkg_resources ASSET_REVISION = md5(str(pkg_resources.get_distribution( 'Package-Name').version)).hexdigest())[:14] @app.url_defaults def static_cache_buster(endpoint, values): if endpoint == 'static': values['_v'] = ASSET_REVISION
  • 40. Disable Parsing from flask import Flask, Request class SimpleRequest(Request): want_form_data_parsed = False data = None app = Flask(__name__) app.request_class = SimpleRequest
  • 41. 8 Secure Redirects
  • 42. Redirect Back from urlparse import urlparse, urljoin def is_safe_url(target): ref_url = urlparse(request.host_url) test_url = urlparse(urljoin(request.host_url, target)) return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc def is_different_url(url): this_parts = urlparse(request.url) other_parts = urlparse(url) return this_parts[:4] != other_parts[:4] and url_decode(this_parts.query) != url_decode(other_parts.query) def redirect_back(fallback): next = request.args.get('next') or request.referrer if next and is_safe_url(next) and is_different_url(next): return redirect(next) return redirect(fallback)
  • 43. Q&A http://fireteam.net/ — Armin Ronacher — @mitsuhiko