Metadata-Version: 2.4
Name: flagdrop-sdk
Version: 0.3.0
Summary: FlagDrop Python SDK — evaluate feature flags from your cloud bucket
Author-email: FlagDrop <support@flagdrop.io>
License-Expression: MIT
Project-URL: Homepage, https://flagdrop.io
Project-URL: Documentation, https://flagdrop.io/docs
Keywords: feature-flags,flagdrop,sdk,s3,gcs,azure,feature-toggles
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: aws
Requires-Dist: boto3>=1.28.0; extra == "aws"
Provides-Extra: gcp
Requires-Dist: google-cloud-storage>=2.14.0; extra == "gcp"
Provides-Extra: azure
Requires-Dist: azure-storage-blob>=12.19.0; extra == "azure"
Requires-Dist: azure-identity>=1.15.0; extra == "azure"
Provides-Extra: all
Requires-Dist: boto3>=1.28.0; extra == "all"
Requires-Dist: google-cloud-storage>=2.14.0; extra == "all"
Requires-Dist: azure-storage-blob>=12.19.0; extra == "all"
Requires-Dist: azure-identity>=1.15.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
Requires-Dist: moto[s3]>=5.0; extra == "dev"

<p align="center">
  <a href="https://flagdrop.io">
    <img src="https://flagdrop.io/og-image.png" alt="FlagDrop — Feature flags that run where your code runs" width="600">
  </a>
</p>

<p align="center">
  <a href="https://pypi.org/project/flagdrop-sdk/"><img src="https://img.shields.io/pypi/v/flagdrop-sdk?color=3B82F6&label=pypi" alt="PyPI"></a>
  <a href="https://pypi.org/project/flagdrop-sdk/"><img src="https://img.shields.io/pypi/pyversions/flagdrop-sdk?color=3B82F6" alt="Python"></a>
  <a href="https://github.com/flagdrop-io/platform/blob/main/LICENSE"><img src="https://img.shields.io/pypi/l/flagdrop-sdk?color=3B82F6" alt="License"></a>
</p>

# FlagDrop Python SDK

Feature flag management where evaluations run entirely inside **your** cloud. No vendor servers. No data leaving your infrastructure. No single point of failure.

FlagDrop pushes a lightweight JSON config to a storage bucket in your cloud account. The SDK reads that file and evaluates flags locally at runtime — zero network calls to external servers during evaluation.

## Installation

Install the SDK with the cloud provider you need:

```bash
# AWS
pip install flagdrop-sdk[aws]

# GCP
pip install flagdrop-sdk[gcp]

# Azure
pip install flagdrop-sdk[azure]

# All providers
pip install flagdrop-sdk[all]
```

Only the cloud library for your provider is required — unused providers are never imported.

## Quick Start

```python
from flagdrop import FlagClient

client = FlagClient(
    bucket="my-app-flags",
    environment="production",
    provider="aws",
    region="us-east-1",
)
client.initialize()

# Boolean flag
enabled = client.get_bool("new-checkout", False)

# String flag with targeting context
theme = client.get_string("app-theme", "light", {"plan": "enterprise"})

# Number flag
max_items = client.get_number("max-items", 10)

# JSON flag
config = client.get_json("feature-config", {"limit": 5})
```

## How It Works

```
  ┌──────────────────┐      ┌──────────────────────────────────────┐
  │  FlagDrop Cloud   │      │  Your Cloud (AWS / Azure / GCP)      │
  │                   │      │                                      │
  │  Dashboard ───────┼──────▶  S3 / Blob Storage / GCS Bucket     │
  │  (define flags)   │ push │  (JSON config file)                  │
  └──────────────────┘      │         │                             │
                             │         ▼                             │
                             │  ┌──────────────┐                    │
                             │  │  Your App     │                    │
                             │  │  + FlagDrop   │  ← evaluates      │
                             │  │    SDK        │    flags locally   │
                             │  └──────────────┘                    │
                             └──────────────────────────────────────┘
```

1. **Define flags** in the FlagDrop dashboard — boolean, string, number, or JSON
2. **FlagDrop pushes** a JSON config file to a storage bucket in your cloud account
3. **The SDK reads** that file locally and evaluates flags at runtime

The critical difference: flag evaluation happens inside your infrastructure. User context never leaves your cloud. There are no network calls to FlagDrop servers at evaluation time.

## Cloud Providers

| Provider | Status | Storage |
|----------|--------|---------|
| **AWS** | GA | Amazon S3 |
| **Azure** | GA | Azure Blob Storage |
| **GCP** | GA | Google Cloud Storage |

All three major cloud providers are fully supported. The `provider` parameter controls which cloud storage backend is used.

## All Flag Types

### Boolean

```python
enabled = client.get_bool("dark-mode", False)
```

### String

```python
theme = client.get_string("color-theme", "light")
```

### Number

```python
rate_limit = client.get_number("api-rate-limit", 100)
```

### JSON

```python
plan_config = client.get_json("plan-features", {"max_seats": 5})
```

Each getter returns the flag's configured value when the flag is found and enabled, or the caller-provided default when the flag is missing, disabled, or the wrong type.

## Targeting Rules

Pass user context to evaluate targeting rules. Rules are evaluated locally — context never leaves your infrastructure.

```python
# Target by user attribute
ui = client.get_string("checkout-ui", "standard", {
    "plan": "enterprise",
    "country": "US",
    "email": "admin@acme.com",
})

# Target by segment membership
variant = client.get_string("landing-page", "control", {
    "segments": ["beta-testers"],
})
```

### Typed Context Values

Context values can be strings, numbers, booleans, or string lists. The evaluator preserves types for accurate comparisons:

```python
result = client.get_bool("age-gate", False, {
    "age": 25,              # int — compared numerically for lt/gt
    "score": 9.8,           # float — compared numerically for lt/gt
    "active": True,         # bool — exact match with eq/neq
    "tags": ["beta", "us"], # list[str] — overlap check with in/notIn
})
```

### targetingKey

Use `targetingKey` as a conventional identity key for rollout bucketing. If the rollout attribute is missing from context, the evaluator falls back to `targetingKey`:

```python
# targetingKey is used for rollout when "userId" is not provided
result = client.get_bool("new-search", False, {
    "targetingKey": "user-123",
})
```

### Supported Operators

| Operator | Description | Example |
|----------|-------------|---------|
| `eq` | Exact match | `plan == "enterprise"` |
| `neq` | Not equal | `role != "guest"` |
| `in` | Value in list | `country in ["US", "CA", "GB"]` |
| `notIn` | Value not in list | `email not in blocklist` |
| `lt` | Less than (numeric) | `age < 18` |
| `gt` | Greater than (numeric) | `requestCount > 1000` |
| `startsWith` | String prefix | `email starts with "admin"` |
| `endsWith` | String suffix | `email ends with "@acme.com"` |
| `contains` | String contains | `userAgent contains "Chrome"` |
| `segment` | Segment membership | `user in "beta-testers"` |

Rules are evaluated in order — **first match wins**. If no rule matches, the flag's default value is returned.

## Percentage Rollouts

Gradually roll out features to a percentage of users with deterministic bucketing:

```python
# Same userId always gets the same result
enabled = client.get_bool("new-search", False, {"userId": "user-123"})
```

Rollouts use FNV-1a hashing for deterministic bucketing — the same user always gets the same result across evaluations, restarts, and deployments.

## Configuration Reference

```python
client = FlagClient(
    bucket="my-flags",             # Storage bucket name (required)
    environment="production",       # Environment name (required)
    provider="aws",                 # Cloud provider: "aws", "azure", "gcp" (required)
    region="us-east-1",            # Cloud region (required)
    scope="backend",               # "backend" or "frontend" (default: "backend")
    refresh_interval_seconds=30,   # Auto-refresh interval (default: 30, 0 to disable)
)
```

### Caching & Refresh

The SDK caches the config file in memory and automatically re-fetches it based on `refresh_interval_seconds`. Set to `0` to disable auto-refresh (the config is fetched once on `initialize()` and never refreshed).

### Scopes

Flags can be scoped to `backend`, `frontend`, or `both`. The SDK only loads the config for its configured scope, so frontend-only flags won't be included in your backend config and vice versa.

## Usage in AWS Lambda

The SDK works in Lambda without any special configuration. Lambda's built-in `boto3` is used automatically — no need to bundle it.

```python
from flagdrop import FlagClient

client = FlagClient(
    bucket="my-flags",
    environment="production",
    provider="aws",
    region="us-east-1",
    refresh_interval_seconds=0,  # fetch once per invocation
)

def handler(event, context):
    client.initialize()
    if client.get_bool("new-feature", False, {"userId": event["userId"]}):
        return new_feature_handler(event)
    return legacy_handler(event)
```

For warm Lambdas, you can initialize the client outside the handler and use the default refresh interval to pick up config changes.

## Requirements

- Python 3.9+
- One of the following cloud SDKs (install via extras):
  - **AWS**: `boto3` — included in AWS Lambda, install via `pip install flagdrop-sdk[aws]`
  - **GCP**: `google-cloud-storage` — install via `pip install flagdrop-sdk[gcp]`
  - **Azure**: `azure-storage-blob` + `azure-identity` — install via `pip install flagdrop-sdk[azure]`
- Cloud credentials with read access to your flag config bucket

## Why FlagDrop?

| | Traditional Flag Services | FlagDrop |
|---|---|---|
| **Where flags evaluate** | Vendor's servers | Your cloud |
| **User context** | Sent to vendor | Never leaves your infra |
| **Vendor outage impact** | Flags stop working | No impact (local file) |
| **Latency** | Network round-trip | Local file read |
| **Data residency** | Vendor's region | Your region |
| **Lock-in** | Proprietary SDK | Standard JSON + S3 |

## Links

- [FlagDrop](https://flagdrop.io) — Feature flags in your cloud
- [Documentation](https://flagdrop.io/docs)
- [Dashboard](https://platform.flagdrop.io)
- [Twitter/X](https://x.com/flagdrop_)
