FlagrshipGuidesReference
esc

Python SDK

The same SDK, in Python. Standard library only, thread-safe, and it passes the same conformance file as the JavaScript SDK line for line.

Install

$ pip install flagrship-sdk

Python 3.9 or later. No dependencies: urllib for HTTP and threading for the poll loop.

Usage

app.py
1import os
2from flagrship import Flagrship
3 
4flags = Flagrship(
5 api_key=os.environ["FLAGRSHIP_KEY"],
6 defaults={"new-checkout": False},
7)
8 
9# Blocks until the first sync attempt finishes. Never raises.
10flags.ready()
11 
12if flags.is_enabled("new-checkout", user.id):
13 show_new_checkout()

Or as a context manager, which waits for ready() on entry and stops polling on exit:

with Flagrship(api_key=key) as flags:
if flags.is_enabled("new-checkout", user.id):
show_new_checkout()

Constructor arguments

api_key is positional; everything else is keyword-only.

ArgumentTypeDefaultWhat it does
api_keystrrequiredA read-scoped key for one environment.
api_urlstrhttps://api.flagrship.devOverride for self-hosted or local APIs.
poll_intervalfloat30.0Seconds between polls. 0 disables polling.
defaultsMapping[str, bool]{}What is_enabled returns for unknown flags.
on_updateCallable[[dict], None]NoneCalled after every successful config change.
on_errorCallable[[Exception], None]NoneCalled when a sync fails. Last config keeps serving.
transportCallableurllibInjectable for tests. See the source for the signature.

Methods

ready(timeout=None)

Blocks until the first sync attempt finishes. Returns False only if timeout elapsed first. Never raises. The first sync runs on a background thread, so construction itself never blocks.

is_enabled(flag_key, user_id=None, default=None)

Same five-step evaluation as the JavaScript SDK:

  • Unknown flag → default, then defaults[flag_key], then False
  • Disabled → False
  • Rollout 100 → True
  • No user ID and rollout below 100 → False
  • Otherwise bucket(flag_key, user_id) < rollout_percentage

get_flag(flag_key)

A frozen FlagConfig dataclass, or None. Fields: key, enabled, rollout_percentage, targeting_rules.

all_flags()

A snapshot dict. Safe to iterate while polling continues.

refresh()

Sync now. Returns True if config changed. Never raises.

close()

Stop the poll thread. The last config stays in memory.

Threads

Evaluation is lock-free. Each successful sync replaces the whole config dict in a single assignment, which is atomic in CPython, so a reader on any thread sees either the old snapshot or the new one and never a partially written mix. A lock serialises writers only (the poll thread versus an explicit refresh()).

Both background threads are daemon threads. Your process exits when your code finishes; the SDK never keeps it alive.

Bucketing

from flagrship import bucket, murmurhash3_x86_32
 
bucket("new-checkout", "alice") # 40
murmurhash3_x86_32("hello") # 613153351

These return exactly what the JavaScript SDK returns for the same input. Both implementations are checked against the same fixture file on every commit.

Flagrship · Ship without a release.