Add support for light-weight feature checks.
Review Request #8031 — Created March 4, 2016 and submitted
Feature checks (aka feature switches/toggles) are a way to allow new features to be built and tested in a codebase without exposing them to every user. This introduces support for light-weight feature checks. There are three parts: Features, Feature Checkers, and the Feature Registry. The Feature class is used to define a feature. It just requires a feature ID and an optional name, summary, and stability level. It may also contain functions for handling initialization and shutdown (for when the feature is registered and unregistered, respectively). Once instantiated, the feature is registered and ready to check. Feature checkers determine whether a feature should be enabled, based on the severity level and any other custom criteria. When an application checks if a feature should be enabled, it can pass any criteria it wants (user, request, etc.), and if the checker understands it, it can consider it. This gives applications a lot of control of how features and their checkers are to be used, without imposing major requirements on them like other frameworks. The feature registry contains all the features that have been instantiated, and can be used to look up or list features dynamically. There are template tags available as well for limiting bits of a template based on whether a feature is enabled. Documentation is provided covering how features work, and how to write both features and feature checkers.
Unit tests pass.
Checked the docs for errors and bad code references.
Description | From | Last Updated |
---|---|---|
'FeatureNotFoundError' imported but unused |
reviewbot | |
redefinition of unused 'test_is_enabled_with_unavailable' from line 91 |
reviewbot | |
'settings' imported but unused |
reviewbot | |
'Site' imported but unused |
reviewbot | |
'ImproperlyConfigured' imported but unused |
reviewbot | |
'set_feature_checker' imported but unused |
reviewbot | |
'SiteConfigFeatureChecker' imported but unused |
reviewbot | |
'SettingsFeatureChecker' imported but unused |
reviewbot | |
'BaseFeatureChecker' imported but unused |
reviewbot | |
'get_feature_checker' imported but unused |
reviewbot | |
'FeatureNotFoundError' imported but unused |
reviewbot | |
'SiteConfiguration' imported but unused |
reviewbot | |
local variable 't' is assigned to but never used |
reviewbot | |
local variable 't' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
local variable 't' is assigned to but never used |
reviewbot | |
local variable 't' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
local variable 'feature' is assigned to but never used |
reviewbot | |
'cache' imported but unused |
reviewbot | |
Can we log the original exception? |
david | |
Missing closing paren. |
brennie | |
I think we should initialize the feature before registering it. |
david | |
This should be djblets.features.feature.Feature |
brennie | |
Docstrings in this file? |
david | |
'Site' imported but unused |
reviewbot | |
Too many blank lines. |
david | |
Too many blank lines. |
david | |
typo: "registerd" |
david | |
I don't suppose it's possible to extract the docs for these from the code? |
david | |
Can you add a period here? |
david | |
Can you add a period here? |
david | |
undefined name 'feature_id' |
reviewbot | |
'set_feature_checker' imported but unused |
reviewbot | |
'get_feature_checker' imported but unused |
reviewbot |
-
Tool: Pyflakes Processed Files: djblets/features/tests/test_feature.py djblets/features/tests/test_checkers.py djblets/features/feature.py djblets/features/errors.py djblets/registries/registry.py djblets/features/tests/test_template_tags.py djblets/features/tests/test_registry.py djblets/features/templatetags/features.py djblets/features/registry.py djblets/siteconfig/models.py djblets/features/__init__.py djblets/features/level.py djblets/features/checkers.py Ignored Files: docs/djblets/guides/features/intro.rst docs/djblets/guides/features/index.rst docs/djblets/guides/index.rst docs/djblets/guides/features/writing-feature-checkers.rst docs/djblets/guides/features/writing-features.rst docs/djblets/coderef/index.rst djblets/features/templatetags/__init__.py djblets/features/tests/__init__.py Tool: PEP8 Style Checker Processed Files: djblets/features/tests/test_feature.py djblets/features/tests/test_checkers.py djblets/features/feature.py djblets/features/errors.py djblets/registries/registry.py djblets/features/tests/test_template_tags.py djblets/features/tests/test_registry.py djblets/features/templatetags/features.py djblets/features/registry.py djblets/siteconfig/models.py djblets/features/__init__.py djblets/features/level.py djblets/features/checkers.py Ignored Files: docs/djblets/guides/features/intro.rst docs/djblets/guides/features/index.rst docs/djblets/guides/index.rst docs/djblets/guides/features/writing-feature-checkers.rst docs/djblets/guides/features/writing-features.rst docs/djblets/coderef/index.rst djblets/features/templatetags/__init__.py djblets/features/tests/__init__.py
-
-
Would you mind adding some utilities (either a method decorator or a context manager) to make it possible to set whether or not a feature is enabled when unit testing?
-
-
-
-
-
-
-
-
-
-
- Change Summary:
-
- Added unit test helpers for overriding feature enabled states.
- Features are now registered after being initialized.
- Exceptions are logged if failing to construct a feature checker.
- Improved the documentation throughout, including fixes to guides and addition of docstrings.
- Added a new guide on testing features in unit tests.
-
Tool: PEP8 Style Checker Processed Files: djblets/features/tests/test_feature.py djblets/features/tests/test_checkers.py djblets/features/feature.py djblets/features/errors.py djblets/registries/registry.py djblets/features/tests/test_template_tags.py djblets/features/tests/test_registry.py djblets/features/templatetags/features.py djblets/features/registry.py djblets/siteconfig/models.py djblets/features/__init__.py djblets/features/tests/test_testing.py djblets/features/level.py djblets/features/checkers.py djblets/features/testing.py Ignored Files: docs/djblets/guides/features/intro.rst docs/djblets/guides/features/index.rst docs/djblets/guides/index.rst docs/djblets/guides/features/testing.rst docs/djblets/guides/features/writing-feature-checkers.rst docs/djblets/guides/features/writing-features.rst docs/djblets/coderef/index.rst djblets/features/templatetags/__init__.py djblets/features/tests/__init__.py Tool: Pyflakes Processed Files: djblets/features/tests/test_feature.py djblets/features/tests/test_checkers.py djblets/features/feature.py djblets/features/errors.py djblets/registries/registry.py djblets/features/tests/test_template_tags.py djblets/features/tests/test_registry.py djblets/features/templatetags/features.py djblets/features/registry.py djblets/siteconfig/models.py djblets/features/__init__.py djblets/features/tests/test_testing.py djblets/features/level.py djblets/features/checkers.py djblets/features/testing.py Ignored Files: docs/djblets/guides/features/intro.rst docs/djblets/guides/features/index.rst docs/djblets/guides/index.rst docs/djblets/guides/features/testing.rst docs/djblets/guides/features/writing-feature-checkers.rst docs/djblets/guides/features/writing-features.rst docs/djblets/coderef/index.rst djblets/features/templatetags/__init__.py djblets/features/tests/__init__.py
-
-
-
-
Tool: Pyflakes Processed Files: djblets/features/tests/test_feature.py djblets/features/tests/test_checkers.py djblets/features/feature.py djblets/features/errors.py djblets/registries/registry.py djblets/features/tests/test_template_tags.py djblets/features/tests/test_registry.py djblets/features/templatetags/features.py djblets/features/registry.py djblets/siteconfig/models.py djblets/features/__init__.py djblets/features/tests/test_testing.py djblets/features/level.py djblets/features/checkers.py djblets/features/testing.py Ignored Files: docs/djblets/guides/features/intro.rst docs/djblets/guides/features/index.rst docs/djblets/guides/index.rst docs/djblets/guides/features/testing.rst docs/djblets/guides/features/writing-feature-checkers.rst docs/djblets/guides/features/writing-features.rst docs/djblets/coderef/index.rst djblets/features/templatetags/__init__.py djblets/features/tests/__init__.py Tool: PEP8 Style Checker Processed Files: djblets/features/tests/test_feature.py djblets/features/tests/test_checkers.py djblets/features/feature.py djblets/features/errors.py djblets/registries/registry.py djblets/features/tests/test_template_tags.py djblets/features/tests/test_registry.py djblets/features/templatetags/features.py djblets/features/registry.py djblets/siteconfig/models.py djblets/features/__init__.py djblets/features/tests/test_testing.py djblets/features/level.py djblets/features/checkers.py djblets/features/testing.py Ignored Files: docs/djblets/guides/features/intro.rst docs/djblets/guides/features/index.rst docs/djblets/guides/index.rst docs/djblets/guides/features/testing.rst docs/djblets/guides/features/writing-feature-checkers.rst docs/djblets/guides/features/writing-features.rst docs/djblets/coderef/index.rst djblets/features/templatetags/__init__.py djblets/features/tests/__init__.py