Metadata-Version: 1.1
Name: wagtail-flags
Version: 2.0.0
Summary: Feature flags for Wagtail sites
Home-page: https://github.com/cfpb/wagtail-flags
Author: CFPB
Author-email: tech@cfpb.gov
License: CC0
Description: Wagtail-Flags
        =============
        
        |Build Status| |Coverage Status|
        
        Feature flags allow you to toggle functionality in both Django settings
        and the Wagtail or Django admin based on configurable conditions.
        
        .. figure:: https://raw.githubusercontent.com/cfpb/wagtail-flags/master/screenshot_list.png
           :alt: Feature flags in the Wagtail admin
        
           Feature flags in the Wagtail admin
        
        -  `Dependencies <#dependencies>`__
        -  `Installation <#installation>`__
        -  `Concepts <#concepts>`__
        -  `Usage <#usage>`__
        
           -  `Overview <#overview>`__
           -  `Adding Flags <#adding-flags>`__
        
              -  `Defining flags <#defining-flags>`__
              -  `Built-in conditions <#built-in-conditions>`__
        
        -  `API <#api>`__
        
           -  `Flag state <#flag-state>`__
           -  `Flag decorators <#flag-decorators>`__
           -  `Flagged URLs <#flagged-urls>`__
           -  `Django templates <#django-templates>`__
           -  `Jinja2 templates <#jinja2-templates>`__
           -  `Conditions <#conditions>`__
        
        -  `Getting help <#getting-help>`__
        -  `Getting involved <#getting-involved>`__
        -  `Licensing <#licensing>`__
        -  `Credits and references <#credits-and-references>`__
        
        Dependencies
        ------------
        
        -  Django 1.8+
        -  Wagtail 1.7+
        -  Python 2.7+, 3.5+
        
        Installation
        ------------
        
        1. Install wagtail-flags using pip:
        
        .. code:: shell
        
            pip install wagtail-flags
        
        2. Add ``flags`` as an installed app in your Django ``settings.py``:
        
        ``python  INSTALLED_APPS = (      ...      'flags',      ...  )``
        
        Concepts
        --------
        
        Feature flags in Wagtail-Flags are identified by simple strings that are
        enabled when the conditions they are associated with are met. These
        flags can be used to wrap code and template content that should only be
        used when a flag is enabled or disabled.
        
        Conditions determine whether a flag is enabled or disabled by comparing
        a defined expected value of some kind with the value at the time the
        flag is checked. In many cases, the flag is checked during a request,
        and some piece of the request's metadata is what is compared. For
        example, a feature flag that is enabled for a specific Wagtail Site
        would be enabled if the request's site matches the condition's site.
        
        Usage
        -----
        
        Overview
        ~~~~~~~~
        
        To use Wagtail-Flags you first need to define the flag, use the flag in
        code, and define conditions for the flag to be enabled.
        
        First, define the flag in Django ``settings.py``:
        
        .. code:: python
        
            FLAGS = {
                'MY_FLAG': {}
            }
        
        Then use the flag in a Django template (``mytemplate.html``):
        
        .. code:: django
        
            {% load feature_flags %}
            {% flag_enabled 'MY_FLAG' as my_flag %}
        
            {% if my_flag %}
              <div class="flagged-banner">
                I’m the result of a feature flag.   
              </div>
            {% endif %}
        
        Configure a URL for that template (``urls.py``):
        
        .. code:: python
        
            from django.conf.urls import url
            from django.views.generic.base import TemplateView
        
            urlpatterns = [
                url(r'^/mypage$', TemplateView.as_view(template_name='mytemplate.html'),
            ]
        
        Then in the Wagtail admin add conditions for the flag in "Settings",
        "Flags":
        
        .. figure:: https://raw.githubusercontent.com/cfpb/wagtail-flags/master/screenshot_create.png
           :alt: Creating conditions in the Wagtail admin
        
           Creating conditions in the Wagtail admin
        
        Then visiting the URL ``/mypage?enable_my_flag=True`` should show you
        the flagged ``<div>`` in the template.
        
        Adding flags
        ~~~~~~~~~~~~
        
        Defining flags
        ^^^^^^^^^^^^^^
        
        Flags are defined in Django settings with the conditions in which they
        are enabled.
        
        .. code:: python
        
            FLAGS = {
              'FLAG_WITH_EMPTY_CONDITIONS': {}
              'MY_FLAG': {
                'condition name': 'value flag is expected to match to be enabled',
                'user': 'lady.liberty'
              }
            }
        
        The set of conditions can be none (flag will never be enabled), one
        (only condition that has to be met for the flag to be enabled), or many
        (all have to be met for the flag to be enabled).
        
        Additional conditions can be added in the Django or Wagtail admin for
        any defined flag (illustrated in `Usage <#usage>`__). Conditions added
        in the Django or Wagtail admin can be changed without restarting Django,
        conditions defined in ``settings.py`` cannot.
        
        Built-in conditions
        ^^^^^^^^^^^^^^^^^^^
        
        Wagtail-Flags comes with the following conditions built-in:
        
        ``boolean``
        '''''''''''
        
        A simple boolean true/false intended to enable or disable a flag
        explicitly. The state of the flag evaluates to the value of the boolean
        condition.
        
        .. code:: python
        
            FLAGS = {'MY_FLAG': {'boolean': True}}
        
        ``user``
        ''''''''
        
        Allows a flag to be enabled for the username given as the condition's
        value.
        
        .. code:: python
        
            FLAGS = {'MY_FLAG': {'user': 'jane.doe'}}
        
        ``anonymous``
        '''''''''''''
        
        Allows a flag to be either enabled or disabled depending on the
        condition's boolean value.
        
        .. code:: python
        
            FLAGS = {'MY_FLAG': {'anonymous: False}}
        
        ``parameter``
        '''''''''''''
        
        Allows a flag to be enabled based on a GET parameter with the name given
        as the condition's value.
        
        .. code:: python
        
            FLAGS = {'MY_FLAG': {'parameter': 'my_flag_param'}}
        
        ``path``
        ''''''''
        
        Allows a flag to be enabled if the request's path matches the condition
        value.
        
        .. code:: python
        
            FLAGS = {'MY_FLAG': {'path': '/flagged/path'}}
        
        ``site``
        ''''''''
        
        Allows a flag to be enabled for a Wagtail site that matches the hostname
        and port in the condition value.
        
        .. code:: python
        
            FLAGS = {'MY_FLAG': {'site': 'staging.mysite.com'}}
        
        API
        ---
        
        Flag state
        ~~~~~~~~~~
        
        .. code:: python
        
            from flags.state import (
                flag_state,
                flag_enabled,
                flag_disabled,
            )
        
        ``flag_state(flag_name, **kwargs)``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Return the value for the flag (``True`` or ``False``) by passing kwargs
        to its conditions.
        
        ``flag_enabled(flag_name, **kwargs)``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Returns ``True`` if a flag is enabled by passing kwargs to its
        conditions, otherwise returns ``False``.
        
        .. code:: python
        
            if flag_enabled('MY_FLAG', request=a_request):
                print("My feature flag is enabled")
        
        ``flag_disabled(flag_name, **kwargs)``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Returns ``True`` if a flag is disabled by passing kwargs to its
        conditions, otherwise returns ``False``.
        
        .. code:: python
        
            if flag_disabled('MY_FLAG', request=a_request):
                print(“My feature flag is disabled”)
        
        Flag decorators
        ~~~~~~~~~~~~~~~
        
        Decorators are provided for use with Django views and conditions that
        take a ``request`` argument. The default behavior is to return a 404 if
        a callable fallback is not given.
        
        .. code:: python
        
            from flags.decorators import (
                flag_check,
                flag_required,
            )
        
        ``flag_check(flag_name, state, fallback=None, **kwargs)``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Check that a given flag has the given state. If the state does not
        match, perform the fallback.
        
        **Note**, because flags that do not exist are taken to be ``False`` by
        default, ``@flag_check('MY_FLAG', False)`` and
        ``@flag_check('MY_FLAG', None)`` will both succeed if ``MY_FLAG`` does
        not exist.
        
        .. code:: python
        
            from flags.decorators import flag_check
        
            @flag_check('MY_FLAG', True)
            def view_requiring_flag(request):
                return HttpResponse('flag was set')
        
            @flag_check('MY_OTHER_FLAG', False)
            def view_when_flag_is_not_set(request):
                return HttpResponse('flag was set')
        
            def other_view(request):
                return HttpResponse('flag was not set')
        
            @flag_check('MY_FLAG_WITH_FALLBACK', True, fallback=other_view)
            def view_with_fallback(request):
                return HttpResponse('flag was set')
        
        ``flag_required(flag_name, fallback_view=None, pass_if_set=True)``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Require the given flag to be enabled.
        
        .. code:: python
        
            from flags.decorators import flag_required
        
            @flag_required('MY_FLAG')
            def view_requiring_flag(request):
                return HttpResponse('flag was set')
        
            def other_view(request):
                return HttpResponse('flag was not set')
        
            @flag_required('MY_FLAG_WITH_FALLBACK', fallback_view=other_view)
            def view_with_fallback(request):
                return HttpResponse('flag was set')
        
        Flagged URLs
        ~~~~~~~~~~~~
        
        .. code:: python
        
            from flags.urls import flagged_url
        
        ``flagged_url(flag_name, regex, view, kwargs=None, name=None, state=True, fallback=None)``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Make a URL depend on the state of a feature flag. ``flagged_url()`` can
        be used in place of Django's ``url()``.
        
        ``fallback`` support for ``include()`` URLs is limited to a single view
        rather than a fallback set of ``include()``\ ed URLs.
        
        .. code:: python
        
            urlpatterns = [
                flagged_url('MY_FLAG', r'^an-url$', view_requiring_flag, state=True),
                flagged_url('MY_FLAG_WITH_FALLBACK', r'^another-url$', view_with_fallback,
                            state=True, fallback=other_view)
                flagged_url('MY_FLAGGED_INCLUDE', r'^myapp$', include('myapp.urls'),
                            state=True, fallback=other_view)
            ]
        
        Django templates
        ~~~~~~~~~~~~~~~~
        
        Wagtail-Flags provides a template tag library that can be used to
        evaluate flags in Django templates.
        
        .. code:: django
        
            {% load feature_flags %}
        
        ``flag_enabled``
        ^^^^^^^^^^^^^^^^
        
        Returns ``True`` if a flag is enabled by passing the current request to
        its conditions, otherwise returns ``False``.
        
        .. code:: django
        
            {% flag_enabled 'MY_FLAG' as my_flag %}
            {% if my_flag %}
              <div class="m-global-banner">
                I’m the result of a feature flag.   
              </div>
            {% endif %}
        
        ``flag_disabled``
        ^^^^^^^^^^^^^^^^^
        
        Returns ``True`` if a flag is disabled by passing the current request to
        its conditions, otherwise returns ``False``.
        
        .. code:: django
        
            {% flag_disabled 'MY_FLAG' as my_flag %}
            {% if my_flag %}
              <div class="m-global-banner">
                I’m the result of a feature flag that is not enabled.
              </div>
            {% endif %}
        
        Jinja2 templates
        ~~~~~~~~~~~~~~~~
        
        Wagtail-Flags provides template functions that can be added to a Jinja2
        environment and subsequently used in templates.
        
        .. code:: python
        
            from flags.template_functions import (
                flag_enabled,
                flag_disabled
            )
        
            ...
        
            env.globals.update(
                flag_enabled=flag_enabled,
                flag_disabled=flag_disabled
            )
        
        ``flag_enabled``
        ^^^^^^^^^^^^^^^^
        
        Returns ``True`` if a flag is enabled by for the given request,
        otherwise returns ``False``.
        
        .. code:: jinja
        
            {% if flag_enabled('MY_FLAG', request) %}
              <div class="m-global-banner">
                I’m the result of a feature flag.   
              </div>
            {% endif %}
        
        ``flag_disabled``
        ^^^^^^^^^^^^^^^^^
        
        Returns ``True`` if a flag is disabled by passing the current request to
        its conditions, otherwise returns ``False``. Returns ``True`` if a flag
        is disabled by for the given request, otherwise returns ``False``.
        
        .. code:: jinja
        
            {% if flag_disabled('MY_FLAG', request) %}
              <div class="m-global-banner">
                I’m the result of a feature flag that is not enabled.
              </div>
            {% endif %}
        
        Conditions
        ~~~~~~~~~~
        
        Conditions are functions that take a configured value and possible
        keyword arguments and determines whether the given arguments are
        equivalent to the value. Conditions are registered with a unique name
        that is exposed to users in Django settings and the Django and Wagtail
        admin.
        
        .. code:: python
        
            from flags import conditions
        
        ``conditions.register(condition_name, fn=None)``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Register a new condition, either as a decorator:
        
        .. code:: python
        
            from flags import conditions
        
            @conditions.register('path')
            def path_condition(path, request=None, **kwargs):
                return request.path.startswith(path)
        
        Or as a function call:
        
        .. code:: python
        
            def path_condition(path, request=None, **kwargs):
                return request.path.startswith(path)
        
            conditions.register('path', fn=path_condition)
        
        ``conditions.RequiredForCondition``
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Exception intended to be raised when a condition is not given a keyword
        argument it requires for evaluation.
        
        .. code:: python
        
            @conditions.register('path')
            def path_condition(path, request=None, **kwargs):
                if request is None:
                    raise conditions.RequiredForCondition(
                        "request is required for condition 'path'")
        
                return request.path.startswith(path)
        
        Getting help
        ------------
        
        Please add issues to the `issue
        tracker <https://github.com/cfpb/wagtail-flags/issues>`__.
        
        Getting involved
        ----------------
        
        General instructions on *how* to contribute can be found in
        `CONTRIBUTING <CONTRIBUTING.md>`__.
        
        Licensing
        ---------
        
        1. `TERMS <TERMS.md>`__
        2. `LICENSE <LICENSE>`__
        3. `CFPB Source Code
           Policy <https://github.com/cfpb/source-code-policy/>`__
        
        Credits and references
        ----------------------
        
        1. Forked from
           `cfgov-refresh <https://github.com/cfpb/cfgov-refresh/tree/master/cfgov/flags>`__
        
        .. |Build Status| image:: https://travis-ci.org/cfpb/wagtail-flags.svg?branch=master
           :target: https://travis-ci.org/cfpb/wagtail-flags
        .. |Coverage Status| image:: https://coveralls.io/repos/github/cfpb/wagtail-flags/badge.svg?branch=master
           :target: https://coveralls.io/github/cfpb/wagtail-flags?branch=master
        
Platform: UNKNOWN
Classifier: License :: Public Domain
Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
