A Flask extension that enables or disables features based on configuration.

Overview

Flask FeatureFlags

PyPI version Build Status Coverage Status

This is a Flask extension that adds feature flagging to your applications. This lets you turn parts of your site on or off based on configuration.

It's useful for any setup where you deploy from trunk but want to hide unfinished features from your users, such as continuous integration builds.

You can also extend it to do simple a/b testing or whitelisting.

Installation

Installation is easy with pip:

pip install flask_featureflags

To install from source, download the source code, then run this:

python setup.py install

Flask-FeatureFlags supports Python 2.6, 2.7, and 3.3+ with experimental support for PyPy.

Version 0.1 of Flask-FeatureFlags supports Python 2.5 (but not Python 3), so use that version if you need it. Be aware that both Flask and Jinja have dropped support for Python 2.5.

Docs

For the most complete and up-to-date documentation, please see: https://flask-featureflags.readthedocs.org/en/latest/

Setup

Adding the extension is simple:

from flask import Flask
from flask_featureflags import FeatureFlag

app = Flask(__name__)

feature_flags = FeatureFlag(app)

In your Flask app.config, create a FEATURE_FLAGS dictionary, and add any features you want as keys. Any UTF-8 string is a valid feature name.

For example, to have 'unfinished_feature' hidden in production but active in development:

class ProductionConfig(Config):

    FEATURE_FLAGS = {
        'unfinished_feature' : False,
    }


class DevelopmentConfig(Config):

    FEATURE_FLAGS = {
      'unfinished_feature' : True,
    }

Note: If a feature flag is used in code but not defined in FEATURE_FLAGS, it's assumed to be off. Beware of typos.

If you want your app to throw an exception in dev when a feature flag is used in code but not defined, add this to your configuration:

RAISE_ERROR_ON_MISSING_FEATURES = True

If app.debug=True, this will throw a KeyError instead of silently ignoring the error.

Usage

Controllers/Views

If you want to protect an entire view:

from flask import Flask
import flask_featureflags as feature

@feature.is_active_feature('unfinished_feature', redirect_to='/old/url')
def index():
  # unfinished view code here

The redirect_to parameter is optional. If you don't specify, the url will return a 404.

If your needs are more complicated, you can check inside the view:

from flask import Flask
import flask_featureflags as feature

def index():
    if feature.is_active('unfinished_feature') and some_other_condition():
        # do new stuff
    else:
        # do old stuff

Templates

You can also check for features in Jinja template code:

{% if 'unfinished_feature' is active_feature %}
    new behavior here!
{% else %}
    old behavior...
{% endif %}

Using other backends

Want to store your flags somewhere other than the config file? There are third-party contrib modules for other backends.

Please see the documentation here: https://flask-featureflags.readthedocs.org/en/latest/contrib.html

Feel free to add your own - see CONTRIBUTING.rst for help.

Customization

If you need custom behavior, you can write your own feature flag handler.

A feature flag handler is simply a function that takes the feature name as input, and returns True (the feature is on) or False (the feature is off).

For example, if you want to enable features on Tuesdays:

from datetime import date

def is_it_tuesday(feature):
  return date.today().weekday() == 2:

You can register the handler like so:

from flask import Flask
from flask_featureflags import FeatureFlag

app = Flask(__name__)

feature_flags = FeatureFlag(app)
feature_flags.add_handler(is_it_tuesday)

If you want to remove a handler for any reason, simply do:

feature_flags.remove_handler(is_it_tuesday)

If you try to remove a handler that was never added, the code will silently ignore you.

To clear all handlers (thus effectively turning all features off):

feature_flags.clear_handlers()

Clearing handlers is also useful when you want to remove the built-in behavior of checking the FEATURE_FLAGS dictionary.

To enable all features on Tuesdays, no matter what the FEATURE_FLAGS setting says:

from flask import Flask
from flask_featureflags import FeatureFlag

app = Flask(__name__)

feature_flags = FeatureFlag(app)
feature_flags.clear_handlers()
feature_flags.add_handler(is_it_tuesday)

Chaining multiple handlers

You can define multiple handlers. If any of them return true, the feature is considered on.

For example, if you want features to be enabled on Tuesdays or Fridays:

feature_flags.add_handler(is_it_tuesday)
feature_flags.add_handler(is_it_friday)

Important: the order of handlers matters! The first handler to return True stops the chain. So given the above example, if it's Tuesday, is_it_tuesday will return True and is_it_friday will not run.

You can override this behavior by raising the StopCheckingFeatureFlags exception in your custom handler:

from flask_featureflags import StopCheckingFeatureFlags

def run_only_on_tuesdays(feature):
  if date.today().weekday() == 2:
    return True
  else:
    raise StopCheckingFeatureFlags

If it isn't Tuesday, this will cause the chain to return False and any other handlers won't run.

Acknowledgements

A big thank you to LinkedIn for letting me opensource this, and for my coworkers for all their feedback on this project. You guys are great. :)

Questions?

Feel free to ping me on twitter @trustrachel or on the Github project page.

Comments
  • add flask_featureflags.contrib sub package in install script

    add flask_featureflags.contrib sub package in install script

    This changeset fixes the installed packages. Previously, flask_featureflags.contrib sub packages (including inline and sqlalchemy) were not installed through pip install flask-featureflags.

    opened by iromli 6
  • Signal for missing keys

    Signal for missing keys

    I want to add the key to my sqlalchemy database if it does not exist in any other handler. I can listen to some flask signal in this case to do that.

    Is it a good idea? I can work on it, but maybe others have better ideas about how to handle it.

    opened by iurisilvio 5
  • Update __init__.py to fix ExtDeprecationWarning

    Update __init__.py to fix ExtDeprecationWarning

    This is the fix the following warning which happens whenever the module is loaded: ExtDeprecationWarning: Importing flask.ext.featureflags is deprecated, use flask_featureflags instead. from flask.ext.featureflags import NoFeatureFlagFound, log

    opened by Naishy 3
  • Add contrib modules to setup.py

    Add contrib modules to setup.py

    Was trying to use InlineFeatureFlag (as described here), but found that the contrib modules weren't being included. Small change to setup.py fixes it.

    opened by pcraig3 3
  • SQLAlchemy handler

    SQLAlchemy handler

    My proposal to make an SQLAlchemy handler.

    You just need a SQLAlchemy instance (from Flask-SQLAlchemy extension) and a check method in the model.

    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    from flask.ext.featureflags import FeatureFlag
    from flask.ext.featureflags.contrib.sqlalchemy import SQLAlchemyFeatureFlags
    
    app = Flask(__name__)
    db = SQLAlchemy(app)
    handler = SQLAlchemyFeatureFlags(db)
    
    ff = FeatureFlag(app)
    ff.add_handlers(handler)
    
    opened by iurisilvio 3
  • Feature flag application backend

    Feature flag application backend

    As a fellow lover of python and flask, and having written a feature-switching backend application with an administrative UI, I would like to contribute an integration between the two. Is that something you'd be interested in?

    https://github.com/giftig/flippy

    I was actually inspired by gargoyle / django-gargoule when writing flippy, which worked very similarly to your lib.

    I'm genuinely not sure why I've never written my own python connector to it.

    opened by giftig 2
  • consistent version in __init__.py and setup.py

    consistent version in __init__.py and setup.py

    Previously, flask_featureflags.__version__ is set to 0.4dev while setup.py is set to 0.7-dev. This changeset ensures consistent version found in flask_featureflags.__version__ and setup.py.

    You can check the version in Python shell:

    >>> import flask_featureflags
    >>> print(flask_featureflags.__version__)
    0.7-dev
    

    and using pip freeze:

    $ pip freeze | grep FeatureFlags
    Flask-FeatureFlags==0.7.dev0
    
    opened by iromli 2
  • Add custom handler to add inline feature flags

    Add custom handler to add inline feature flags

    The changesets introduce custom handler for inline feature flags.

    One notable difference is, instead of specifying feature flags in dict-style:

    FEATURE_FLAGS = {
        "finished": False,
    }
    

    the flag must be written in uppercased plain string with FEATURE_FLAGS_X where X is the feature name:

    FEATURE_FLAGS_FINISHED = False
    

    The motivation behind this custom handler is to interopt with other Flask extensions, e.g. Flask-AppConfig.

    opened by iromli 2
  • Adding route definition to example

    Adding route definition to example

    This tripped me up a bit, so thought explicitly stating the order of decorators could help.

    This works (404s):

    @app.route('/feature-flag-test-route')
    @is_active_feature('test_route')
    def feature_flag_test_route():
        return 'on!'
    

    This does not (returns 200, displays 'on!')

    @is_active_feature('test_route')
    @app.route('/feature-flag-test-route')
    def feature_flag_test_route():
        return 'on!'
    
    opened by jskulski 1
  • Raise NoFeatureFlagFound instead of handle missing flags

    Raise NoFeatureFlagFound instead of handle missing flags

    The handler is not responsible to handle the feature flag missing. I expect the KeyError only if it was not found in any handler.

    The current implementation works for only one handler.

    This is my first step to create a custom handler. I want to make the core responsible for missing keys.

    I'm not sure about the exception name. Django use DoesNotExist, SQLAlchemy use NoResultFound, but I tried FeatureFlagNotFound, NotFound, FeatureNotFound and others.

    opened by iurisilvio 1
  • Add argument redirect (optional) to is_active_feature

    Add argument redirect (optional) to is_active_feature

    It's not possible to use url_for() in the decorator call if the app context is not build yet. Therefore this patch adds a new optional argument named redirect to is_active_feature. It's the same as redirect_to but it triggers url_for() right before the redirect.

    opened by michaelcontento 1
  • Fix imports to remove warning per Flask recommendation.

    Fix imports to remove warning per Flask recommendation.

    Flask no longer recommend using the "flask.ext." import style; this change eliminates the warning currently generated by flask when using this extension.

    http://flask.pocoo.org/docs/0.12/extensiondev/#extension-import-transition

    (The 0.12 docs are somewhat contradictory on this, but the confusing text seems to have been removed in the latest dev docs.)

    opened by galund 1
Releases(0.6)
  • 0.6(Jun 10, 2015)

  • 0.5.1(Oct 13, 2014)

    Adding the ability to have feature flags inline instead of in a dictionary, to make it easier to interoperate with other Flask extensions, e.g. Flask-AppConfig.

    A big thank you to Isman Firmansyah (@iromli) for the contribution!

    Source code(tar.gz)
    Source code(zip)
  • 0.5(Aug 7, 2014)

    Official support for contributed modules, thank you to iurisilvio! He contributed the first for SQLAlchemy, so you can store your flags in the database instead.

    Contributions for other storage backends welcome!

    Source code(tar.gz)
    Source code(zip)
  • 0.4(Apr 8, 2014)

    • General code cleanup, modernization and optimization
    • Adding optional redirect to is_active_feature, thank you to michaelcontento
    • Fixed syntax error in docs, thank you to iurisilvio
    Source code(tar.gz)
    Source code(zip)
Owner
Rachel Greenfield
Currently funlancing, Previously Stripe, LinkedIn
Rachel Greenfield
Ansible Inventory Plugin, created to get hosts from HTTP API.

ansible-ws-inventory-plugin Ansible Inventory Plugin, created to get hosts from HTTP API. Features: Database compatible with MongoDB and Filesystem (J

Carlos Neto 0 Feb 05, 2022
Formatting of dates and times in Flask templates using moment.js.

Flask-Moment This extension enhances Jinja2 templates with formatting of dates and times using moment.js. Quick Start Step 1: Initialize the extension

Miguel Grinberg 358 Nov 28, 2022
Boilerplate code for quick docker implementation of REST API with JWT Authentication using FastAPI, PostgreSQL and PgAdmin ⭐

FRDP Boilerplate code for quick docker implementation of REST API with JWT Authentication using FastAPI, PostgreSQL and PgAdmin ⛏ . Getting Started Fe

BnademOverflow 53 Dec 29, 2022
A dynamic FastAPI router that automatically creates CRUD routes for your models

⚡ Create CRUD routes with lighting speed ⚡ A dynamic FastAPI router that automatically creates CRUD routes for your models

Adam Watkins 950 Jan 08, 2023
Simple example of FastAPI + Celery + Triton for benchmarking

You can see the previous work from: https://github.com/Curt-Park/producer-consumer-fastapi-celery https://github.com/Curt-Park/triton-inference-server

Jinwoo Park (Curt) 37 Dec 29, 2022
Opinionated set of utilities on top of FastAPI

FastAPI Contrib Opinionated set of utilities on top of FastAPI Free software: MIT license Documentation: https://fastapi-contrib.readthedocs.io. Featu

identix.one 543 Jan 05, 2023
Easy and secure implementation of Azure AD for your FastAPI APIs 🔒

FastAPI-Azure-auth Azure AD Authentication for FastAPI apps made easy. 🚀 Description FastAPI is a modern, fast (high-performance), web framework for

Intility 216 Dec 27, 2022
A rate limiter for Starlette and FastAPI

SlowApi A rate limiting library for Starlette and FastAPI adapted from flask-limiter. Note: this is alpha quality code still, the API may change, and

Laurent Savaete 562 Jan 01, 2023
Regex Converter for Flask URL Routes

Flask-Reggie Enable Regex Routes within Flask Installation pip install flask-reggie Configuration To enable regex routes within your application from

Rhys Elsmore 48 Mar 07, 2022
LuSyringe is a documentation injection tool for your classes when using Fast API

LuSyringe LuSyringe is a documentation injection tool for your classes when using Fast API Benefits The main benefit is being able to separate your bu

Enzo Ferrari 2 Sep 06, 2021
Voucher FastAPI

Voucher-API Requirement Docker Installed on system Libraries Pandas Psycopg2 FastAPI PyArrow Pydantic Uvicorn How to run Download the repo on your sys

Hassan Munir 1 Jan 26, 2022
FastAPI with async for generating QR codes and bolt11 for Lightning Addresses

sendsats An API for getting QR codes and Bolt11 Invoices from Lightning Addresses. Share anywhere; as a link for tips on a twitter profile, or via mes

Bitkarrot 12 Jan 07, 2023
FastAPI-PostgreSQL-Celery-RabbitMQ-Redis bakcend with Docker containerization

FastAPI - PostgreSQL - Celery - Rabbitmq backend This source code implements the following architecture: All the required database endpoints are imple

Juan Esteban Aristizabal 54 Nov 26, 2022
Adds simple SQLAlchemy support to FastAPI

FastAPI-SQLAlchemy FastAPI-SQLAlchemy provides a simple integration between FastAPI and SQLAlchemy in your application. It gives access to useful help

Michael Freeborn 465 Jan 07, 2023
Lightning FastAPI

Lightning FastAPI Lightning FastAPI framework, provides boiler plates for FastAPI based on Django Framework Explaination / | │ manage.py │ README.

Rajesh Joshi 1 Oct 15, 2021
A FastAPI Middleware of joerick/pyinstrument to check your service performance.

fastapi_profiler A FastAPI Middleware of joerick/pyinstrument to check your service performance. 📣 Info A FastAPI Middleware of pyinstrument to check

LeoSun 107 Jan 05, 2023
Prometheus exporter for Starlette and FastAPI

starlette_exporter Prometheus exporter for Starlette and FastAPI. The middleware collects basic metrics: Counter: starlette_requests_total Histogram:

Steve Hillier 225 Jan 05, 2023
Easily integrate socket.io with your FastAPI app 🚀

fastapi-socketio Easly integrate socket.io with your FastAPI app. Installation Install this plugin using pip: $ pip install fastapi-socketio Usage To

Srdjan Stankovic 210 Dec 23, 2022
A simple Redis Streams backed Chat app using Websockets, Asyncio and FastAPI/Starlette.

redis-streams-fastapi-chat A simple demo of Redis Streams backed Chat app using Websockets, Python Asyncio and FastAPI/Starlette. Requires Python vers

ludwig404 135 Dec 19, 2022
Cbpa - Coinbase Pro Automation for buying your favourite cryptocurrencies

cbpa Coinbase Pro Automation for making buy orders from a default bank account.

Anthony Corletti 3 Nov 27, 2022