From 22494b33b64578af010594d9e68ac631828f1786 Mon Sep 17 00:00:00 2001 From: kj-podonos Date: Mon, 21 Sep 2026 13:48:29 +0900 Subject: [PATCH] docs: spell the brand "Onepin" and feature the OnepinClient client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No-rebuild brand fix (the generated client class rename needs a Fern regen, which is deferred because the current generator also flips list endpoints to auto-pagination — a separate, deliberate change). - Feature `OnepinClient` / `AsyncOnepinClient` (credential-resolving, version-gated hand-rolled client) in the README and examples, using `api_key=` (not `token=`). Dev targeting uses `base_url=` rather than the enum, because OnepinClient resolves base_url from credentials and would ignore `environment=`. - Rename the version-gate response header literal `X-OnePin-Required-Version` -> `X-Onepin-Required-Version` to match the backend; safe because the SDK matches header names case-insensitively (test_version_gate covers both casings). - Fix `scripts/post_fern.sh` so future regens brand the generated README "Onepin". - Sweep stray brand prose in `_version_gate.py` docstrings and `fern/generators.yml` comments. Deliberately unchanged (require the deferred regen): the generated `OnePinClient`/ `AsyncOnePinClient` classes, `OnePinClientEnvironment` enum, `OnePinUpgradeRequiredError`, and the CLI's internal exception classes. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 29 +++++++++++++---------------- examples/README.md | 4 ++-- examples/async_client.py | 6 +++--- examples/error_handling.py | 4 ++-- examples/list_workflows.py | 4 ++-- examples/quickstart.py | 4 ++-- fern/generators.yml | 4 ++-- scripts/post_fern.sh | 6 +++--- src/onepin/_version_gate.py | 4 ++-- tests/unit/test_version_gate.py | 2 +- 10 files changed, 32 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 938a54c..081bad7 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,14 @@ installed `onepin` is **below that floor**, the SDK stops with a clear, copy-pas onepin 0.4.1 is below the required minimum 0.5.0. Upgrade: pip install --upgrade 'onepin>=0.5.0' ``` -The `onepin` CLI enforces this automatically. For **programmatic** use, build the client with -`onepin.make_client` (instead of `OnePinClient` directly) to get the same gate plus a corrected -`User-Agent`: +The `onepin` CLI enforces this automatically. For **programmatic** use, `OnepinClient` has the +same gate built in plus a corrected `User-Agent` (`make_client` is the explicit-token equivalent +if you are not using credential resolution): ```python import onepin -client = onepin.make_client(token="op_live_...") +client = onepin.OnepinClient() # resolves your key (arg / ONEPIN_API_KEY / `onepin login`), version-gated client.workflows.list() # raises onepin.OnePinUpgradeRequiredError if the SDK is too old ``` @@ -440,9 +440,9 @@ Full per-endpoint reference: [`src/onepin/reference.md`](src/onepin/reference.md hosted docs at [onepin.ai/docs](https://onepin.ai/docs). Runnable scripts in [`examples/`](examples/). ```python -from onepin import OnePinClient +from onepin import OnepinClient -client = OnePinClient(token="op_...") # your API key, used as the bearer token +client = OnepinClient(api_key="op_...") # or set ONEPIN_API_KEY, or run `onepin login` workflows = client.workflows.list() # paginated — iterate items directly voices = client.voices.list() @@ -451,22 +451,19 @@ voices = client.voices.list() ### Environments ```python -from onepin import OnePinClient -from onepin.environment import OnePinClientEnvironment +from onepin import OnepinClient -# Defaults to PROD (https://api.onepin.ai). Target the dev API instead: -client = OnePinClient(token="op_...", environment=OnePinClientEnvironment.DEV) -# ...or point at any host directly: -client = OnePinClient(token="op_...", base_url="https://dev-api.onepin.ai") +# Defaults to PROD (https://api.onepin.ai). Target the dev API by URL: +client = OnepinClient(api_key="op_...", base_url="https://dev-api.onepin.ai") ``` ### Async ```python import asyncio -from onepin import AsyncOnePinClient +from onepin import AsyncOnepinClient -client = AsyncOnePinClient(token="op_...") +client = AsyncOnepinClient(api_key="op_...") async def main() -> None: @@ -479,10 +476,10 @@ asyncio.run(main()) ### Errors, retries, timeouts ```python -from onepin import OnePinClient +from onepin import OnepinClient from onepin.core.api_error import ApiError -client = OnePinClient(token="op_...", timeout=20.0) # client-wide timeout (default 60s) +client = OnepinClient(api_key="op_...", timeout=20.0) # client-wide timeout (default 60s) try: client.workflows.get( diff --git a/examples/README.md b/examples/README.md index 73610fe..f7de595 100644 --- a/examples/README.md +++ b/examples/README.md @@ -13,10 +13,10 @@ python examples/quickstart.py |------|-------| | `quickstart.py` | Construct a client, list workflows | | `list_workflows.py` | Paginate workflows, fetch one by id | -| `async_client.py` | `AsyncOnePinClient` + async pagination | +| `async_client.py` | `AsyncOnepinClient` + async pagination | | `error_handling.py` | `ApiError`, retries, timeouts | By default the client targets **PROD** (`https://api.onepin.ai`). Pass -`environment=OnePinClientEnvironment.DEV` or `base_url="https://dev-api.onepin.ai"` to +`base_url="https://dev-api.onepin.ai"` to target another host. See the repo [README](../README.md#sdk-usage) and the full per-endpoint reference in [`src/onepin/reference.md`](../src/onepin/reference.md). diff --git a/examples/async_client.py b/examples/async_client.py index ea7c002..8119ee6 100644 --- a/examples/async_client.py +++ b/examples/async_client.py @@ -1,13 +1,13 @@ -"""Async client usage with the AsyncOnePinClient.""" +"""Async client usage with the AsyncOnepinClient.""" import asyncio import os -from onepin import AsyncOnePinClient +from onepin import AsyncOnepinClient async def main() -> None: - client = AsyncOnePinClient(token=os.environ["ONEPIN_API_KEY"]) + client = AsyncOnepinClient(api_key=os.environ["ONEPIN_API_KEY"]) # AsyncPager is async-iterable. voices = await client.voices.list() diff --git a/examples/error_handling.py b/examples/error_handling.py index 90fb4ac..bce406b 100644 --- a/examples/error_handling.py +++ b/examples/error_handling.py @@ -6,12 +6,12 @@ import os -from onepin import OnePinClient +from onepin import OnepinClient from onepin.core.api_error import ApiError def main() -> None: - client = OnePinClient(token=os.environ["ONEPIN_API_KEY"], timeout=20.0) + client = OnepinClient(api_key=os.environ["ONEPIN_API_KEY"], timeout=20.0) try: client.workflows.get( diff --git a/examples/list_workflows.py b/examples/list_workflows.py index 41d4b9b..4e272d4 100644 --- a/examples/list_workflows.py +++ b/examples/list_workflows.py @@ -2,11 +2,11 @@ import os -from onepin import OnePinClient +from onepin import OnepinClient def main() -> None: - client = OnePinClient(token=os.environ["ONEPIN_API_KEY"]) + client = OnepinClient(api_key=os.environ["ONEPIN_API_KEY"]) # `list()` returns a SyncPager — iterate items directly, or use `.iter_pages()`. for index, workflow in enumerate(client.workflows.list()): diff --git a/examples/quickstart.py b/examples/quickstart.py index b641651..31bbafc 100644 --- a/examples/quickstart.py +++ b/examples/quickstart.py @@ -8,11 +8,11 @@ import os -from onepin import OnePinClient +from onepin import OnepinClient def main() -> None: - client = OnePinClient(token=os.environ["ONEPIN_API_KEY"]) + client = OnepinClient(api_key=os.environ["ONEPIN_API_KEY"]) # Workflows in your workspace. `list()` returns a pager you can iterate directly. for workflow in client.workflows.list(): diff --git a/fern/generators.yml b/fern/generators.yml index c968fe3..f900e45 100644 --- a/fern/generators.yml +++ b/fern/generators.yml @@ -1,6 +1,6 @@ -# Fern generator config for the OnePin Python SDK. +# Fern generator config for the Onepin Python SDK. # -# This repo self-generates its SDK. The OnePin API spec is shaped upstream (x-fern + servers +# This repo self-generates its SDK. The Onepin API spec is shaped upstream (x-fern + servers # folded into the published OpenAPI), so this is a VANILLA generate — no overlay/overrides here. # # regen.yml fetches the shaped spec into ./openapi/openapi.yml, then `fern generate diff --git a/scripts/post_fern.sh b/scripts/post_fern.sh index 971b18d..5e44ff1 100755 --- a/scripts/post_fern.sh +++ b/scripts/post_fern.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Post-process Fern output after it overwrites src/onepin/: # 1. Restore py.typed PEP 561 markers. -# 2. Rebrand the generated SDK README ("Podonos" -> "OnePin"). +# 2. Rebrand the generated SDK README ("Podonos" -> "Onepin"). # Run this after every `fern generate` invocation. set -euo pipefail touch src/onepin/py.typed @@ -10,8 +10,8 @@ echo "Restored py.typed markers after Fern regen." # Brand name only: case-sensitive so the lowercase "podonos" org slug in URLs is preserved. if [ -f src/onepin/README.md ]; then - sed -i.bak 's/Podonos/OnePin/g' src/onepin/README.md && rm -f src/onepin/README.md.bak - echo "Rebranded src/onepin/README.md (Podonos -> OnePin)." + sed -i.bak 's/Podonos/Onepin/g' src/onepin/README.md && rm -f src/onepin/README.md.bak + echo "Rebranded src/onepin/README.md (Podonos -> Onepin)." fi # Scrub an internal backend symbol path Fern copies verbatim from the spec docstring. diff --git a/src/onepin/_version_gate.py b/src/onepin/_version_gate.py index 78e6953..870cba8 100644 --- a/src/onepin/_version_gate.py +++ b/src/onepin/_version_gate.py @@ -1,7 +1,7 @@ """Client-side SDK version gate (hand-written; preserved across ``fern generate`` via ``.fernignore``). The Onepin API advertises the minimum SDK version it still accepts via the -``X-OnePin-Required-Version`` response header (and enforces it with HTTP 426). This module reads +``X-Onepin-Required-Version`` response header (and enforces it with HTTP 426). This module reads that header off every response and stops the caller when the installed ``onepin`` package is older than the floor. @@ -31,7 +31,7 @@ from onepin.client import AsyncOnePinClient, OnePinClient #: Response header the API uses to advertise the minimum acceptable SDK version. -REQUIRED_VERSION_HEADER = "X-OnePin-Required-Version" +REQUIRED_VERSION_HEADER = "X-Onepin-Required-Version" _BASE_UPGRADE_COMMAND = "pip install --upgrade onepin" diff --git a/tests/unit/test_version_gate.py b/tests/unit/test_version_gate.py index 4fea49a..9b5df24 100644 --- a/tests/unit/test_version_gate.py +++ b/tests/unit/test_version_gate.py @@ -28,7 +28,7 @@ def test_unparseable_is_not_older(self) -> None: class TestRequiredVersionFrom: def test_case_insensitive(self) -> None: - assert vg.required_version_from({"X-OnePin-Required-Version": "0.7.0"}) == "0.7.0" + assert vg.required_version_from({"X-Onepin-Required-Version": "0.7.0"}) == "0.7.0" assert vg.required_version_from({"x-onepin-required-version": "0.7.0"}) == "0.7.0" def test_missing_and_blank(self) -> None: