Developing Flask Extensions
-
Upload
rachel-sanders -
Category
Technology
-
view
640 -
download
1
description
Transcript of Developing Flask Extensions
DEVELOPING FLASK EXTENSIONS
Rachel Sanders @ PyTennessee 2014
Rachel Sanders Engineer at LinkedIn & PyLadiesSF
organizer Our internal stack: Python + Flask Team lead for a 30K LOC Flask app
What we talkin’ about The really really really quick intro to
Flask The really really quick intro to extending
Flask Flask-FeatureFlags: a case study Beyond the Basics Questions
Like 3 min tops, promise
The really really quick intro to Flask
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello San Dimas High!"
if __name__ == "__main__":
app.run()
whaaaaaaa? No database?? No forms? No admin interface?
“The idea of Flask is to build a good foundation for all
applications. Everything else is up to you or
extensions.” -- Armin Ronacher, creator of
Flask
All these are extensions database SQLAlchemy + Flask-
SQLAlchemy forms WTForms + FlaskWTF admin Flask-Admin
Like 5 min, promise
The really quick intro to extending Flask
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello San Dimas High!"
if __name__ == "__main__":
app.run()
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello San Dimas High!"
if __name__ == "__main__":
app.run()
extending Flask
= changing app
You can change the app object by
Hooking into request lifecycle Adding more resources
Jinja filters, tests, global variables Routes, blueprints, static files
Middleware Monkeypatching
with the power to turn code on or off
Flask-FeatureFlags
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello San Dimas High!”
from flask import Flask
import flask_featureflags as feature
app = Flask(__name__)
feature_flag = feature.FeatureFlag(app)
@app.route("/")
def hello():
return "Hello San Dimas High!"
from flask import Flask
import flask_featureflags as feature
app = Flask(__name__)
feature_flag = feature.FeatureFlag(app)
@app.route("/")
def hello():
if feature.is_active('pytennessee'):
return "Hello PyTennessee!"
else:
return "Hello San Dimas High!"
from flask import Flask
import flask_featureflags as feature
app = Flask(__name__)
feature_flag = feature.FeatureFlag(app)
app.config['FEATURE_FLAGS']['pytennessee'] = True
@app.route("/")
def hello():
if feature.is_active('pytennessee'):
return "Hello PyTennessee!"
else:
return "Hello San Dimas High!"
{% if 'pytennesse' is active_feature %} “Hi PyTennessee!”{% else %} “Hello San Dimas High!”{% endif %}
FEATURE FLAG SPEC
feature flags stored in config Jinja template test called “active_feature” Module function called “is_active”
class FeatureFlags(object):
class FeatureFlags(object):
def __init__(self, app=None):
class FeatureFlags(object):
def __init__(self, app=None): if app is not None: self.init_app(app)
def init_app(self, app):
class FeatureFlags(object):
def __init__(self, app=None): if app is not None: self.init_app(app)
def init_app(self, app):
app.config.setdefault('FEATURE_FLAGS’, {})
from flask import current_app
class FeatureFlags(object):
def __init__(self, app=None): if app is not None: self.init_app(app)
def init_app(self, app):
app.config.setdefault('FEATURE_FLAGS’, {})
def in_config(self, feature): try: return current_app.config['FEATURE_FLAGS'][feature] except (AttributeError, KeyError): return False
FEATURE FLAGS SPEC
feature flags stored in config Jinja template test is_active function
{% if 'pytennesse' is active_feature %} “Hi PyTennessee!”{% else %} “Hello San Dimas High!”{% endif %}
from flask import current_appclass FeatureFlags(object):
def __init__(self, app=None): if app is not None: self.init_app(app)
def init_app(self, app):
app.config.setdefault('FEATURE_FLAGS’, {})
app.add_template_test(self.in_config, name=’active_feature’)
def in_config(self, feature): try: return current_app.config['FEATURE_FLAGS'][feature] except (AttributeError, KeyError): return False
class FeatureFlags(object):
def __init__(self, app=None): if app is not None: self.init_app(app)
def init_app(self, app):
app.config.setdefault('FEATURE_FLAGS’, {})
if hasattr(app, "add_template_test"): app.add_template_test(self.in_config, name='active_feature') else: app.jinja_env.tests[’active_feature’] = self.in_config
FEATURE FLAGS SPEC
feature flags stored in config Jinja template test is_active function
from flask import Flask
import flask_featureflags as feature
app = Flask(__name__)
feature_flag = feature.FeatureFlag(app)
app.config['FEATURE_FLAGS']['pytennessee'] = True
@app.route("/")
def hello():
if feature.is_active('pytennessee'):
return "Hello PyTennessee!"
else:
return "Hello San Dimas High!"
class FeatureFlags(object):
def __init__(self, app=None): if app is not None: self.init_app(app)
def init_app(self, app):
app.config.setdefault('FEATURE_FLAGS’, {})
if hasattr(app, "add_template_test"): app.add_template_test(self.in_config, name='active_feature') else: app.jinja_env.tests[’active_feature’] = self.in_config
app.extensions['FeatureFlags'] = self
from flask import current_app
def is_active(feature): feature_flagger = current_app.extensions['FeatureFlags'] return feature_flagger.in_config(feature)
FEATURE FLAGS SPEC
feature flags stored in config Jinja template test is_active function
ok so what’d we learn? use init_app because app factories be sure to set config defaults calling Flask hooks 0.10+ is a trap how to get to our extension later
ok what now lady
Beyond the basics
http://flask-debugtoolbar.readthedocs.org/
Flask-DebugToolbar
other great extensions Flask-SeaSurf – request processing,
cookies Flask-Admin – SQLAlchemy, blueprints,
static files Flask-Classy – adds class-based views
thanks everybody! @trustrachel github.com/trustrachel trustrachel.com