Skip to main content

Feature Flagging for Flask

Project description

flask-pancake

GitHub Workflow Status (branch) Codecov branch PyPI

Feature Flagging for Flask

This library was heavily inspired by django-waffle.

Installation

flask-pancake depends on Redis and the flask-redis Python package.

$ python -m pip install flask-pancake
Successfully installed flask-pancake
from flask import Flask
from flask_pancake import FlaskPancake, Switch
from flask_redis import FlaskRedis

app = Flask(__name__)
pancake = FlaskPancake(app)
redis = FlaskRedis(app)

SWITCH_FEATURE = Switch("FEATURE", default=False)


@app.route("/")
def index():
    if SWITCH_FEATURE.is_active():
        return "Hello World!", 200
    else:
        return "Not found", 404

Alternatively, if you use a create_app() method to configure your Flask app, use pancake.init_app():

from flask import Flask
from flask_pancake import FlaskPancake

pancake = FlaskPancake()


def create_app() -> Flask:
    app = Flask(__name__)
    pancake.init_app(app)
    return app

Usage

flask-pancake provides three types of flags:

  • Switches, which are either globally active or inactive. A common use case for these are system-wide enabling or disabling of a feature. E.g. in the context of a dependency on a third party service, disabling a feature with a global switch when that service is unavailable.

  • Flags are like Switches but can be overridden for individual groups. To make use of Flags, one needs to define at least one function that returns a group's unique ID or None. Groups can be anything that you want users to be grouped by: their user ID (which would allow per-user enabling/disabling of features), a user's attribute, such as "is_superuser" or "is_staff", or anything else that you can think of.

    The groups are tried in order. The first one to match will be used. Meaning, more specific functions should be defined first, less specific functions last.

    from flask import request
    from flask_pancake import FlaskPancake
    
    def get_group_user():
        # If the `request` object has a `user` attribute and the `user` object
        # has a `uid` attribute, return that.
        return getattr(getattr(request, "user", None), "uid", None)
    
    def get_group_superuser():
        # If the `request` object has a `user` attribute and the `user` object
        # has an `is_superuser` attribute, return "y" if that is boolean `True`
        # or "n" if it isn't.
        return getattr(getattr(request, "user", None), "is_superuser", None) and "y" or "n"
    
    pancake = FlaskPancake(
        group_funcs={"user", get_group_user, "superuser", get_group_superuser}
    )
    # Or, if importing a function from somewhere isn't possible, a string based
    # approach can be used.
    # Separate the the fully qualified module path from the function with a `:`
    pancake = FlaskPancake(
        group_funcs={
            "user", "my.app.account.utils:get_group_user",
            "superuser", "my.app.account.utils:get_group_superuser",
        }
    )
    

    In the example, whenever one checks for a Flag, FlaskPancake would check if a value has been set in the following order:

    1. Is the flag disable/enable for the current user?
    2. If not, is the flag disable/enabled for superusers/non-superusers?
    3. If not, is the flag disable/enabled by default?
  • Samples, have a global "ratio" of 0 - 100%. Each time a check is done on a sample, a random value is checked within these bounds. Hence:

    # DO THIS!
    def foo():
        is_active = MY_SAMPLE.is_active()
        if is_active:
            # do something
            pass
        ...
        if is_active:
            # do more
            pass
    
    # DO NOT DO THIS!
    def foo():
        if MY_SAMPLE.is_active():
            # do something
            pass
        ...
        if MY_SAMPLE.is_active():
            # do more
            pass
    

    In the second example, each call to is_active() will be evaluated again. Thus, the first block might be executed, but the second might not (or vice versa).

The persisted state for all three types of feature flags can be cleared, using the clear() method.

Similarly, one can change the persisted state for Flags and Switches using their disable() and enable() methods. Samples can be updated using their set(value: float) method.

When using Flags, there are clear_group(group_id) and clear_all_group(group_id) methods, to clear the state for the current or all users within a group. Along the same line, there are disable_group(group_id) and enable_group(group_id) to set the group's state the current user is part of.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flask-pancake-0.4.0.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

flask_pancake-0.4.0-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file flask-pancake-0.4.0.tar.gz.

File metadata

  • Download URL: flask-pancake-0.4.0.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.3.1 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.8.3

File hashes

Hashes for flask-pancake-0.4.0.tar.gz
Algorithm Hash digest
SHA256 7f7ef36c36d1a7f63ae46a45827e6277ffbc6f96d97abdd2c67c83f6c6e31e2d
MD5 d47af80ccfd5b29e6b6e4b39e295a88e
BLAKE2b-256 bf18bcda7ffbe9637601f21fb2800c8f7f1af55eb8f026d39b5528cc074c34be

See more details on using hashes here.

File details

Details for the file flask_pancake-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: flask_pancake-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 9.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.3.1 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.8.3

File hashes

Hashes for flask_pancake-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7bca9ff258b778eaa810492a36b91f96dd778655ebd4003a7bb0faae15474aed
MD5 84d63d6cb2668b28ab92e5a282900c02
BLAKE2b-256 a8537b02d0635da950900b8f4559ef28619f1f2d4f552d11599d3cea5a84263b

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page