From 77c8911c8faa595f880c68049efb66074eb4238c Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 14:01:29 -0700 Subject: [PATCH 1/8] rye --- .gitignore | 1 + README.md | 13 +++++++------ pyproject.toml | 6 ++++++ requirements-dev.lock | 26 ++++++++++++++++++++++++++ requirements.lock | 1 + 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 8779740..99cf5c6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ dist .envrc codegen.log Brewfile.lock.json +screenshot.png diff --git a/README.md b/README.md index 2880764..5976e27 100644 --- a/README.md +++ b/README.md @@ -50,17 +50,18 @@ so that your API Key is not stored in source control. See the [examples](examples) directory for more usage examples. +> [!NOTE] +> Running the examples requires [Rye](https://rye.astral.sh/) to be installed. + To run the examples, clone this repository and run the following commands from the project root (this directory): ```bash -python3 -m venv .venv -source .venv/bin/activate -python3 -m pip install . -python3 -m examples/02_create_session.py # replace with the example you want to run +rye sync +rye run run-example 02_create_session.py # replace with the example you want to run ``` -!!! note - Make sure you have a `.env` file that matches the [.env.example](.env.example) file in the root of this repository. +> [!NOTE] +> Make sure you have a `.env` file that matches the [.env.example](.env.example) file in the root of this repository. ## Async usage diff --git a/pyproject.toml b/pyproject.toml index e0a6c1f..56516cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,12 +50,15 @@ dev-dependencies = [ "respx", "pytest", "pytest-asyncio", + "pytest-playwright", "ruff", "time-machine", "nox", "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", + "python-dotenv", + "playwright", ] [tool.rye.scripts] @@ -79,10 +82,13 @@ format = { chain = [ "check:importable" = "python -c 'import browserbase'" +"run-example" = "python -c 'import sys; from pathlib import Path; example = Path(\"examples\") / sys.argv[1]; exec(open(example).read())'" + typecheck = { chain = [ "typecheck:pyright", "typecheck:mypy" ]} + "typecheck:pyright" = "pyright" "typecheck:verify-types" = "pyright --verifytypes browserbase --ignoreexternal" "typecheck:mypy" = "mypy ." diff --git a/requirements-dev.lock b/requirements-dev.lock index b6be61c..3bd5de5 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 @@ -21,6 +22,9 @@ attrs==23.1.0 certifi==2023.7.22 # via httpcore # via httpx + # via requests +charset-normalizer==3.4.0 + # via requests colorlog==6.7.0 # via nox dirty-equals==0.6.0 @@ -32,6 +36,8 @@ exceptiongroup==1.1.3 # via anyio filelock==3.12.4 # via virtualenv +greenlet==3.1.1 + # via playwright h11==0.14.0 # via httpcore httpcore==1.0.2 @@ -42,6 +48,7 @@ httpx==0.25.2 idna==3.4 # via anyio # via httpx + # via requests importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -60,6 +67,8 @@ packaging==23.2 # via pytest platformdirs==3.11.0 # via virtualenv +playwright==1.48.0 + # via pytest-playwright pluggy==1.3.0 # via pytest py==1.11.0 @@ -68,16 +77,28 @@ pydantic==2.7.1 # via browserbase pydantic-core==2.18.2 # via pydantic +pyee==12.0.0 + # via playwright pygments==2.18.0 # via rich pyright==1.1.380 pytest==7.1.1 # via pytest-asyncio + # via pytest-base-url + # via pytest-playwright pytest-asyncio==0.21.1 +pytest-base-url==2.1.0 + # via pytest-playwright +pytest-playwright==0.5.2 python-dateutil==2.8.2 # via time-machine +python-dotenv==1.0.1 +python-slugify==8.0.4 + # via pytest-playwright pytz==2023.3.post1 # via dirty-equals +requests==2.32.3 + # via pytest-base-url respx==0.20.2 rich==13.7.1 ruff==0.6.9 @@ -89,6 +110,8 @@ sniffio==1.3.0 # via anyio # via browserbase # via httpx +text-unidecode==1.3 + # via python-slugify time-machine==2.9.0 tomli==2.0.1 # via mypy @@ -99,6 +122,9 @@ typing-extensions==4.8.0 # via mypy # via pydantic # via pydantic-core + # via pyee +urllib3==2.2.3 + # via requests virtualenv==20.24.5 # via nox zipp==3.17.0 diff --git a/requirements.lock b/requirements.lock index 44b55d0..b71b55a 100644 --- a/requirements.lock +++ b/requirements.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 From 54c8faf3dc378432da81d2b42da93ad2af74f758 Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 14:33:45 -0700 Subject: [PATCH 2/8] basic test --- e2e/test_session.py | 65 +++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 4 ++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 e2e/test_session.py diff --git a/e2e/test_session.py b/e2e/test_session.py new file mode 100644 index 0000000..e93e462 --- /dev/null +++ b/e2e/test_session.py @@ -0,0 +1,65 @@ +import os +import re + +import pytest +from dotenv import load_dotenv +from playwright.sync_api import Browser, Playwright, expect, sync_playwright + +from browserbase import Browserbase + +load_dotenv(override=True) +BROWSERBASE_URL = os.environ.get("BROWSERBASE_URL", "wss://connect.browserbase.com") +BROWSERBASE_API_KEY = os.environ.get("BROWSERBASE_API_KEY") +if not BROWSERBASE_API_KEY: + raise ValueError("BROWSERBASE_API_KEY is not set in environment") +BROWSERBASE_PROJECT_ID = os.environ.get("BROWSERBASE_PROJECT_ID") +if not BROWSERBASE_PROJECT_ID: + raise ValueError("BROWSERBASE_PROJECT_ID is not set in environment") + +bb = Browserbase(api_key=BROWSERBASE_API_KEY) + + +@pytest.fixture(scope="session") +def playwright() -> Playwright: + with sync_playwright() as p: + yield p + + +""" +def test_has_title(): + + page = browser.new_page() + page.goto("https://playwright.dev/") + + # Expect a title "to contain" a substring. + expect(page).to_have_title(re.compile("Playwright")) + + +def test_get_started_link(browser: Browser): + page = browser.new_page() + page.goto("https://playwright.dev/") + + # Click the get started link. + page.get_by_role("link", name="Get started").click() + + # Expects page to have a heading with the name of Installation. + expect(page.get_by_role("heading", name="Installation")).to_be_visible() +""" + + +def test_create_session(playwright: Playwright): + session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID) + print("Api Key: " + os.environ.get("BROWSERBASE_API_KEY")) + connect_url = session.connectUrl + print("connect_url: " + connect_url) + chromium = playwright.chromium + browser = chromium.connect_over_cdp( + "wss://connect.browserbase.com?apiKey=" + BROWSERBASE_API_KEY + ) + context = browser.contexts[0] + page = context.pages[0] + + page.goto("https://www.google.com") + page.screenshot(path="screenshot.png") + print(page.title) + assert True diff --git a/pyproject.toml b/pyproject.toml index 56516cf..7ece4e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,9 @@ format = { chain = [ "check:importable" = "python -c 'import browserbase'" -"run-example" = "python -c 'import sys; from pathlib import Path; example = Path(\"examples\") / sys.argv[1]; exec(open(example).read())'" +"example" = "python -c 'import sys; from pathlib import Path; example = Path(\"examples\") / sys.argv[1]; exec(open(example).read())'" + +"test:e2e" = "python -m pytest e2e" typecheck = { chain = [ "typecheck:pyright", From 8fd6a9356dc6fa2aba5fb9db8719ad11c4ae738e Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 16:49:23 -0700 Subject: [PATCH 3/8] temp --- .gitignore | 1 + e2e/test_session.py | 65 --------------------------- examples/__init__.py | 24 ++++++++++ examples/e2e/README.md | 26 +++++++++++ examples/e2e/__init__.py | 1 + examples/e2e/test_playwright_basic.py | 22 +++++++++ examples/playwright_basic.py | 34 ++++++++++++++ pyproject.toml | 4 +- 8 files changed, 110 insertions(+), 67 deletions(-) delete mode 100644 e2e/test_session.py create mode 100644 examples/__init__.py create mode 100644 examples/e2e/README.md create mode 100644 examples/e2e/__init__.py create mode 100644 examples/e2e/test_playwright_basic.py create mode 100644 examples/playwright_basic.py diff --git a/.gitignore b/.gitignore index 99cf5c6..860eff4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ dist codegen.log Brewfile.lock.json screenshot.png +openapi.v1.yaml diff --git a/e2e/test_session.py b/e2e/test_session.py deleted file mode 100644 index e93e462..0000000 --- a/e2e/test_session.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import re - -import pytest -from dotenv import load_dotenv -from playwright.sync_api import Browser, Playwright, expect, sync_playwright - -from browserbase import Browserbase - -load_dotenv(override=True) -BROWSERBASE_URL = os.environ.get("BROWSERBASE_URL", "wss://connect.browserbase.com") -BROWSERBASE_API_KEY = os.environ.get("BROWSERBASE_API_KEY") -if not BROWSERBASE_API_KEY: - raise ValueError("BROWSERBASE_API_KEY is not set in environment") -BROWSERBASE_PROJECT_ID = os.environ.get("BROWSERBASE_PROJECT_ID") -if not BROWSERBASE_PROJECT_ID: - raise ValueError("BROWSERBASE_PROJECT_ID is not set in environment") - -bb = Browserbase(api_key=BROWSERBASE_API_KEY) - - -@pytest.fixture(scope="session") -def playwright() -> Playwright: - with sync_playwright() as p: - yield p - - -""" -def test_has_title(): - - page = browser.new_page() - page.goto("https://playwright.dev/") - - # Expect a title "to contain" a substring. - expect(page).to_have_title(re.compile("Playwright")) - - -def test_get_started_link(browser: Browser): - page = browser.new_page() - page.goto("https://playwright.dev/") - - # Click the get started link. - page.get_by_role("link", name="Get started").click() - - # Expects page to have a heading with the name of Installation. - expect(page.get_by_role("heading", name="Installation")).to_be_visible() -""" - - -def test_create_session(playwright: Playwright): - session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID) - print("Api Key: " + os.environ.get("BROWSERBASE_API_KEY")) - connect_url = session.connectUrl - print("connect_url: " + connect_url) - chromium = playwright.chromium - browser = chromium.connect_over_cdp( - "wss://connect.browserbase.com?apiKey=" + BROWSERBASE_API_KEY - ) - context = browser.contexts[0] - page = context.pages[0] - - page.goto("https://www.google.com") - page.screenshot(path="screenshot.png") - print(page.title) - assert True diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 0000000..baf9883 --- /dev/null +++ b/examples/__init__.py @@ -0,0 +1,24 @@ +import os + +from dotenv import load_dotenv + +from browserbase import Browserbase + +# Load our environment variables +load_dotenv(override=True) + +# Make sure we have the required environment variables +BROWSERBASE_CONNECT_URL = os.environ.get( + "BROWSERBASE_CONNECT_URL", "wss://connect.browserbase.com" +) +_BROWSERBASE_API_KEY = os.environ.get("BROWSERBASE_API_KEY") +if not _BROWSERBASE_API_KEY: + raise ValueError("BROWSERBASE_API_KEY is not set in environment") +BROWSERBASE_API_KEY: str = _BROWSERBASE_API_KEY +_BROWSERBASE_PROJECT_ID = os.environ.get("BROWSERBASE_PROJECT_ID") +if not _BROWSERBASE_PROJECT_ID: + raise ValueError("BROWSERBASE_PROJECT_ID is not set in environment") +BROWSERBASE_PROJECT_ID = _BROWSERBASE_PROJECT_ID or "" + +# Instantiate our Browserbase client +bb = Browserbase(api_key=BROWSERBASE_API_KEY) diff --git a/examples/e2e/README.md b/examples/e2e/README.md new file mode 100644 index 0000000..0443cc8 --- /dev/null +++ b/examples/e2e/README.md @@ -0,0 +1,26 @@ +# End-to-end tests + +This directory contains end-to-end tests that run against a real Browserbase instance. + +## Running the tests + +To run the tests, you will need to set the following environment variables: + +- `BROWSERBASE_API_KEY`: Your Browserbase API key +- `BROWSERBASE_PROJECT_ID`: The ID of the project you want to use for the tests + +You can set these variables in a `.env` file in the root of this directory. + +Then, run the tests with: + +```sh +$ rye run test:e2e +``` + +## Writing tests + +The tests are written using pytest and the [pytest-playwright](https://playwright.dev/python/docs/pytest) plugin. + +You can find more information about writing tests in the [pytest documentation](https://docs.pytest.org/en/7.1.x/). + +To submit a test, create a new file in the `e2e` directory with a name that describes the test and starts with `test_`. diff --git a/examples/e2e/__init__.py b/examples/e2e/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/e2e/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/e2e/test_playwright_basic.py b/examples/e2e/test_playwright_basic.py new file mode 100644 index 0000000..628d48c --- /dev/null +++ b/examples/e2e/test_playwright_basic.py @@ -0,0 +1,22 @@ +import pytest +from playwright.sync_api import Playwright, sync_playwright + +from browserbase import Browserbase + +from .. import ( + BROWSERBASE_API_KEY, + playwright_basic, +) + +bb = Browserbase(api_key=BROWSERBASE_API_KEY) + + +@pytest.fixture(scope="session") +def playwright(): + with sync_playwright() as p: + yield p + + +def test_create_session(playwright: Playwright): + page = playwright_basic.run(playwright) + assert page["title"] == "Hacker News" diff --git a/examples/playwright_basic.py b/examples/playwright_basic.py new file mode 100644 index 0000000..767b426 --- /dev/null +++ b/examples/playwright_basic.py @@ -0,0 +1,34 @@ +from playwright.sync_api import Playwright, sync_playwright + +from examples import (BROWSERBASE_API_KEY, BROWSERBASE_CONNECT_URL, + BROWSERBASE_PROJECT_ID, bb) + + +def run(playwright: Playwright): + # Create a session on Browserbase + session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID) + + # Connect to the remote session + connect_url = ( + f"{BROWSERBASE_CONNECT_URL}?sessionId={session.id}&apiKey={BROWSERBASE_API_KEY}" + ) + chromium = playwright.chromium + browser = chromium.connect_over_cdp(connect_url) + context = browser.contexts[0] + page = context.pages[0] + + # Execute Playwright actions on the remote browser tab + page.goto("https://news.ycombinator.com/") + assert page.title == "Hacker News" + page.screenshot(path="screenshot.png") + + updated_session = bb.sessions.retrieve(session.id) + print(updated_session.) + + page.close() + browser.close() + + +if __name__ == "__main__": + with sync_playwright() as playwright: + run(playwright) diff --git a/pyproject.toml b/pyproject.toml index 7ece4e8..28a35a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,9 +82,9 @@ format = { chain = [ "check:importable" = "python -c 'import browserbase'" -"example" = "python -c 'import sys; from pathlib import Path; example = Path(\"examples\") / sys.argv[1]; exec(open(example).read())'" +"example" = "python -c 'import sys; from pathlib import Path; example = Path(\"examples\") / (sys.argv[1] + \".py\"); exec(open(example).read())'" -"test:e2e" = "python -m pytest e2e" +"test:e2e" = "python -m pytest examples/e2e" typecheck = { chain = [ "typecheck:pyright", From a8ae3b49377692d0ac8d2931f036a1dcda283121 Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 17:05:57 -0700 Subject: [PATCH 4/8] working example in pytest --- examples/e2e/test_playwright_basic.py | 5 ++--- examples/playwright_basic.py | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/e2e/test_playwright_basic.py b/examples/e2e/test_playwright_basic.py index 628d48c..aba94d4 100644 --- a/examples/e2e/test_playwright_basic.py +++ b/examples/e2e/test_playwright_basic.py @@ -17,6 +17,5 @@ def playwright(): yield p -def test_create_session(playwright: Playwright): - page = playwright_basic.run(playwright) - assert page["title"] == "Hacker News" +def test_playwright_basic(playwright: Playwright): + playwright_basic.run(playwright) diff --git a/examples/playwright_basic.py b/examples/playwright_basic.py index 767b426..c2114a9 100644 --- a/examples/playwright_basic.py +++ b/examples/playwright_basic.py @@ -1,12 +1,18 @@ from playwright.sync_api import Playwright, sync_playwright -from examples import (BROWSERBASE_API_KEY, BROWSERBASE_CONNECT_URL, - BROWSERBASE_PROJECT_ID, bb) +from examples import ( + BROWSERBASE_API_KEY, + BROWSERBASE_CONNECT_URL, + BROWSERBASE_PROJECT_ID, + bb, +) def run(playwright: Playwright): # Create a session on Browserbase session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID) + assert session.id is not None + assert session.status == "RUNNING", f"Session status is {session.status}" # Connect to the remote session connect_url = ( @@ -19,14 +25,18 @@ def run(playwright: Playwright): # Execute Playwright actions on the remote browser tab page.goto("https://news.ycombinator.com/") - assert page.title == "Hacker News" + page_title = page.title() + assert ( + page_title == "Hacker News" + ), f"Page title is not 'Hacker News', it is '{page_title}'" page.screenshot(path="screenshot.png") updated_session = bb.sessions.retrieve(session.id) - print(updated_session.) + print(updated_session.status) page.close() browser.close() + return session.id if __name__ == "__main__": From eb58b8d4ed37e47d0e48fa167ab3ab6f34d2c07f Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 17:07:23 -0700 Subject: [PATCH 5/8] cleanup --- examples/playwright_basic.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/playwright_basic.py b/examples/playwright_basic.py index c2114a9..0c75901 100644 --- a/examples/playwright_basic.py +++ b/examples/playwright_basic.py @@ -31,12 +31,9 @@ def run(playwright: Playwright): ), f"Page title is not 'Hacker News', it is '{page_title}'" page.screenshot(path="screenshot.png") - updated_session = bb.sessions.retrieve(session.id) - print(updated_session.status) - page.close() browser.close() - return session.id + print("Done!") if __name__ == "__main__": From c26d132ad2e3a77a7f7abc8bf176899e02d1ca78 Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 17:09:41 -0700 Subject: [PATCH 6/8] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5976e27..41f865c 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ To run the examples, clone this repository and run the following commands from t ```bash rye sync -rye run run-example 02_create_session.py # replace with the example you want to run +rye run example playwright_basic # replace with the example you want to run ``` > [!NOTE] From 2e236c360b62b4102e345945db4add9ecb43802d Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 17:12:17 -0700 Subject: [PATCH 7/8] fix lint --- examples/playwright_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/playwright_basic.py b/examples/playwright_basic.py index 0c75901..e909f9d 100644 --- a/examples/playwright_basic.py +++ b/examples/playwright_basic.py @@ -2,8 +2,8 @@ from examples import ( BROWSERBASE_API_KEY, - BROWSERBASE_CONNECT_URL, BROWSERBASE_PROJECT_ID, + BROWSERBASE_CONNECT_URL, bb, ) From 335a81a52f9eae63e8572c6b268a38491f77cf66 Mon Sep 17 00:00:00 2001 From: Anirudh Kamath Date: Fri, 25 Oct 2024 17:14:09 -0700 Subject: [PATCH 8/8] rm numbered examples --- examples/01_quickstart.py | 28 ---------------------- examples/02_create_session.py | 44 ----------------------------------- 2 files changed, 72 deletions(-) delete mode 100644 examples/01_quickstart.py delete mode 100644 examples/02_create_session.py diff --git a/examples/01_quickstart.py b/examples/01_quickstart.py deleted file mode 100644 index 6fb908c..0000000 --- a/examples/01_quickstart.py +++ /dev/null @@ -1,28 +0,0 @@ -import os - -from dotenv import load_dotenv -from playwright.sync_api import Playwright, sync_playwright - -load_dotenv(override=True) -BROWSERBASE_API_KEY = os.environ["BROWSERBASE_API_KEY"] -BROWSERBASE_PROJECT_ID = os.environ["BROWSERBASE_PROJECT_ID"] - - -def run(playwright: Playwright): - print("Api Key: " + os.environ["BROWSERBASE_API_KEY"]) - connect_url = "wss://connect.browserbase.com?apiKey=" + BROWSERBASE_API_KEY - print("connect_url: " + connect_url) - chromium = playwright.chromium - browser = chromium.connect_over_cdp( - "wss://connect.browserbase.com?apiKey=" + BROWSERBASE_API_KEY - ) - context = browser.contexts[0] - page = context.pages[0] - - page.goto("https://www.google.com") - page.screenshot(path="screenshot.png") - print(page.title) - - -with sync_playwright() as playwright: - run(playwright) diff --git a/examples/02_create_session.py b/examples/02_create_session.py deleted file mode 100644 index ec5d3b6..0000000 --- a/examples/02_create_session.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -from pprint import pprint - -from dotenv import load_dotenv -from playwright.sync_api import Playwright, sync_playwright - -from browserbase import Browserbase - -load_dotenv(override=True) -BROWSERBASE_API_KEY = os.environ["BROWSERBASE_API_KEY"] -BROWSERBASE_PROJECT_ID = os.environ["BROWSERBASE_PROJECT_ID"] - - -bb = Browserbase( - api_key=BROWSERBASE_API_KEY -) # can be omitted if in environment variable - -session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID) -pprint({"session": session}) - - -def run(playwright: Playwright): - print("Api Key: " + os.environ["BROWSERBASE_API_KEY"]) - connect_url = session.connectUrl - print("connect_url: " + connect_url) - chromium = playwright.chromium - browser = chromium.connect_over_cdp(connect_url) - context = browser.contexts[0] - page = context.pages[0] - - page.goto("https://www.google.com") - page.screenshot(path="screenshot.png") - print(page.title) - - -with sync_playwright() as playwright: - run(playwright) - -update_session_resp = bb.sessions.update( - id=session.id, status="REQUEST_RELEASE", project_id=BROWSERBASE_PROJECT_ID -) -pprint({"update_session_resp": update_session_resp}) - -print("done")