From cc8bab464154f520759311ea170a0080318cbc03 Mon Sep 17 00:00:00 2001 From: Goutam Date: Sun, 8 Mar 2026 22:33:31 +0530 Subject: [PATCH 1/3] Add Google Sheets persister skeleton (#213) --- burr/integrations/persisters/b_google_sheets.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 burr/integrations/persisters/b_google_sheets.py diff --git a/burr/integrations/persisters/b_google_sheets.py b/burr/integrations/persisters/b_google_sheets.py new file mode 100644 index 000000000..e69de29bb From 12c9f9fb9b303abb4a27b3ef89360b0f46d2fc35 Mon Sep 17 00:00:00 2001 From: Goutam Date: Sun, 8 Mar 2026 22:37:58 +0530 Subject: [PATCH 2/3] Add Google Sheets persister skeleton implementation (#213) --- .../persisters/b_google_sheets.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/burr/integrations/persisters/b_google_sheets.py b/burr/integrations/persisters/b_google_sheets.py index e69de29bb..3701d5fd6 100644 --- a/burr/integrations/persisters/b_google_sheets.py +++ b/burr/integrations/persisters/b_google_sheets.py @@ -0,0 +1,29 @@ +import json +from burr.core.persistence import BaseStatePersister + + +class GoogleSheetsPersister(BaseStatePersister): + """ + Persister that stores Burr state in Google Sheets. + """ + + def __init__(self, spreadsheet_id): + self.spreadsheet_id = spreadsheet_id + + def save(self, app_id: str, partition_key: str, state: dict): + """ + Save state to Google Sheets + """ + print("Saving state to Google Sheets") + + def load(self, app_id: str, partition_key: str): + """ + Load state from Google Sheets + """ + print("Loading state from Google Sheets") + + def list(self, app_id: str): + """ + List partitions + """ + return [] \ No newline at end of file From da8f6b6f2a2fa941dbbf2fd3f9834a8ae09ef5aa Mon Sep 17 00:00:00 2001 From: Goutam Date: Sun, 15 Mar 2026 21:55:14 +0530 Subject: [PATCH 3/3] Implement Google Sheets persister prototype (#213) --- .gitignore | 1 + .../persisters/b_google_sheets.py | 81 +++++++++++++++---- test_sheets.py | 15 ++++ 3 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 test_sheets.py diff --git a/.gitignore b/.gitignore index a92fd35b4..9c29d3c3d 100644 --- a/.gitignore +++ b/.gitignore @@ -193,3 +193,4 @@ burr/tracking/server/build examples/*/statemachine examples/*/*/statemachine .vscode +google_creds.json diff --git a/burr/integrations/persisters/b_google_sheets.py b/burr/integrations/persisters/b_google_sheets.py index 3701d5fd6..5daab5f64 100644 --- a/burr/integrations/persisters/b_google_sheets.py +++ b/burr/integrations/persisters/b_google_sheets.py @@ -1,29 +1,78 @@ import json -from burr.core.persistence import BaseStatePersister +from burr.core import persistence +from googleapiclient.discovery import build +from google.oauth2.service_account import Credentials - -class GoogleSheetsPersister(BaseStatePersister): +class GoogleSheetsPersister(persistence.BaseStatePersister): """ Persister that stores Burr state in Google Sheets. """ - def __init__(self, spreadsheet_id): + def __init__(self, spreadsheet_id: str, credentials_file: str): self.spreadsheet_id = spreadsheet_id + scopes = ["https://www.googleapis.com/auth/spreadsheets"] + creds = Credentials.from_service_account_file( + credentials_file, + scopes=scopes) + self.service = build("sheets", "v4", credentials=creds) + + def save(self, app_id: str, partition_key: str, state: dict): - """ - Save state to Google Sheets - """ - print("Saving state to Google Sheets") + state_json = json.dumps(state) + + values = [[app_id, partition_key, state_json]] + body = {"values": values} + + self.service.spreadsheets().values().append( + spreadsheetId=self.spreadsheet_id, + range="states!A:C", + valueInputOption="RAW", + body=body).execute() + + def load(self, app_id: str, partition_key: str): - """ - Load state from Google Sheets - """ - print("Loading state from Google Sheets") + result = self.service.spreadsheets().values().get( + spreadsheetId=self.spreadsheet_id, + range="states!A:C").execute() + + rows = result.get("values", []) + + for row in rows: + if len(row) >= 3 and row[0] == app_id and row[1] == partition_key: + return json.loads(row[2]) + + return None + + def list(self, app_id: str): - """ - List partitions - """ - return [] \ No newline at end of file + result = self.service.spreadsheets().values().get( + spreadsheetId=self.spreadsheet_id, + range="states!A:C").execute() + + rows = result.get("values", []) + partition_keys = [] + + for row in rows: + if len(row) >= 2 and row[0] == app_id: + partition_keys.append(row[1]) + + return partition_keys + + + + def list_app_ids(self): + result = self.service.spreadsheets().values().get( + spreadsheetId=self.spreadsheet_id, + range="states!A:C").execute() + + rows = result.get("values", []) + app_ids = [] + + for row in rows[1:]: + if len(row) >= 1 and row[0] not in app_ids: + app_ids.append(row[0]) + + return app_ids \ No newline at end of file diff --git a/test_sheets.py b/test_sheets.py new file mode 100644 index 000000000..1bbf50f9d --- /dev/null +++ b/test_sheets.py @@ -0,0 +1,15 @@ +from burr.integrations.persisters.b_google_sheets import GoogleSheetsPersister + +persister = GoogleSheetsPersister( + spreadsheet_id="1ur4GqM0tQQyCRn3lAj5bZk3DAeZBvrbYRwKok780hHc", + credentials_file="google_creds.json" +) + +# Save some data +persister.save("demo_app", "user1", {"hello": "world"}) + +# Load the data +data = persister.load("demo_app", "user1") + +print("Loaded data:", data) +print("App IDs:", persister.list_app_ids()) \ No newline at end of file