From b1e7f7b5a4b814bfd1a184ed81b437f84cf75aac Mon Sep 17 00:00:00 2001 From: Sven Schmit Date: Wed, 29 May 2024 16:24:58 -0700 Subject: [PATCH 1/5] update python examples --- example/.env.dist | 1 + example/{main.py => 01_script.py} | 4 +- example/02_fastapi.py | 40 +++++++++++++++++++ example/03_bandit.py | 64 +++++++++++++++++++++++++++++++ example/README.md | 2 +- example/requirements.txt | 2 + 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 example/.env.dist rename example/{main.py => 01_script.py} (89%) create mode 100644 example/02_fastapi.py create mode 100644 example/03_bandit.py create mode 100644 example/requirements.txt diff --git a/example/.env.dist b/example/.env.dist new file mode 100644 index 0000000..8b0339a --- /dev/null +++ b/example/.env.dist @@ -0,0 +1 @@ +EPPO_API_KEY='' \ No newline at end of file diff --git a/example/main.py b/example/01_script.py similarity index 89% rename from example/main.py rename to example/01_script.py index 1ee921f..b05bc64 100644 --- a/example/main.py +++ b/example/01_script.py @@ -30,7 +30,9 @@ def init_eppo_and_assign(): subject = "user_1234" flag_key = "my-flag-key" - assigned_variation = eppo.get_assignment(subject, flag_key) + assigned_variation = eppo.get_string_assignment( + flag_key, subject, subject_attributes={}, default="control" + ) if assigned_variation == "control": print("Assigned to control") elif assigned_variation == "treatment": diff --git a/example/02_fastapi.py b/example/02_fastapi.py new file mode 100644 index 0000000..101e10c --- /dev/null +++ b/example/02_fastapi.py @@ -0,0 +1,40 @@ +""" +Run using +`fastapi dev 02_fastapi.py` + +Test using +`curl "http://127.0.0.1:8000/hello?name=bob"` +""" + +from dotenv import load_dotenv +import os + +from fastapi import FastAPI +import eppo_client +from eppo_client.config import Config, AssignmentLogger + +load_dotenv() +EPPO_API_KEY = os.environ.get("EPPO_API_KEY") +print(EPPO_API_KEY[:5] + "...") + +app = FastAPI() + + +class LocalLogger(AssignmentLogger): + def log_assignment(self, assignment_event): + print(assignment_event) + + +client_config = Config(api_key=EPPO_API_KEY, assignment_logger=LocalLogger()) + +eppo_client.init(client_config) + + +@app.get("/hello") +async def hello(name: str): + client = eppo_client.get_instance() + + print(client.get_flag_keys()) + greeting = client.get_string_assignment("hello-world-greeting", name, {}, "Hello") + + return f"{greeting}, {name}!" diff --git a/example/03_bandit.py b/example/03_bandit.py new file mode 100644 index 0000000..b1bdd3e --- /dev/null +++ b/example/03_bandit.py @@ -0,0 +1,64 @@ +""" +Run using +`fastapi dev 03_bandit.py` + +Test using +`curl "http://127.0.0.1:8000/bandit?name=bob&country=UK&age=25"` +""" + +from dotenv import load_dotenv +import os + +from fastapi import FastAPI +import eppo_client +from eppo_client.config import Config, AssignmentLogger +import eppo_client.bandit + +load_dotenv() +EPPO_API_KEY = os.environ.get("EPPO_API_KEY") +print(EPPO_API_KEY[:5] + "...") + +app = FastAPI() + + +class LocalLogger(AssignmentLogger): + def log_assignment(self, assignment_event): + print(assignment_event) + + +client_config = Config(api_key=EPPO_API_KEY, assignment_logger=LocalLogger()) + +eppo_client.init(client_config) + + +@app.get("/bandit") +async def bandit(name: str, country: str, age: int): + client = eppo_client.get_instance() + + print(client.get_flag_keys()) + + bandit_result = client.get_bandit_action( + "shoe-bandit", + name, + eppo_client.bandit.Attributes( + numeric_attributes={"age": age}, categorical_attributes={"country": country} + ), + [ + eppo_client.bandit.ActionContext.create( + "nike", + numeric_attributes={"brand_affinity": 2.3}, + categorical_attributes={"aspect_ratio": "16:9"}, + ), + eppo_client.bandit.ActionContext.create( + "adidas", + numeric_attributes={"brand_affinity": 0.2}, + categorical_attributes={"aspect_ratio": "16:9"}, + ), + ], + "control", + ) + + if bandit_result.action: + return f"The bandit recommends {bandit_result.action} to {name}" + + return f"{name} was assigned to {bandit_result.variation}" diff --git a/example/README.md b/example/README.md index 4f20c6b..2f782d6 100644 --- a/example/README.md +++ b/example/README.md @@ -8,7 +8,7 @@ source venv/bin/activate pip install -r requirements.txt ``` -Set your API key in `main.py`: +Set your API key in `01_script.py`: ``` API_KEY = "[replace with your API key]" ``` diff --git a/example/requirements.txt b/example/requirements.txt new file mode 100644 index 0000000..582acad --- /dev/null +++ b/example/requirements.txt @@ -0,0 +1,2 @@ +python-dotenv +fastapi \ No newline at end of file From 42090d44f9182e288eec8a2ebec5565eaee551d0 Mon Sep 17 00:00:00 2001 From: Sven Schmit Date: Wed, 29 May 2024 16:31:44 -0700 Subject: [PATCH 2/5] :broom: --- example/02_fastapi.py | 2 +- example/03_bandit.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/02_fastapi.py b/example/02_fastapi.py index 101e10c..057e78d 100644 --- a/example/02_fastapi.py +++ b/example/02_fastapi.py @@ -1,5 +1,5 @@ """ -Run using +Run using `fastapi dev 02_fastapi.py` Test using diff --git a/example/03_bandit.py b/example/03_bandit.py index b1bdd3e..5ecf664 100644 --- a/example/03_bandit.py +++ b/example/03_bandit.py @@ -1,5 +1,5 @@ """ -Run using +Run using `fastapi dev 03_bandit.py` Test using From 0203cbfa58e2acac166a48cd6ca7c2eeac5afc35 Mon Sep 17 00:00:00 2001 From: Sven Schmit Date: Wed, 29 May 2024 16:53:38 -0700 Subject: [PATCH 3/5] add bandit logger --- example/03_bandit.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/03_bandit.py b/example/03_bandit.py index 5ecf664..2ce0f3f 100644 --- a/example/03_bandit.py +++ b/example/03_bandit.py @@ -25,6 +25,9 @@ class LocalLogger(AssignmentLogger): def log_assignment(self, assignment_event): print(assignment_event) + def log_bandit_assignment(self, bandit_assignment): + print(bandit_assignment) + client_config = Config(api_key=EPPO_API_KEY, assignment_logger=LocalLogger()) From 0731118cd9b366b108c93dbf1237fb882061fc8a Mon Sep 17 00:00:00 2001 From: Sven Schmit Date: Wed, 29 May 2024 22:15:05 -0700 Subject: [PATCH 4/5] add eppo sdk as requirement --- example/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/example/requirements.txt b/example/requirements.txt index 582acad..ef0af4d 100644 --- a/example/requirements.txt +++ b/example/requirements.txt @@ -1,2 +1,3 @@ +eppo-server-sdk==3.1.0 python-dotenv fastapi \ No newline at end of file From 52f5a8097d4484d80befc542309a6617714e2180 Mon Sep 17 00:00:00 2001 From: Sven Schmit Date: Wed, 29 May 2024 22:30:06 -0700 Subject: [PATCH 5/5] updated readme --- example/README.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/example/README.md b/example/README.md index 2f782d6..46e231a 100644 --- a/example/README.md +++ b/example/README.md @@ -1,4 +1,4 @@ -## Running the Eppo SDK example +# Running the Eppo SDK examples Before running the example, you need to install the dependencies for the Eppo SDK. From the root of the repo, install the necessary requirements: @@ -8,9 +8,38 @@ source venv/bin/activate pip install -r requirements.txt ``` -Set your API key in `01_script.py`: +Note that all these examples query feature flags set up within the Eppo UI. +Make sure to set up flags prior to running the examples and adjusting the scripts accordingly. + + +## 01: Local script + +This is the simplest example that shows how to use the Eppo SDK. Set your API key in `01_script.py`: ``` API_KEY = "[replace with your API key]" ``` -Run the example \ No newline at end of file +Then run the example: +``` +python 01_script.py +``` + +## 02: FastAPI + +Generally, Eppo is configured as part of a server. This example shows how to use the Eppo SDK in a FastAPI server. +To follow best practices, create a .env file by copying .env.dist and put your API key in it. +We will use `python-dotenv` to read the SDK key from the .env file. + +Then run the example: +``` +fastapi dev 02_fastapi.py +``` + +## 03: Bandit + +This example builds on the previous FastAPI example but instead of showing a simple feature flag, it shows how to use Eppo's contextual bandits. + +Make sure you have your Eppo API key set in `.env` as instructed above, then run the example: +``` +fastapi dev 03_bandit.py +``` \ No newline at end of file