Add weftsh: the Python SDK for Weft - #1
Merged
Merged
Conversation
The Python counterpart of @weftsh/sdk, with the same surface and the
same semantics, shaped after code.storage's pierre-storage: a client, a
repository handle, keyword-only arguments, httpx underneath.
- `Weft` (sync) and `AsyncWeft` (asyncio) with identical methods. Every
method is one request, so the sync client is generated from the async
one by scripts/unasync.py; a test fails when the committed copy is
stale, so the two cannot drift.
- Repositories, commits through a builder, reads with ETag caching,
history and diffs, branches and tags, reset/revert, tokens, webhooks,
export, mirrors, and `get_remote_url()` minting a repo-bound token.
- `expected_parent` keeps the server's three cases apart with an UNSET
sentinel: left out omits the key, `None` sends JSON null ("the branch
must not exist yet"), a SHA must match. `update()` uses the same rule
so `None` clears a field and a missing argument leaves it alone.
- The 404 rule from the TypeScript SDK: a missing path or revision reads
as None, a missing repository (a bare `not found`) raises.
- `verify_webhook` with hmac.compare_digest.
- Results are frozen dataclasses; mypy --strict clean; one dependency.
Tested the same two ways as the TypeScript SDK. 36 unit tests pin the
wire through httpx.MockTransport. 18 e2e tests run against a real Weft
server (skipped unless WEFT_E2E_* are set; the client is built inside a
fixture so a skipped run constructs nothing): real `git` clone, push and
`fsck --full --strict` through get_remote_url, a read-only URL that
cannot push, a scoped credential that cannot reach a sibling repo, a
webhook delivery the server signed, and the async client end to end.
Breaking the expected_parent mapping turns 9 tests red.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYuyBuroUvxh32x9SCbx13
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYuyBuroUvxh32x9SCbx13
…ample Same as the TypeScript SDK: a Quickstart section (token with the scopes it needs, install, run examples/quickstart.py, expected output) whose script is embedded verbatim, held to examples/quickstart.py by tests/test_readme.py, and run as a subprocess by the e2e suite. The first example in the README was mangled: ruff 0.16 formats Python code blocks inside Markdown, and `ruff format .` had rewritten a readable builder chain into one split across a call's parentheses. Markdown is now excluded from formatting, as is the quickstart script (it keeps the README's hand layout), and the example is rewritten. get_remote_url() now explains a 400/403/404 from the mint in words naming the scopes needed (org:read plus repo:write, or org:admin) instead of passing on the server's masked 404, and the README's note on the scopes is corrected; both checked with real personal tokens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYuyBuroUvxh32x9SCbx13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The first release (0.1.0) of
weftsh, the Python counterpart of@weftsh/sdk(Weftsh/typescript-sdk#1). It has the same features and the same behaviour, and follows the shape of code.storage's Python SDK (pierre-storage): a client, a repository handle, keyword-only arguments, andhttpxunderneath.Weftis the sync client andAsyncWeftis the asyncio one, with identical methods. The sync client is generated from the async one byscripts/unasync.py, and a test fails if the committed copy is stale.pierre-storageis async-only; this SDK ships both because plain scripts want sync.reset/revert; tokens; webhooks; bundle export.get_remote_url()creates a short-lived token that works only on that one repository and puts it in the URL. If the server refuses to create it, the error names the scopes the client token needs, instead of passing on the server's masked 404.expected_parentcovers the server's three cases with anUNSETsentinel. Leaving it out omits the field.Nonesends JSONnull, meaning "the branch must not exist yet". A SHA must match the branch tip.update()follows the same rule:Noneclears a field, and a missing argument leaves it alone.None. A missing repository, which the server answers with a barenot found, raises an error instead.verify_webhookchecks the signature withhmac.compare_digest.mypy --strict, it has one dependency (httpx), and it needs Python 3.10+.examples/quickstart.pyandexamples/agent_session.py.mypy --strict, pytest and a wheel-install check, on Python 3.10–3.13. This PR is the first time it runs.Quickstart
The README opens with a Quickstart:
org:readandrepo:write, ororg:admin.examples/quickstart.py, which creates a repository, commits, reads the file back and clones it with the realgitCLI.The script is embedded in the README verbatim,
tests/test_readme.pyfails if the two differ, and the e2e suite runs it as a subprocess.ruff 0.16 formats Python code blocks inside Markdown, and it had mangled the README's first example. Markdown and the quickstart script are now excluded from formatting.
Testing
httpx.MockTransport, for both the sync and async clients.stratum-core. They are skipped unlessWEFT_E2E_URL,WEFT_E2E_TOKENandWEFT_E2E_ORGare set; the client is built inside a fixture, so a skipped run creates nothing. Among other things they:git fsck --full --strictthroughget_remote_url();expected_parentmapping turned 9 tests red.org:read+repo:writeruns it all, andrepo:writealone fails at the clone step with the new explanatory error.All 61 tests pass against a local server. With no server set, 42 pass and 19 skip. The unit suite also passes on Python 3.10 and 3.13, the wheel installs and imports on its own, and
uv lock --checkpasses.Before publishing
weftshis free on PyPI;weftandweft-sdkare taken. The name matches the npm scope.create_repostakes a list of names (pluspublic=), while the TypeScriptcreateRepostakes a list of option objects.🤖 Generated with Claude Code
https://claude.ai/code/session_01SYuyBuroUvxh32x9SCbx13
Generated by Claude Code