diff --git a/README.md b/README.md index 71e1657..ddb03a3 100644 --- a/README.md +++ b/README.md @@ -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/). diff --git a/main.py b/main.py old mode 100755 new mode 100644 index 06022e8..63394b4 --- a/main.py +++ b/main.py @@ -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 @@ -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__": diff --git a/requirements.txt b/requirements.txt index 58a5592..7898a81 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -featurevisor==2.0.0 +featurevisor==3.0.0