Add support for light-weight feature checks.

Review Request #8031 — Created March 4, 2016 and submitted

Information

Djblets
release-0.10.x

Reviewers

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

reviewbotreviewbot

redefinition of unused 'test_is_enabled_with_unavailable' from line 91

reviewbotreviewbot

'settings' imported but unused

reviewbotreviewbot

'Site' imported but unused

reviewbotreviewbot

'ImproperlyConfigured' imported but unused

reviewbotreviewbot

'set_feature_checker' imported but unused

reviewbotreviewbot

'SiteConfigFeatureChecker' imported but unused

reviewbotreviewbot

'SettingsFeatureChecker' imported but unused

reviewbotreviewbot

'BaseFeatureChecker' imported but unused

reviewbotreviewbot

'get_feature_checker' imported but unused

reviewbotreviewbot

'FeatureNotFoundError' imported but unused

reviewbotreviewbot

'SiteConfiguration' imported but unused

reviewbotreviewbot

local variable 't' is assigned to but never used

reviewbotreviewbot

local variable 't' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

local variable 't' is assigned to but never used

reviewbotreviewbot

local variable 't' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

local variable 'feature' is assigned to but never used

reviewbotreviewbot

'cache' imported but unused

reviewbotreviewbot

Can we log the original exception?

daviddavid

Missing closing paren.

brenniebrennie

I think we should initialize the feature before registering it.

daviddavid

This should be djblets.features.feature.Feature

brenniebrennie

Docstrings in this file?

daviddavid

'Site' imported but unused

reviewbotreviewbot

Too many blank lines.

daviddavid

Too many blank lines.

daviddavid

typo: "registerd"

daviddavid

I don't suppose it's possible to extract the docs for these from the code?

daviddavid

Can you add a period here?

daviddavid

Can you add a period here?

daviddavid

undefined name 'feature_id'

reviewbotreviewbot

'set_feature_checker' imported but unused

reviewbotreviewbot

'get_feature_checker' imported but unused

reviewbotreviewbot
reviewbot
  1. 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
    
    
    
    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
    
    
  2. Show all issues
     'FeatureNotFoundError' imported but unused
    
  3. djblets/features/tests/test_feature.py (Diff revision 1)
     
     
    Show all issues
     redefinition of unused 'test_is_enabled_with_unavailable' from line 91
    
  4. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'settings' imported but unused
    
  5. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'Site' imported but unused
    
  6. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'ImproperlyConfigured' imported but unused
    
  7. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'set_feature_checker' imported but unused
    
  8. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'SiteConfigFeatureChecker' imported but unused
    
  9. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'SettingsFeatureChecker' imported but unused
    
  10. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'BaseFeatureChecker' imported but unused
    
  11. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'get_feature_checker' imported but unused
    
  12. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'FeatureNotFoundError' imported but unused
    
  13. djblets/features/tests/test_registry.py (Diff revision 1)
     
     
    Show all issues
     'SiteConfiguration' imported but unused
    
  14. Show all issues
     local variable 't' is assigned to but never used
    
  15. Show all issues
     local variable 't' is assigned to but never used
    
  16. Show all issues
     local variable 'feature' is assigned to but never used
    
  17. Show all issues
     local variable 'feature' is assigned to but never used
    
  18. Show all issues
     local variable 'feature' is assigned to but never used
    
  19. Show all issues
     local variable 'feature' is assigned to but never used
    
  20. Show all issues
     local variable 't' is assigned to but never used
    
  21. Show all issues
     local variable 't' is assigned to but never used
    
  22. Show all issues
     local variable 'feature' is assigned to but never used
    
  23. Show all issues
     local variable 'feature' is assigned to but never used
    
  24. Show all issues
     local variable 'feature' is assigned to but never used
    
  25. Show all issues
     local variable 'feature' is assigned to but never used
    
  26. djblets/siteconfig/models.py (Diff revision 1)
     
     
    Show all issues
     'cache' imported but unused
    
  27. 
      
chipx86
reviewbot
  1. 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
    
    
  2. djblets/features/tests/test_registry.py (Diff revision 2)
     
     
    Show all issues
     'Site' imported but unused
    
  3. 
      
david
  1. 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?

    1. Good idea. Will do!

  2. djblets/features/checkers.py (Diff revision 2)
     
     
     
     
    Show all issues

    Can we log the original exception?

  3. djblets/features/registry.py (Diff revision 2)
     
     
     
     
    Show all issues

    I think we should initialize the feature before registering it.

  4. Show all issues

    Docstrings in this file?

  5. djblets/features/tests/test_checkers.py (Diff revision 2)
     
     

    :)

  6. docs/djblets/guides/features/intro.rst (Diff revision 2)
     
     
     
    Show all issues

    Too many blank lines.

  7. docs/djblets/guides/features/intro.rst (Diff revision 2)
     
     
     
    Show all issues

    Too many blank lines.

  8. Show all issues

    typo: "registerd"

  9. docs/djblets/guides/features/writing-features.rst (Diff revision 2)
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    I don't suppose it's possible to extract the docs for these from the code?

    1. Kind of is, but the presentation isn't quite right for this guide, and ends up not linking to the right place anymore (wants to link to itself).

  10. Show all issues

    Can you add a period here?

  11. Show all issues

    Can you add a period here?

  12. 
      
brennie
  1. 
      
  2. djblets/features/registry.py (Diff revision 2)
     
     
    Show all issues

    Missing closing paren.

  3. djblets/features/registry.py (Diff revision 2)
     
     
    Show all issues

    This should be djblets.features.feature.Feature

  4. 
      
chipx86
reviewbot
  1. 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
    
    
  2. Show all issues
     undefined name 'feature_id'
    
  3. djblets/features/testing.py (Diff revision 3)
     
     
    Show all issues
     'set_feature_checker' imported but unused
    
  4. djblets/features/testing.py (Diff revision 3)
     
     
    Show all issues
     'get_feature_checker' imported but unused
    
  5. 
      
chipx86
reviewbot
  1. 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
    
    
  2. 
      
david
  1. Ship It!
  2. 
      
chipx86
Review request changed
Status:
Completed
Change Summary:
Pushed to release-0.10.x (9e2737e)