Simple feature flags with percentage rollout and user targeting.
pip install philiprehberger-feature-flagSimple feature flags with percentage rollout and user targeting.
pip install philiprehberger-feature-flag
from philiprehberger_feature_flag import flags
flags.load({"dark_mode": True, "beta_ui": False})
if flags.is_enabled("dark_mode"):
enable_dark_mode()
from philiprehberger_feature_flag import flags
flags.load({
"new_checkout": {
"enabled": True,
"rollout": 25, # 25% of users
}
})
if flags.is_enabled("new_checkout", user_id="user-42"):
show_new_checkout()
from philiprehberger_feature_flag import flags
flags.load({
"admin_panel": {
"enabled": True,
"users": ["alice", "bob"],
}
})
if flags.is_enabled("admin_panel", user_id="alice"):
show_admin_panel()
from philiprehberger_feature_flag import flags
flags.define_segment("beta_testers", {"plan": "beta", "region": "us"})
flags.load({
"new_ui": {
"enabled": True,
"segments": ["beta_testers"],
}
})
if flags.is_enabled("new_ui", plan="beta", region="us"):
show_new_ui()
from philiprehberger_feature_flag import flags
flags.load({"auth": True, "billing": True, "premium": True})
flags.add_dependency("premium", "auth")
flags.add_dependency("premium", "billing")
# premium is only enabled when both auth and billing are enabled
flags.is_enabled("premium") # True
from datetime import datetime, timezone
from philiprehberger_feature_flag import flags
flags.load({"launch": True})
flags.schedule(
"launch",
activate_at=datetime(2026, 7, 1, tzinfo=timezone.utc),
deactivate_at=datetime(2026, 8, 1, tzinfo=timezone.utc),
)
# Flag is only enabled between July 1 and August 1
flags.is_enabled("launch")
from philiprehberger_feature_flag import flags
def on_flag_change(name, old, new):
print(f"Flag {name} changed from {old} to {new}")
flags.on_change(on_flag_change)
flags.load({"dark_mode": True})
# prints: Flag dark_mode changed from None to True
flags.remove_listener(on_flag_change)
from philiprehberger_feature_flag import flags
flags.load({"feature_a": True, "feature_b": False})
snap = flags.snapshot()
# Modify state for testing
flags.override("feature_b", True)
assert flags.is_enabled("feature_b")
# Restore original state
flags.restore(snap)
assert not flags.is_enabled("feature_b")
from philiprehberger_feature_flag import flags
flags.load("flags.json")
from philiprehberger_feature_flag import flags
# Set FF_DARK_MODE=true, FF_BETA=0, etc.
flags.load() # reads FF_* env vars
from philiprehberger_feature_flag import flags
flags.override("beta_ui", True) # force-enable for testing
flags.reset() # clear all overrides
from philiprehberger_feature_flag import flags
flags.load({"dark_mode": True, "beta": False})
flags.is_enabled("dark_mode")
flags.is_enabled("dark_mode")
flags.is_enabled("beta")
flags.export_metrics()
# {
# "dark_mode": {"enabled_count": 2, "disabled_count": 0, "total_evaluations": 2},
# "beta": {"enabled_count": 0, "disabled_count": 1, "total_evaluations": 1},
# }
flags.reset_metrics() # zero counters; flag definitions untouched
from philiprehberger_feature_flag import flags
flags.load({
"ui_dark_mode": True,
"ui_sidebar": False,
"api_rate_limit": 100,
})
ui_flags = flags.group("ui_")
# {"ui_dark_mode": True, "ui_sidebar": False}
| Function / Class | Description |
|---|---|
FlagStore() | Create a new flag store |
store.load(config) | Load flags from dict, JSON file path, or env vars (None) |
store.is_enabled(name, **context) | Check if a flag is enabled |
store.all() | Return all loaded flags as a dict |
store.override(name, value) | Set a runtime override |
store.reset() | Clear all runtime overrides |
store.on_change(callback) | Register a callback fired as callback(flag_name, old_value, new_value) on changes |
store.remove_listener(callback) | Remove a previously registered change callback |
store.group(prefix) | Return dict of flags whose name starts with prefix with resolved values |
store.define_segment(name, attributes) | Define a user segment with required attribute key-value pairs |
store.remove_segment(name) | Remove a previously defined segment |
store.add_dependency(flag, depends_on) | Declare that flag requires depends_on to be enabled |
store.remove_dependency(flag, depends_on) | Remove a dependency from a flag |
store.schedule(name, activate_at, deactivate_at) | Schedule a flag to activate/deactivate at specific datetimes |
store.remove_schedule(name) | Remove the schedule for a flag |
store.snapshot() | Capture full store state (flags, overrides, segments, dependencies, schedules) |
store.restore(snap) | Restore the store to a previously captured snapshot |
store.export_metrics() | Return a snapshot of per-flag enabled_count, disabled_count, and total_evaluations counters |
store.reset_metrics() | Zero all usage counters without touching flag definitions |
flags | Module-level FlagStore instance |
pip install -e .
python -m pytest tests/ -v
If you find this project useful: