Skip to main content

OpenFeature provider for Cloudflare Flagship feature flags.

Project description

cloudflare-flagship

PyPI version Python versions license

Flagship is a globally distributed, low-latency feature flag platform built entirely on Cloudflare. This package is the Python SDK — an OpenFeature-compliant provider for evaluating feature flags from Python server environments.

Note: The Python SDK supports HTTP mode only. The Cloudflare Workers binding mode (env.FLAGS) is exclusive to the TypeScript SDK and is not available in Python.

Installation

# uv
uv add cloudflare-flagship

# pip
pip install cloudflare-flagship

Quick start

from openfeature import api
from openfeature.evaluation_context import EvaluationContext
from flagship import FlagshipServerProvider

api.set_provider(
    FlagshipServerProvider(
        app_id="your-app-id",
        account_id="your-account-id",
        auth_token="your-token",
    )
)

client = api.get_client()
enabled = client.get_boolean_value(
    "dark-mode",
    False,
    EvaluationContext(targeting_key="user-123", attributes={"plan": "premium"}),
)

See examples/server.py for a full synchronous example and examples/async_server.py for async usage with asyncio.

Flag types

All four OpenFeature flag types are supported. Python's OpenFeature SDK splits the TypeScript number type into integer and float.

enabled = client.get_boolean_value("new-checkout", False, context)
variant = client.get_string_value("homepage-hero", "control", context)
limit   = client.get_integer_value("upload-limit", 10, context)
rate    = client.get_float_value("sample-rate", 0.1, context)
config  = client.get_object_value("ui-config", {"theme": "light"}, context)

Use the *_details variants when you need the full resolution result:

details = client.get_boolean_details("my-flag", False, context)

print(details.value)          # resolved value (or default on error)
print(details.reason)         # TARGETING_MATCH | SPLIT | DEFAULT | DISABLED | ERROR
print(details.variant)        # variation key, e.g. "on", "off", "v2"
print(details.error_code)     # set on error, e.g. FLAG_NOT_FOUND, TYPE_MISMATCH
print(details.error_message)

Configuration

FlagshipServerProvider accepts either app_id + account_id (recommended) or a full endpoint URL — not both.

FlagshipServerProvider(
    # Option A (recommended)
    app_id="your-app-id",
    account_id="your-account-id",

    # Option B: full URL (mutually exclusive with app_id)
    # endpoint="http://localhost:8787/v1/acct/apps/app-id/evaluate",

    # Static bearer token
    auth_token="your-token",

    # Dynamic credentials — called once per request, takes precedence over auth_token
    # headers_factory=lambda: {"Authorization": f"Bearer {get_token()}"},

    # Override the base URL for local dev
    # base_url="http://localhost:8787",

    timeout=5.0,      # seconds (default: 5.0)
    retries=1,        # retry attempts on transient errors, capped at 10 (default: 1)
    retry_delay=1.0,  # seconds between retries, capped at 30.0 (default: 1.0)
    logging=False,    # set True to enable SDK debug output (default: False)

    # Response caching — opt-in, off by default (see "Caching")
    # cache_ttl=30.0,      # seconds; enables caching when set
    # cache_max_size=1000, # max cached entries, LRU-evicted (default: 1000)
)
Option Type Default Description
app_id str Flagship app ID (mutually exclusive with endpoint)
account_id str Required with app_id
base_url str https://api.cloudflare.com Base URL override (only used with app_id)
endpoint str Full evaluation URL (mutually exclusive with app_id)
auth_token str Bearer token added to every request
headers_factory Callable[[], dict[str, str]] Called per request; takes precedence over auth_token
timeout float 5.0 Request timeout in seconds
retries int 1 Retry attempts on transient errors; capped at 10
retry_delay float 1.0 Delay between retries in seconds; capped at 30.0
logging bool False Enable SDK-level debug output via the flagship logger
cache_ttl float Cache TTL in seconds; enables caching when set
cache_max_size int 1000 Maximum cached entries; least-recently-used is evicted

Caching

The provider can cache evaluations to avoid a network round-trip for repeated flag/context pairs. Caching is off by default and enabled by setting cache_ttl (seconds):

FlagshipServerProvider(
    app_id="your-app-id",
    account_id="your-account-id",
    cache_ttl=30.0,        # cached values may be up to 30s stale
    cache_max_size=1000,   # LRU eviction beyond this many entries
)

Each entry is keyed by flag key, type, and the full evaluation context, so distinct contexts never share a value. Cache hits resolve with reason == Reason.CACHED. Disabled flags and errors are never cached. Because freshness is TTL-based, a flag change in Flagship takes effect after the entry expires.

The cache is shared by the sync and async APIs and guarded by a lock for thread-safe sync use.

Evaluation context

Context attributes are sent as URL query parameters. Supported types:

Type Serialisation
str, int, float Passed as a string
bool "true" or "false"
datetime ISO 8601
dict, list, other Not supported — raises InvalidContextError

Async

The async API mirrors the sync API — just await the *_async variants:

enabled = await client.get_boolean_value_async("dark-mode", False, context)
details = await client.get_boolean_details_async("dark-mode", False, context)

# Evaluate multiple flags concurrently
import asyncio
dark_mode, beta_access = await asyncio.gather(
    client.get_boolean_value_async("dark-mode", False, context),
    client.get_boolean_value_async("beta-access", False, context),
)

When shutting down in an async context, use shutdown_async() to properly close the HTTP client:

await api.shutdown_async()

Error handling

The provider never throws from a resolution method. On error the OpenFeature SDK returns the default value with an error_code and error_message.

Error code Cause
FLAG_NOT_FOUND Flag key does not exist (HTTP 404)
TYPE_MISMATCH The flag's resolved type does not match the requested type
INVALID_CONTEXT The evaluation context contains unsupported types (dict, list)
PARSE_ERROR The API response was not a valid evaluation response
GENERAL Network error, timeout, or any other transient failure

404 and 400 responses are never retried. All other failures are retried up to retries times.

Hooks

from flagship import LoggingHook, TelemetryHook

# Logs evaluation lifecycle events via the flagship logger (INFO level)
api.add_hooks([LoggingHook()])

# Emits a TelemetryEvent after every evaluation
api.add_hooks([TelemetryHook(lambda event: analytics.track("flag_evaluated", event))])

TelemetryEvent fields: type, flag_key, timestamp, duration_ms, value, reason, variant, error_code, error_message, context, hints.

Provider events

from openfeature.event import ProviderEvent

api.add_handler(ProviderEvent.PROVIDER_READY, lambda _: print("ready"))

Initialization does not perform network I/O. Flag evaluation requests happen only when resolving flags.

Development

uv sync --group dev        # install dependencies
uv run pytest              # run tests
uv run ty check            # type check
uv build                   # build wheel and sdist

License

Apache-2.0

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

cloudflare_flagship-0.4.0.tar.gz (14.3 kB view details)

Uploaded Source

Built Distribution

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

cloudflare_flagship-0.4.0-py3-none-any.whl (17.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: cloudflare_flagship-0.4.0.tar.gz
  • Upload date:
  • Size: 14.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for cloudflare_flagship-0.4.0.tar.gz
Algorithm Hash digest
SHA256 a38d97dea70fbee3a276c92a84b114d7bcc167828da142e326ff169e1697a5b4
MD5 9e04db73e13e1e71bb04d60fd932f26e
BLAKE2b-256 2cf51486fff7818522f5d4357c31cf8b92c72da6dda92ebf068656babaa3c232

See more details on using hashes here.

File details

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

File metadata

  • Download URL: cloudflare_flagship-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 17.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for cloudflare_flagship-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9df7d804ca60cf94276a56745d4eaf90b2f1b00d904bae17e3a396ed921cf41c
MD5 9e4c9935e5ec6e2e02588cb55653fd2b
BLAKE2b-256 e6db801d6dccc8b95195e9cf45cd3958ffdcbc40652b42d4f3eebbbf595a4560

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