docs(examples): per-file Downloads API example - #193
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50f6c4678b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| from pydantic import Field as FieldInfo | ||
| from playwright.sync_api import Playwright, sync_playwright | ||
|
|
||
| from examples import BROWSERBASE_PROJECT_ID, bb |
There was a problem hiding this comment.
Make the example runnable through the documented runner
The README directs users to ./scripts/example downloads_api, but that script executes uv run python examples/downloads_api.py; in that mode Python puts examples/ rather than the repository root on sys.path, so this absolute from examples ... import searches for a nested examples package and raises ModuleNotFoundError before the example starts. Invoke the example as a module or otherwise ensure the repository root is on the import path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Accurate, but pre-existing rather than introduced here. Every file in examples/ uses the same from examples import ... line, and on main today ./scripts/example playwright_downloads fails with the identical ModuleNotFoundError, because uv run python examples/<name>.py puts examples/ rather than the repository root on sys.path. The fix belongs in scripts/example (for example uv run python -m "examples.$1"), which I kept out of this PR to limit it to the example and the README note. The PR description gives the working invocation, uv run python -m examples.downloads_api. If maintainers would rather have the one-line runner fix in this PR, I can add it.
sessions.downloads.list() returns one zip archive per session and its description does not say so. Browserbase also documents a per-file Downloads API under /v1/downloads (list, get, delete) that is not generated into the SDK yet. Add an example that lists a session's downloads, fetches one file by id through client.get() and make_request_options(), writes it to disk, and checks the bytes against the listing's size and SHA-256 checksum. Note the zip return type in the README's Examples section and point at the new example for per-file access. Refs browserbase#192
50f6c46 to
795649d
Compare
What this adds
examples/downloads_api.py: an end-to-end example of Browserbase's per-file Downloads API, reached through the SDK's custom-request surface.Browser.setDownloadBehaviorwithbehavior: "allow",downloadPath: "downloads",eventsEnabled: true(the configuration downloads need in order to sync; see Downloads example doesn't work #108).playwright_downloads.pyuses.GET /v1/downloads?sessionId=...until the file shows up in the listing (files sync a few seconds after the browser finishes writing them).GET /v1/downloads/{id}andAccept: application/octet-stream, and writes it to disk.size, SHA-256 matcheschecksum.It also adds a short paragraph to the README's Examples section saying that
client.sessions.downloads.list(id)returns a zip archive of every file the session downloaded, and pointing at the new example for per-file access.Why
sessions.downloads.list()is the SDK's only download call today. It returns one zip per session, and nothing in its description says so. The documented per-file endpoints (/v1/downloads: list, get, delete, with mime and size filters and pagination) are not in the generated SDK; #192 asks for them to be added to the spec. Until then, this example shows how to reach them withclient.get()andmake_request_options(), the same calls the generated resources use, so callers do not have to drop to raw httpx to get one file.Notes for review
BinaryAPIResponseandmake_request_optionsare imported frombrowserbase._responseandbrowserbase._base_client; neither is re-exported from the package root. Pyright'sreportPrivateUsageis off in this repo so lint is clean, but the example does depend on those paths.Download,DownloadListResponse) are written the way the generator would emit them (FieldInfo(alias=...)) and should be replaced by the generated types once the endpoints are in the spec.sandstorm.mp3), while entries in the zip fromsessions.downloads.list()carry a timestamp suffix (sandstorm-<ms>.mp3). The example accepts both when it picks the file to verify.examples/downloads_api.pyandREADME.mdare touched../scripts/formatand./scripts/lintpass (ruff, pyright, mypy).uv run python -m examples.downloads_apifrom the repo root../scripts/example <name>and theuv run python examples/<name>.pyshebang putexamples/rather than the repo root onsys.path, sofrom examples import ...fails for every example in this checkout, not just this one. Left alone here as out of scope.Refs #192