Skip to content
This repository has been archived by the owner on Feb 7, 2019. It is now read-only.

Commit

Permalink
Merge pull request #11 from iromli/inline-featureflags
Browse files Browse the repository at this point in the history
Add custom handler to add inline feature flags
  • Loading branch information
Rachel Sanders committed Oct 13, 2014
2 parents f5a1935 + 45a7bd8 commit dcaeb81
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
52 changes: 52 additions & 0 deletions docs/contrib.rst
Expand Up @@ -30,3 +30,55 @@ It will automatically create a table to store your flags in, or you can override

ff.add_handler(SQLAlchemyFeatureFlags(db, model=MyModel))


Inline
------

``InlineFeatureFlag`` checks for any flag in app's config with `FEATURE_FLAGS_X` format,
where `X` is the name of a specific feature.

The difference between this handler and default handler is,
instead of defining flag in ``dict``-style:

.. sourcecode:: python

FEATURE_FLAGS {
'finished': False,
}

the feature name must use uppercased plain string:

.. sourcecode:: python

FEATURE_FLAGS_FINISHED = False

The motivation behind this inline handler is to interopt with other Flask extensions
that rely on environment variable, e.g. `Flask-AppConfig <https://pypi.python.org/pypi/flask-appconfig>`_.

Usage
+++++

A typical usage is as trivial as the following snippet:

.. sourcecode:: python

from flask import Flask
import flask_featureflags as feature_flags
from flask_featureflags.contrib.inline import InlineFeatureFlag

# feature flags config
FEATURE_FLAGS_FINISHED = False

app = Flask(__name__)
app.config.from_object(__name__)
ff = feature_flags.FeatureFlag(app)
ff.add_handler(InlineFeatureFlag())

@app.route("/")
def index():
return "Homepage"

@app.route("/new")
@feature_flags.is_active_feature("FINISHED", redirect_to="/")
def new():
return "New feature"
18 changes: 18 additions & 0 deletions flask_featureflags/contrib/inline/__init__.py
@@ -0,0 +1,18 @@
from flask import current_app
from flask.ext.featureflags import FEATURE_FLAGS_CONFIG
from flask.ext.featureflags import NoFeatureFlagFound
from flask.ext.featureflags import log


class InlineFeatureFlag(object):
def __call__(self, feature):
if not current_app:
log.warn(u"Got a request to check for {feature} but we're outside the request context. Returning False".format(feature=feature))
return False

feature_cfg = "{prefix}_{feature}".format(prefix=FEATURE_FLAGS_CONFIG, feature=feature)

try:
return current_app.config[feature_cfg]
except KeyError:
raise NoFeatureFlagFound()
42 changes: 42 additions & 0 deletions tests/contrib/test_inline_handler.py
@@ -0,0 +1,42 @@
import unittest

import flask_featureflags as feature_flags
from flask_featureflags.contrib.inline import InlineFeatureFlag

from tests.fixtures import app
from tests.fixtures import feature_setup


inline_feature_flag = InlineFeatureFlag()


class InlineFeatureFlagTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
feature_setup.add_handler(inline_feature_flag)

@classmethod
def tearDownClass(cls):
feature_setup.clear_handlers()

def setUp(self):
self.app_ctx = app.app_context()
self.app_ctx.push()
app.config["FEATURE_FLAGS_ACTIVE"] = True
app.config["FEATURE_FLAGS_INACTIVE"] = False

def tearDown(self):
self.app_ctx.pop()

def test_flag_active(self):
self.assertTrue(feature_flags.is_active("ACTIVE"))

def test_flag_inactive(self):
self.assertFalse(feature_flags.is_active("INACTIVE"))

def test_flag_not_found(self):
self.assertFalse(feature_flags.is_active("NOT_FOUND"))

def test_flag_not_found_raise_handler_exception(self):
self.assertRaises(feature_flags.NoFeatureFlagFound,
inline_feature_flag, "NOT_FOUND")

0 comments on commit dcaeb81

Please sign in to comment.