Skip to main content

Simple feature flags with percentage rollout and user targeting.

Project description

philiprehberger-feature-flag

Tests PyPI version Last updated

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:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

philiprehberger_feature_flag-0.4.0.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

philiprehberger_feature_flag-0.4.0-py3-none-any.whl (8.6 kB view details)

Uploaded Python 3

File details

Details for the file philiprehberger_feature_flag-0.4.0.tar.gz.

File metadata

File hashes

Hashes for philiprehberger_feature_flag-0.4.0.tar.gz
Algorithm Hash digest
SHA256 315f62ca200318ce7f85990b0d9064d746d56f76d154c4b72dc3f0d397c48c44
MD5 097761c41baef5caefe3d0cb0ab3e521
BLAKE2b-256 27a634d5112759d370886454ad5941ab6324d5f9d6527265521a4ffbbb2e648a

See more details on using hashes here.

File details

Details for the file philiprehberger_feature_flag-0.4.0-py3-none-any.whl.

File metadata

File hashes

Hashes for philiprehberger_feature_flag-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4efe92223e6296395c1e9306e75a3e3a1a927f4a375ba60f8e44f24c39abe80e
MD5 13ff5c9c9970f8ba66603b419fe8a421
BLAKE2b-256 d89195d6eafdddb14637f3e7c20413ea10f28da536f0dd65f6984411e8827073

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page