Writing Feature Checkers¶
Feature checkers are small classes that determine whether a feature should be enabled or disabled. They do this by making a determination based on a feature stability level and based on any arguments passed to the checker.
Any application that ties features to users or their teams, or has other more complex needs, will have to write a feature checker.
Feature Enabled Checks¶
When writing a feature checker, you usually will only need to implement a
single function: is_feature_enabled()
. This is
used to determine if a feature is enabled, based on some criteria defined by
the checker. This criteria can include some global state (such as
pre-configured settings) or can be based off keyword arguments passed to the
function.
For instance, you may want to write a feature checker that takes into account
the enabled feature IDs in a user’s profile, falling back on values in
settings.py
:
from django.conf import settings
from djblets.features.checkers import BaseFeatureChecker
class MyFeatureChecker(BaseFeatureChecker):
def is_feature_enabled(self, feature_id, user=None, **kwargs):
if user:
enabled_features = user.get_profile().enabled_features
else:
enabled_features = settings.ENABLED_FEATURES
return enabled_features.get(feature_id, False)
You can do pretty much anything in this method, including querying a database. It’s really up to you.
It’s important to note that your checker may be passed keyword arguments it
doesn’t expect, and may not be passed arguments it does expect. It’s important
to handle all cases, and to always return True
or False
. It must never
raise an exception.
Minimum Levels¶
A feature checker can also specify the minimum level for an enabled feature,
or can outright reject features based on their stability level. It does this
by overriding the min_enabled_level()
property.
For example, to enable all beta features based on a key in settings:
from django.conf import settings
from djblets.features.checkers import BaseFeatureChecker
from djblets.features.level import FeatureLevel
class MyFeatureChecker(BaseFeatureChecker):
@property
def min_enabled_level(self):
if settings.ENABLE_BETA_FEATURES:
return FeatureLevel.BETA
else:
return FeatureLevel.STABLE
If you just want to hard-code a default for all cases, simply set this as an attribute:
from djblets.features.checkers import BaseFeatureChecker
from djblets.features.level import FeatureLevel
class MyFeatureChecker(BaseFeatureChecker):
min_enabled_level = FeatureLevel.BETA
If you’re doing something more complex, and only ever need to do it once, you
may want to use a @cached_property
decorator. For example, we might
want to use it for our settings-based check above, to avoid the unnecessary
setting lookup:
from django.utils.functional import cached_property
from djblets.features.checkers import BaseFeatureChecker
from djblets.features.level import FeatureLevel
class MyFeatureChecker(BaseFeatureChecker):
@cached_property
def min_enabled_level(self):
if settings.ENABLE_BETA_FEATURES:
return FeatureLevel.BETA
else:
return FeatureLevel.STABLE