camunda / camunda/api-test-generator
feat: Python SDK emitter (`python-sdk`) — lower path-analyser scenarios onto camunda-orchestration-sdk
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 3
- Avg merge
- 13h 41m
- Merged PRs (30d)
- 23
Description
Sub-issue of #8. Implement the python-sdk emitter strategy that lowers path-analyser EndpointScenarioCollection objects onto the camunda-orchestration-sdk Python SDK, generating pytest suites instead of raw Playwright HTTP calls.
Prerequisites
-
Emitterinterface — landed (path-analyser/src/codegen/emitter.ts,registry.ts,orchestrator.ts,cli-args.ts) — see #5 / #8 - Reference implementation —
PlaywrightEmitteratpath-analyser/src/codegen/playwright/emitter.ts(488 lines). Treat this as the canonical lowering reference. - Per-step success-status correctness —
successStatusByOpflows throughRequestStep.expect.status(PR #52 / Bug A). SDK emitter gets this for free. - JS SDK emitter (
js-sdk) — recommended to land first as it establishes theSdkMappingSourceinterface andOperationMapJsonSourceimplementation.
What to build
A new emitter registered under --target=python-sdk at:
path-analyser/src/codegen/python-sdk/
emitter.ts # PythonSdkEmitter implements Emitter
sdk-mapping.ts # reuses SdkMappingSource interface; OperationMapJsonSource impl with snake_case transform
materialize-support.ts # vendors a self-contained Python project skeleton into <outDir>/
README.md # emitter id, env vars, supported scenario shapes
The emitter is written in TypeScript (part of this Node.js generator) but its output is .py test files.
SDK surface
- Package:
camunda-orchestration-sdk(PyPI) - Client:
CamundaAsyncClient(recommended over syncCamundaClient— matches SDK's own integration tests) - Method naming:
snake_case— transform fromoperationIdcamelCase viacamelToSnake() - Ergonomic helpers:
deploy_resources_from_filesand others ingenerated/.../client.py - Codegen hook:
hooks/post_gen/ - Existing helper map:
examples/operation-map.json—regionvalues are already in snake_case method symbol form
Mapping strategy (Option C from #8)
- Load the SDK's
examples/operation-map.json(see Open Question 1 on checkout layout). - For each
operationId, look upoperation-map.json[operationId][0].region— this is the preferred Python method symbol. - If no entry exists, derive raw method by converting
operationIdcamelCase → snake_case. - Emit
result = await client.<method>(args)inside anasync def test_...function.
Reuse the SdkMappingSource interface established by the JS SDK sub-issue; provide a Python-specific OperationMapJsonSource that applies the snake_case naming fallback.
Test framework
- pytest + pytest-asyncio for async test execution.
- One
conftest.pywith a session-scopedclientfixture that constructsCamundaAsyncClientfrom env vars. - Each scenario maps to one
async def test_<operationId>_<variant>(client)function.
Auth / env vars
The generated suite must support both:
- Local unauthenticated —
CamundaAsyncClient()with no credentials (matchesdocker-compose.ymlsetup) - OAuth2 / SaaS —
CAMUNDA_CLIENT_ID,CAMUNDA_CLIENT_SECRET,CAMUNDA_OAUTH_URLper SDK conventions
Document the env-var mapping from the current API_BASE_URL-based setup to SDK-native config.
Emitter behaviour
For each scenario step, the emitter should:
- Map
RequestStep.operationId→ Python method symbol viaSdkMappingSource. - Build Python keyword-argument call from
RequestStep.body/RequestStep.pathParams/RequestStep.queryParams. - Emit
result = await client.<method>(<kwargs>). - Extract response fields into a
ctxdict using equivalent Python extraction logic. - Assert response shape using Python
assertstatements or a Python port of the assertion pattern.
Emitted file structure
<outDir>/
conftest.py # client fixture
requirements.txt # camunda-orchestration-sdk, pytest, pytest-asyncio
pytest.ini / pyproject.toml # asyncio_mode = auto
activate_jobs/
test_activate_jobs.py
create_process_instance/
test_create_process_instance.py
...
Open questions to resolve (from #8)
- SDK-repo checkout layout — same question as the JS sub-issue. Decision made there should be applied consistently here. Options: sparse clone, published PyPI sidecar package, local path env var.
- Helper-signature mismatch policy — silent fallback to raw method vs. hard-fail. Align with the decision made in the JS sub-issue.
request-validationparity — shouldrequest-validationget a Python SDK variant, or path-analyser-only for now?- Python type model — the SDK likely uses Pydantic models for request/response. Investigate whether scenario
bodyshapes map cleanly onto Pydantic constructors, or whether a dict-based fallback is needed for complex/oneOf shapes. - Assertion library —
assert-json-bodyis JS-only. Determine the Python equivalent (e.g.jsonschema,pydanticmodel validation, or plainassertcomparisons) for response shape assertions.
Layered test requirements (mirrors Bug A pattern from #8)
Per the AGENTS.md red/green/class-scoped rule and the regression-guard pattern in #8:
- Layer-1 fixture — one hand-built
EndpointScenarioCollection→ emitted Python test assertion (intests/fixtures/planner/). - Layer-2 contract —
PythonSdkEmitter.emit()purity test: same input → byte-identical.pyoutput (intests/codegen/python-sdk-emitter.test.ts). - Layer-3 invariant — class-scoped assertion in
tests/regression/bundled-spec-invariants.test.ts:- Every URL placeholder in the Python SDK suite is either seeded or extracted by an upstream step (mirrors Bug A invariant).
operationIdkeyset of the emitter's call-shape table matchesexamples/operation-map.jsonunder CI.
Definition of Done
-
PythonSdkEmitterregistered under--target=python-sdkviaregisterEmitter(). -
npm run testsuite:generate -- --target=python-sdkproduces a runnable suite for every endpoint in the pinned bundled spec. -
materialize-supportanalogue produces a self-contained project (requirements.txt,pyproject.toml/pytest.ini,conftest.py) that runspip install -r requirements.txt && pytestwithout referencing this generator. - Layer-3 invariant in
tests/regression/bundled-spec-invariants.test.tscovers placeholder binding and per-step success-status correctness for the Python SDK suite. -
operationIdkeyset of emitter's mapping matches SDK'sexamples/operation-map.jsonunder CI. -
path-analyser/src/codegen/python-sdk/README.mddocuments: emitter id, expected env vars, supported scenario shapes, how to point the strategy at a checked-out SDK repo. -
npm run lint,tsc --noEmit, andnpm testall pass.
Out of scope
- Live-cluster CI matrix (separate follow-up).
- Resolving Bug B (#53) and Bug C (#54) — apply same scope filters as Bug A invariant.
- JS and C# emitters (tracked in their own sub-issues).
- Sync
CamundaClientvariant — async-only for now.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with path-analyser/src/codegen/playwright/emitter.ts and the Emitter registration files, then review the JS SDK sub-issue decisions for mapping and checkout layout. Implement and test the new path-analyser/src/codegen/python-sdk/ files, including the fixture, contract, and regression tests named in the issue. Done means --target=python-sdk produces a self-contained pytest suite and npm run lint, tsc --noEmit, and npm test pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, playwright, python, typescript
- Domain
- api, testing, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100