Skip to content

@W-24132874@ Add Python port of b2c-tooling-sdk (SDK, samples, docs, agent-skills plugin) - #667

Open
priandsf wants to merge 31 commits into
SalesforceCommerceCloud:mainfrom
priandsf:python
Open

priandsf wants to merge 31 commits into
SalesforceCommerceCloud:mainfrom
priandsf:python

Conversation

@priandsf

@priandsf priandsf commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

@W-24132874@

What

Adds a Python port of the B2C tooling SDK under python/b2c-tooling-sdk/, plus supporting samples, documentation, and an agent-skills plugin for consuming it. This is additive — it lives entirely under python/ and does not touch the existing TypeScript packages.

Highlights

  • salesforce-b2c-tooling-sdk (import b2c_tooling_sdk) — a faithful port of @salesforce/b2c-tooling-sdk: async-first with a complete synchronous facade (b2c_tooling_sdk.sync), Python 3.10+.
    • Authentication (OAuth client-credentials, JWT Bearer, PKCE, implicit, Basic, API-key) and a persistent session store.
    • Config resolution (dw.json, ~/.mobify, settings.json, multi-env aliases).
    • Typed OCAPI / SCAPI / WebDAV clients (ClientResult, never raise on 4xx/5xx) and higher-level success-or-raise operations (code deploy, jobs, sites, catalogs, BM users/roles, sandboxes, metrics, logs).
    • SLAS shopper token helpers.
  • CLI interoperability — shares the same on-disk auth-sessions.json and config files as @salesforce/b2c-cli, so a session created by b2c auth login works from Python and vice versa.
  • Samples (python/samples/) — runnable scripts and Jupyter notebooks for each scenario; offline, mocked, CI-safe notebooks under the SDK's docs/notebooks/.
  • Documentation — an MkDocs site with guides and a generated API reference.
  • b2c-python-sdk agent-skills plugin — a consumer skill (using-b2c-tooling-sdk) with a full symbol catalog, wired into the marketplace and the b2c setup skills installer.

Notes for reviewers

  • Install instructions in the SDK docs/skill/samples point at SalesforceCommerceCloud/…@main and only resolve once this merges to main (chicken-and-egg by design; PyPI publishing is future work).
  • RELEASE.md / release.sh intentionally still describe the interim fork-based tag release process.
  • SDK quality gate (ruff check + ruff format + mypy strict + pytest, 1195 tests) is green.

Adds the standalone Python SDK (import: b2c_tooling_sdk; dist:
salesforce-b2c-tooling-sdk) that mirrors the TypeScript b2c-tooling-sdk public
surface and interoperates with the B2C CLI (shared auth-session store and config
files). Includes auth (all methods), config resolution, OCAPI/SCAPI typed
clients, WebDAV, operations, SLAS shopper tokens, a sync facade, docs, and
runnable example notebooks.

Also adds python/LICENSE (Apache-2.0), python/.gitignore, and a
tag-triggered GitHub Actions release workflow (python-v*) that builds the
wheel/sdist and attaches them to a GitHub Release for pip installation.
Document installation via git+https from the python branch (and pinned tags) as
a temporary arrangement during development, until the package is published to
PyPI. Remove the now-unneeded GitHub Release workflow — the git+https install
builds straight from the ref and needs no release assets.
Interactive script proposes the next minor version, runs the quality gate,
bumps pyproject.toml, commits, tags python-v<version>, and pushes to the fork
after confirmation. RELEASE.md now leads with the script; manual steps kept as
reference.
get_default_data_dir() now mirrors @oclif/core's Config.dataDir (and the
sibling get_b2c_config_directory): $B2C_DATA_DIR | $XDG_DATA_HOME |
(win32 %LOCALAPPDATA%) | ~/.local/share, then /b2c. Previously it returned
~/Library/Application Support/@salesforce/b2c-cli on macOS, so find_auth_session
could never locate sessions written by the b2c CLI. The identical bug still
exists in the TS SDK (session-store.ts getDefaultDataDir).
Five auth/API scenarios (oauth_ocapi, oauth_scapi, basic_webdav, cli_session,
slas_shopper) in async + sync, plus matching notebooks, all reading one
git-ignored dw.json (dw.example.json is the pseudo-value template).
…irectly

The sync facade proxies the whole object graph, so instance.webdav from
b2c_tooling_sdk.sync.resolve_config is already blocking. The sample was
await-ing webdav.put/get/delete, which raised TypeError on a None result.
Call the WebDAV methods directly (no asyncio) and correct the docstring +
README note that repeated the wrong 'wrap in asyncio.run' premise.
Adds browser_login_{async,sync}.py + notebook/06-browser-login.ipynb showing
the SDK equivalent of 'b2c auth login <clientId>': create_user_auth_strategy +
get_token_response runs the Authorization Code + PKCE browser flow and persists
the session to the shared auth-sessions store (reusable by the CLI).
Adds multi_env_{async,sync}.py + notebook/07-multi-env.ipynb + a bundled
multi-env.example.json demonstrating named-environment selection from a
multi-config dw.json via ResolveConfigOptions(instance=...). Offline; no
credentials or network required.
… deterministic

Read specs from the sibling JS package (packages/b2c-tooling-sdk/specs)
instead of vendoring a second copy under python/specs, and stop bundling
specs in the wheel/sdist. Generate models with datamodel-code-generator's
builtin formatter, then format each file with the project's pinned ruff --
datamodel's black/isort integration silently no-ops on recent toolchains,
which made regeneration non-deterministic. Pin datamodel-code-generator
so output stays stable. Regenerated models are AST-identical (pure
reformat).
…s, and content

Add live Jupyter notebooks demonstrating the admin Data APIs with OAuth
client-credentials, parsing responses into the SDK's generated Pydantic
types:
- 10-scapi-catalogs: list catalogs via create_catalogs_backend and a typed
  product/catalogs/v1 call (SCAPI Data)
- 11-ocapi-products: product search + product by id (OCAPI Data)
- 12-ocapi-content-assets: list a folder's content + content asset by id
  (OCAPI Data)

SCAPI Admin covers only catalog listing here, so products/content go
through the OCAPI Data API; notebooks handle the OCAPI Data allow-list 403
gracefully. Also add the previously-uncommitted SLAS Shopper notebooks
(08/09) and document all of them in the samples README.
Add python/CLAUDE.md documenting the Python SDK subproject (commands,
architecture, async/sync facade, generated models, conventions), and a
using-b2c-tooling-sdk skill guiding consumption of the SDK from scripts and
notebooks (install, auth by use case, available clients and operations).
…ing SDK

Move the using-b2c-tooling-sdk consumer skill out of the Python package's local .claude/skills into a first-class, installable skills plugin so it ships to consumers. Register it in plugins.json (release packaging), both marketplace manifests, and the CLI skill installer (sources.ts + SkillSet type) so it installs via the plugin marketplace or 'b2c setup skills b2c-python-sdk'. Add the missing references/api-catalog.md the skill points to.
Move the Python package (src, tests, docs, scripts, build/config) from python/ into python/b2c-tooling-sdk/, alongside the sibling python/samples/. Pure relocation.
The Python SDK is headed for SalesforceCommerceCloud/b2c-developer-tooling@main, so update the git-install URL, release badge, and 'python' branch prose in the SDK README, docs/index, and the b2c-python-sdk skill to reference the upstream repo and main branch. Also fix the skill's SDK-development pointer to python/b2c-tooling-sdk/CLAUDE.md after the reorg. RELEASE.md is left untouched — it documents the current fork-based release process. Note: the @main install command only works once the branch is merged upstream.
Remove unused imports, sort imports, and apply ruff format to the offline docs/notebooks so the SDK lint/format gate is green. Autofix only; no behavioral changes. Samples notebooks are left untouched.
…tory

The SDK moved into python/b2c-tooling-sdk/; update the samples requirements pin to the new subdirectory path.
Point the samples requirements at SalesforceCommerceCloud/...@main instead of the priandsf fork, matching the consumer install docs. Release machinery (RELEASE.md, release.sh) still targets the fork by design.
@priandsf
priandsf requested a review from clavery as a code owner September 9, 2026 21:17
priandsf and others added 2 commits September 10, 2026 09:55
The b2c-python-sdk skill set was added to SKILL_SOURCES but the ALL_SKILL_SETS test still expected 5 entries. Include it and bump the expected length to 6.
@clavery

clavery commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

I did a review and there were some good findings but not critical. However we're declaring python 3.10 support here but that's failing the tests. 3.11+ works. I'd suggest just dropping 3.10 instead of resolving it.

But we should probably add a CI step to run pytest, ruff, etc. Basic coverage. We can even scope that to run only on PRs with python/* file changes (skipping otherwise). That might be good to add now so future PRs have a baseline regression suite for py

For reference these are some of the issues identified but all this looks like eventual followups or nit-picking rather than necessary here (except for the CI stuff):

  • ZIP extraction does not block ../ paths, allowing files to be written outside the destination.
  • Python 3.10 is declared as supported, but one deploy-timeout test fails there.
  • 401 retry state is stored permanently by URL, so later token expirations on the same endpoint won’t retry.
  • GitHub CI does not run any Python tests, linting, typing, or supported-version matrix.
  • Auth-session temp files are chmodded only after writing, briefly exposing refresh tokens under permissive umasks.
  • make build-sync calls a script that does not exist.

@clavery

clavery commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

Also I highly recommend we get this onboarded into changesets here. all packages use it even if they aren't nodejs (for instance the agent-skills and docs site here are in changesets).

https://github.com/changesets/changesets/blob/main/docs/versioning-apps.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants