Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,50 @@
# featurevisor-example-python

Tiny example application using the [Featurevisor Python SDK](https://github.com/featurevisor/featurevisor-python).
A small Python application showing how to use the [Featurevisor Python SDK](https://github.com/featurevisor/featurevisor-python).

Learn more about Featurevisor at [featurevisor.com](https://featurevisor.com).
Learn more about Featurevisor [here](https://featurevisor.com).

It fetches a production datafile, creates a Featurevisor instance with customer context, then evaluates a flag, a variation, feature variables, and global variables.

## Requirements

- Python 3.10+
Python 3.10 or newer.

## Installation

```bash
```sh
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

## Usage
## Run the example

```bash
```sh
python main.py
```

## What It Does
The application evaluates `commerce_platform`, `checkout_experience`, `max_items`, `payment_methods`, `serviceEndpoints`, and `supportContact` from this datafile:

```text
https://featurevisor-example-cloudflare.pages.dev/production/featurevisor-sdk-v3.json
```

The script fetches the remote datafile, builds a Featurevisor instance, sets this default context, and evaluates a feature:
Expected output:

```json
{
"userId": "123",
"deviceId": "device-23456",
"country": "nl"
}
```text
Commerce platform enabled: true
Checkout variation: express
Maximum checkout items: 25
Payment methods: ['card', 'wallet']
Service endpoint: https://api.eu.example.com (timeout: 1200 ms, retries: 4)
Support contact: support-nl@example.com
```

It evaluates `my_feature`, which exists in the sample datafile.
Change the context in `main.py` to see how Featurevisor selects different rules, variations, and global variable overrides.

## Featurevisor project

Uses this Featurevisor project to fetch the configuration from: https://github.com/featurevisor/featurevisor-example-cloudflare
The datafile is generated by the [Featurevisor Cloudflare example](https://github.com/featurevisor/featurevisor-example-cloudflare).

Learn more in the [Featurevisor Python SDK documentation](https://featurevisor.com/docs/sdks/python/).
69 changes: 48 additions & 21 deletions main.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,26 @@

from featurevisor import create_featurevisor

DATAFILE_URL = "https://featurevisor-example-cloudflare.pages.dev/production/featurevisor-tag-all.json"
FEATURE_KEY = "my_feature"
DATAFILE_URL = "https://featurevisor-example-cloudflare.pages.dev/production/featurevisor-sdk-v3.json"
CONTEXT = {
"userId": "123",
"deviceId": "device-23456",
"userId": "customer-123",
"country": "nl",
"locale": "nl-NL",
"accountPlan": "pro",
}


def fetch_datafile(url: str) -> dict:
request = Request(
url,
headers={
"User-Agent": "featurevisor-example-python/1.0",
"Accept": "application/json",
},
)

try:
request = Request(
url,
headers={
"User-Agent": "featurevisor-example-python/1.0",
"Accept": "application/json",
},
)
with urlopen(request) as response:
with urlopen(request, timeout=10) as response:
return json.load(response)
except HTTPError as exc:
raise RuntimeError(f"failed to fetch datafile: HTTP {exc.code}") from exc
Expand All @@ -34,20 +35,46 @@ def fetch_datafile(url: str) -> dict:


def main() -> int:
f = None

try:
datafile = fetch_datafile(DATAFILE_URL)
f = create_featurevisor({"datafile": datafile, "logLevel": "error"})
f.set_context(CONTEXT)
enabled = f.is_enabled(FEATURE_KEY)
f = create_featurevisor(
{
"datafile": fetch_datafile(DATAFILE_URL),
"context": CONTEXT,
"logLevel": "error",
}
)

commerce_enabled = f.is_enabled("commerce_platform")
checkout_variation = f.get_variation("checkout_experience")
max_items = f.get_variable_integer("checkout_experience", "max_items")
payment_methods = f.get_variable_array(
"checkout_experience", "payment_methods"
)
endpoints = f.get_variable_object("serviceEndpoints")
support_contact = f.get_variable_string("supportContact")

print(f"Commerce platform enabled: {str(commerce_enabled).lower()}")
print(f"Checkout variation: {value_or_unavailable(checkout_variation)}")
print(f"Maximum checkout items: {value_or_unavailable(max_items)}")
print(f"Payment methods: {payment_methods or []}")
print(
f"Service endpoint: {endpoints['baseUrl']} "
f"(timeout: {endpoints['timeoutMs']} ms, retries: {endpoints['retries']})"
)
print(f"Support contact: {value_or_unavailable(support_contact)}")
return 0
except Exception as exc:
print(f"Error: {exc}", file=sys.stderr)
return 1
finally:
if f is not None:
f.close()


print(f"Datafile revision: {f.get_revision()}")
print(f"Context: {json.dumps(CONTEXT)}")
print(f"Feature '{FEATURE_KEY}' enabled: {enabled}")
print(f"All evaluations: {json.dumps(f.get_all_evaluations(), sort_keys=True)}")
return 0
def value_or_unavailable(value: object) -> object:
return "unavailable" if value is None else value


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
featurevisor==2.0.0
featurevisor==3.0.0