philiprehberger-feature-flag
Simple feature flags with percentage rollout and user targeting.
Installation
pip install philiprehberger-feature-flag
Usage
from philiprehberger_feature_flag import flags
flags.load({"dark_mode": True, "beta_ui": False})
if flags.is_enabled("dark_mode"):
enable_dark_mode()
Percentage rollout
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()
User targeting
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()
Segment targeting
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()
Flag dependencies
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
Scheduled activation
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")
Change callbacks
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)
Snapshot and restore
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")
Load from JSON file
from philiprehberger_feature_flag import flags
flags.load("flags.json")
Load from environment variables
from philiprehberger_feature_flag import flags
# Set FF_DARK_MODE=true, FF_BETA=0, etc.
flags.load() # reads FF_* env vars
Runtime overrides
from philiprehberger_feature_flag import flags
flags.override("beta_ui", True) # force-enable for testing
flags.reset() # clear all overrides
Usage metrics
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
Flag groups
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}
API
| 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 |
Development
pip install -e .
python -m pytest tests/ -v
Support
If you find this project useful:
License
Release files for philiprehberger-feature-flag 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| philiprehberger_feature_flag-0.4.0.tar.gz | 11.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| philiprehberger_feature_flag-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.2 kB
Release files / philiprehberger_feature_flag-0.4.0.tar.gz
| Download URL | philiprehberger_feature_flag-0.4.0.tar.gz |
|---|---|
| Size | 11.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
315f62ca200318ce7f85990b0d9064d746d56f76d154c4b72dc3f0d397c48c44
|
|
BLAKE2b-256 checksum How to use checksums |
27a634d5112759d370886454ad5941ab6324d5f9d6527265521a4ffbbb2e648a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / philiprehberger_feature_flag-0.4.0-py3-none-any.whl
| Download URL | philiprehberger_feature_flag-0.4.0-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4efe92223e6296395c1e9306e75a3e3a1a927f4a375ba60f8e44f24c39abe80e
|
|
BLAKE2b-256 checksum How to use checksums |
d89195d6eafdddb14637f3e7c20413ea10f28da536f0dd65f6984411e8827073
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|