@contractkit/plugin-python 0.12.3 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$ci.log +4 -4
- package/.turbo/turbo-test$colon$ci.log +9 -9
- package/CHANGELOG.md +63 -0
- package/dist/codegen-client.d.ts.map +1 -1
- package/dist/codegen-models.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/codegen-client.ts +6 -1
- package/src/codegen-models.ts +5 -0
- package/tests/codegen-models.test.ts +9 -1
|
@@ -5,9 +5,9 @@ $ tsup src/index.ts --format esm --sourcemap --dts && tsc --emitDeclarationOnly
|
|
|
5
5
|
[34mCLI[39m tsup v8.5.1
|
|
6
6
|
[34mCLI[39m Target: esnext
|
|
7
7
|
[34mESM[39m Build start
|
|
8
|
-
[32mESM[39m [1mdist/index.js [22m[32m52.
|
|
9
|
-
[32mESM[39m [1mdist/index.js.map [22m[32m110.
|
|
10
|
-
[32mESM[39m ⚡️ Build success in
|
|
8
|
+
[32mESM[39m [1mdist/index.js [22m[32m52.51 KB[39m
|
|
9
|
+
[32mESM[39m [1mdist/index.js.map [22m[32m110.73 KB[39m
|
|
10
|
+
[32mESM[39m ⚡️ Build success in 157ms
|
|
11
11
|
[34mDTS[39m Build start
|
|
12
|
-
[32mDTS[39m ⚡️ Build success in
|
|
12
|
+
[32mDTS[39m ⚡️ Build success in 3369ms
|
|
13
13
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.10 KB[39m
|
|
@@ -3,22 +3,22 @@ $ vitest run --coverage
|
|
|
3
3
|
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.5 [39m[90m/home/runner/work/ContractKit/ContractKit/packages/plugin-python[39m
|
|
4
4
|
[2mCoverage enabled with [22m[33mv8[39m
|
|
5
5
|
|
|
6
|
-
[32m✓[39m tests/codegen-client.test.ts [2m([22m[2m35 tests[22m[2m)[22m[32m
|
|
7
|
-
[32m✓[39m tests/codegen-models.test.ts [2m([22m[
|
|
6
|
+
[32m✓[39m tests/codegen-client.test.ts [2m([22m[2m35 tests[22m[2m)[22m[32m 138[2mms[22m[39m
|
|
7
|
+
[32m✓[39m tests/codegen-models.test.ts [2m([22m[2m37 tests[22m[2m)[22m[32m 115[2mms[22m[39m
|
|
8
8
|
|
|
9
9
|
[2m Test Files [22m [1m[32m2 passed[39m[22m[90m (2)[39m
|
|
10
|
-
[2m Tests [22m [1m[
|
|
11
|
-
[2m Start at [22m
|
|
12
|
-
[2m Duration [22m 4.
|
|
10
|
+
[2m Tests [22m [1m[32m72 passed[39m[22m[90m (72)[39m
|
|
11
|
+
[2m Start at [22m 17:30:03
|
|
12
|
+
[2m Duration [22m 4.75s[2m (transform 1.47s, setup 0ms, import 6.02s, tests 253ms, environment 0ms)[22m
|
|
13
13
|
|
|
14
14
|
[34m % [39m[2mCoverage report from [22m[33mv8[39m
|
|
15
15
|
-------------------|---------|----------|---------|---------|-------------------
|
|
16
16
|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
17
17
|
-------------------|---------|----------|---------|---------|-------------------
|
|
18
|
-
All files | 85.
|
|
19
|
-
src | 85.
|
|
20
|
-
...gen-client.ts | 86.
|
|
21
|
-
...gen-models.ts |
|
|
18
|
+
All files | 85.65 | 79.49 | 88.39 | 87.01 |
|
|
19
|
+
src | 85.56 | 79.58 | 87.35 | 86.67 |
|
|
20
|
+
...gen-client.ts | 86.16 | 79.87 | 91.07 | 86.45 | ...01-721,754-755
|
|
21
|
+
...gen-models.ts | 84.52 | 78.98 | 80.64 | 87.05 | ...64,378-380,384
|
|
22
22
|
tests | 86.95 | 78.37 | 92 | 92.3 |
|
|
23
23
|
helpers.ts | 86.95 | 78.37 | 92 | 92.3 | 137-141,170
|
|
24
24
|
-------------------|---------|----------|---------|---------|-------------------
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
# @contractkit/contractkit-plugin-python
|
|
2
2
|
|
|
3
|
+
## 0.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e102a2c: Add a `decimal` scalar, for money and anything else that has to be exact
|
|
8
|
+
|
|
9
|
+
`number` compiles to `z.coerce.number()` — an IEEE-754 double. Anything monetary has to be exact,
|
|
10
|
+
so contracts either lied about their types or routed the value through `string` by hand. `decimal`
|
|
11
|
+
gives the language a type for it:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
contract Payslip: {
|
|
15
|
+
gross: decimal(min=0, scale=2)
|
|
16
|
+
rate: decimal
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
A decimal travels as a **quoted JSON string** (`{"gross": "1250.00"}`) and becomes a decimal.js
|
|
21
|
+
`Decimal` — the same class Prisma hands you for a `Decimal` column, so a value moves between the
|
|
22
|
+
two with no conversion. Python gets `decimal.Decimal`; OpenAPI gets `type: string, format: decimal`.
|
|
23
|
+
|
|
24
|
+
A raw JSON number is **rejected**, not coerced. By the time one reaches the schema it has already
|
|
25
|
+
been through a double, which is precisely the loss the scalar exists to prevent, so accepting it
|
|
26
|
+
would defeat the point silently.
|
|
27
|
+
|
|
28
|
+
**`scale=` is a validation constraint — at most N decimal places — not a formatting directive.**
|
|
29
|
+
It cannot be one: the router assigns `ctx.body` and Koa serializes it with a `JSON.stringify` we
|
|
30
|
+
have no replacer for, so the wire form is whatever decimal.js normalizes to and `"1250.00"` reads
|
|
31
|
+
back as `"1250"`. The two are the same number; format at the display edge if you need the trailing
|
|
32
|
+
zeros. This is also what `scale` means in OpenAPI `pattern`, pydantic `condecimal(decimal_places=)`
|
|
33
|
+
and Prisma `@db.Decimal(_, n)`, so every downstream mapping stays honest.
|
|
34
|
+
|
|
35
|
+
Generated code sets `Decimal.set({ toExpNeg: -9e15, toExpPos: 9e15 })` so values never serialize in
|
|
36
|
+
exponential notation — without it `0.00000001` ships as `"1e-8"` and any peer validating
|
|
37
|
+
`^-?\d+(\.\d+)?$` rejects it. Note this is global decimal.js configuration and affects every
|
|
38
|
+
`Decimal` in the consuming process.
|
|
39
|
+
|
|
40
|
+
SDK clients rehydrate decimals through generated `reviveX` functions. The `bigint` approach does
|
|
41
|
+
not transfer — it works only because bigint invented a tagged `"123n"` wire encoding, and tagging a
|
|
42
|
+
decimal would corrupt the format for every non-ContractKit consumer. Re-parsing responses through
|
|
43
|
+
the Zod schema is not available either: `XOutput` is a type alias with no runtime value, and models
|
|
44
|
+
default to `z.strictObject`, so any field the server added would throw in every deployed client.
|
|
45
|
+
The revivers mutate in place, which preserves unknown server-added keys.
|
|
46
|
+
|
|
47
|
+
Two placements are rejected at parse time, both errors rather than warnings since no existing
|
|
48
|
+
contract can be relying on them. A decimal inside an **undiscriminated union** cannot be rehydrated
|
|
49
|
+
— the SDK has no way to tell which arm arrived, and a convert-if-string fallback would silently
|
|
50
|
+
rewrite a genuine `string` field in a sibling arm. A decimal in a **response header** has no
|
|
51
|
+
parsing step at all, so the annotation would simply be false at runtime.
|
|
52
|
+
|
|
53
|
+
`min`/`max` are kept as exact decimal strings rather than coerced through `Number()`, and OpenAPI
|
|
54
|
+
carries them in `x-contractkit-min`/`-max` extensions, since JSON Schema's numeric `minimum` and
|
|
55
|
+
`maximum` are ignored on a string type. A contract round-trips through OpenAPI and back with its
|
|
56
|
+
bounds intact.
|
|
57
|
+
|
|
58
|
+
SDKs that scaffold a `package.json` gain `decimal.js` as a dependency when a covered model uses the
|
|
59
|
+
scalar. Existing scaffolds are write-once and are not updated, so add it by hand there.
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- Updated dependencies [e102a2c]
|
|
64
|
+
- @contractkit/core@0.28.0
|
|
65
|
+
|
|
3
66
|
## 0.12.3
|
|
4
67
|
|
|
5
68
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen-client.d.ts","sourceRoot":"","sources":["../src/codegen-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EAQb,MAAM,mBAAmB,CAAC;AAqD3B,MAAM,WAAW,oBAAoB;IACjC,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,UAAQ,GAAG,OAAO,CAOtF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,oBAAyB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"codegen-client.d.ts","sourceRoot":"","sources":["../src/codegen-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EAQb,MAAM,mBAAmB,CAAC;AAqD3B,MAAM,WAAW,oBAAoB;IACjC,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,UAAQ,GAAG,OAAO,CAOtF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,oBAAyB,GAAG,MAAM,CAiJ9F;AAmfD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ3D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7D;AAmCD,eAAO,MAAM,cAAc,6+KAyI1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen-models.d.ts","sourceRoot":"","sources":["../src/codegen-models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAwB,gBAAgB,EAAkB,MAAM,mBAAmB,CAAC;AAKlH,MAAM,WAAW,mBAAmB;IAChC,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,GAAE,mBAAwB,GAAG,MAAM,CAwDrG;
|
|
1
|
+
{"version":3,"file":"codegen-models.d.ts","sourceRoot":"","sources":["../src/codegen-models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAwB,gBAAgB,EAAkB,MAAM,mBAAmB,CAAC;AAKlH,MAAM,WAAW,mBAAmB;IAChC,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,GAAE,mBAAwB,GAAG,MAAM,CAwDrG;AAyGD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,QAAQ,UAAQ,GAAG,MAAM,CAkC5G;AA+CD,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUtD;AAuKD,kHAAkH;AAClH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ3D"}
|
package/dist/index.js
CHANGED
|
@@ -120,6 +120,9 @@ function scanTypeImports(type, imports) {
|
|
|
120
120
|
case "duration":
|
|
121
121
|
imports.add("datetime", "timedelta");
|
|
122
122
|
break;
|
|
123
|
+
case "decimal":
|
|
124
|
+
imports.add("decimal", "Decimal");
|
|
125
|
+
break;
|
|
123
126
|
case "uuid":
|
|
124
127
|
imports.add("uuid", "UUID");
|
|
125
128
|
break;
|
|
@@ -211,6 +214,8 @@ function renderScalar(name) {
|
|
|
211
214
|
return "int";
|
|
212
215
|
case "bigint":
|
|
213
216
|
return "int";
|
|
217
|
+
case "decimal":
|
|
218
|
+
return "Decimal";
|
|
214
219
|
case "boolean":
|
|
215
220
|
return "bool";
|
|
216
221
|
case "date":
|
|
@@ -451,6 +456,7 @@ function generatePythonClient(root, opts = {}) {
|
|
|
451
456
|
const needsDatetime = referencedModels.has("__datetime__");
|
|
452
457
|
const needsDate = referencedModels.has("__date__");
|
|
453
458
|
const needsTime = referencedModels.has("__time__");
|
|
459
|
+
const needsDecimal = referencedModels.has("__decimal__");
|
|
454
460
|
const needsUUID = referencedModels.has("__uuid__");
|
|
455
461
|
const needsAny = referencedModels.has("__any__");
|
|
456
462
|
if (needsDatetime || needsDate || needsTime) {
|
|
@@ -460,6 +466,7 @@ function generatePythonClient(root, opts = {}) {
|
|
|
460
466
|
if (needsTime) dtParts.push("time");
|
|
461
467
|
lines.push(`from datetime import ${dtParts.join(", ")}`);
|
|
462
468
|
}
|
|
469
|
+
if (needsDecimal) lines.push("from decimal import Decimal");
|
|
463
470
|
if (needsUUID) lines.push("from uuid import UUID");
|
|
464
471
|
const publicOps = [];
|
|
465
472
|
for (const route of root.routes) {
|
|
@@ -945,6 +952,9 @@ function collectTypeRefs(type, out, modelsWithInput, forInput = false) {
|
|
|
945
952
|
case "datetime":
|
|
946
953
|
out.add("__datetime__");
|
|
947
954
|
break;
|
|
955
|
+
case "decimal":
|
|
956
|
+
out.add("__decimal__");
|
|
957
|
+
break;
|
|
948
958
|
case "uuid":
|
|
949
959
|
out.add("__uuid__");
|
|
950
960
|
break;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/codegen-models.ts","../src/codegen-client.ts"],"sourcesContent":["import { resolve, join, relative, dirname } from 'node:path';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, rmdirSync } from 'node:fs';\nimport type {\n ContractKitPlugin,\n PluginContext,\n ContractRootNode,\n OpRootNode,\n ModelNode,\n IncrementalManifest,\n IncrementalUnit,\n} from '@contractkit/core';\nimport {\n runIncrementalCodegen,\n parseIncrementalManifest,\n emptyIncrementalManifest,\n serializeIncrementalManifest,\n hashFingerprint,\n collectTransitiveModelRefs,\n collectTypeRefs,\n} from '@contractkit/core';\nimport { generatePydanticModels, deriveModelsModuleName } from './codegen-models.js';\nimport {\n generatePythonClient,\n deriveClientClassName,\n deriveClientModuleName,\n deriveClientPropertyName,\n hasPublicOperations,\n BASE_CLIENT_PY,\n} from './codegen-client.js';\n\nexport interface PythonSdkPluginConfig {\n /** Output directory relative to rootDir (default: \"python-sdk\") */\n baseDir?: string;\n /** Python package name used in the aggregator class name (default: \"Sdk\") */\n packageName?: string;\n /**\n * Whether to emit client methods for operations marked `internal`. Defaults to `false` —\n * internal ops are omitted so consumers don't pick them up. Set to `true` for an\n * internal-use SDK that should expose them.\n */\n includeInternal?: boolean;\n}\n\n/**\n * Bumped when the Python codegen output shape changes in a way that should\n * invalidate every per-file fingerprint. Mixed into the manifest's\n * `codegenVersion`, so a plugin upgrade forces full regeneration even when no\n * `.ck` files have changed.\n */\nexport const PYTHON_CODEGEN_VERSION = '1';\n\n/** Filename for the persisted Python manifest under the CLI cache directory. */\nconst CACHE_MANIFEST_FILENAME = 'python-manifest.json';\n\nconst plugin: ContractKitPlugin = {\n name: 'python-sdk',\n async generateTargets(inputs, ctx) {\n const config = ctx.options as PythonSdkPluginConfig;\n await runPythonCodegen(inputs, ctx, config, ctx.rootDir);\n },\n};\n\nexport default plugin;\n\nexport function createPythonSdkPlugin(config: PythonSdkPluginConfig, rootDir: string): ContractKitPlugin {\n return {\n name: 'python-sdk',\n async generateTargets(inputs, ctx) {\n await runPythonCodegen(inputs, ctx, config, rootDir);\n },\n };\n}\n\n/**\n * Shared orchestration. Builds per-file fingerprints, reuses unchanged outputs from\n * the manifest, regenerates only the affected client/model files, and rewrites the\n * shared aggregator + base files (cheap, depend only on the set of public clients).\n *\n * Honors `ctx.cacheEnabled` so `--force` bypasses the per-file cache.\n */\nasync function runPythonCodegen(\n inputs: Parameters<NonNullable<ContractKitPlugin['generateTargets']>>[0],\n ctx: PluginContext,\n config: PythonSdkPluginConfig,\n rootDir: string,\n): Promise<void> {\n const { contractRoots, opRoots } = inputs;\n const modelsWithInput = inputs.modelsWithInput as Set<string>;\n const outDir = resolve(rootDir, config.baseDir ?? 'python-sdk');\n const manifestPath = resolve(ctx.cacheDir, CACHE_MANIFEST_FILENAME);\n\n // ── Build cross-file lookup tables ───────────────────────────────────────\n const modelModulePaths = new Map<string, string>();\n const modelMap = new Map<string, ModelNode>();\n const contractEntries: { moduleName: string; relPath: string; root: ContractRootNode }[] = [];\n\n for (const root of contractRoots) {\n const moduleName = deriveModelsModuleName(root.file);\n contractEntries.push({ moduleName, relPath: `${moduleName}.py`, root });\n for (const model of root.models) {\n modelMap.set(model.name, model);\n modelModulePaths.set(model.name, `.${moduleName}`);\n if (modelsWithInput.has(model.name)) {\n modelModulePaths.set(`${model.name}Input`, `.${moduleName}`);\n }\n }\n }\n\n // Stable, sorted view of modelsWithInput for fingerprint slicing — only the\n // intersection with each unit's referenced names ends up in its fingerprint.\n const modelsWithInputArray = [...modelsWithInput].sort();\n\n const prevManifest: IncrementalManifest = ctx.cacheEnabled ? readManifest(manifestPath) : emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);\n const units: IncrementalUnit[] = [];\n\n // ── Per-contract-root model files ────────────────────────────────────────\n for (const { moduleName, relPath, root } of contractEntries) {\n const ownNames = new Set(root.models.map(m => m.name));\n const externalRefs = collectExternalRefsFromContract(root, ownNames);\n // Module paths that this file actually imports — excludes self-refs and any\n // cross-file refs not used by this file's models.\n const referencedModulePaths: Record<string, string> = {};\n for (const ref of [...externalRefs].sort()) {\n const path = modelModulePaths.get(ref);\n if (path) referencedModulePaths[ref] = path;\n const inputPath = modelModulePaths.get(`${ref}Input`);\n if (inputPath) referencedModulePaths[`${ref}Input`] = inputPath;\n }\n const relevantInputModels = modelsWithInputArray.filter(name => ownNames.has(name) || externalRefs.has(name));\n\n const fingerprint = hashFingerprint({\n kind: 'models',\n v: PYTHON_CODEGEN_VERSION,\n relPath,\n currentModule: `.${moduleName}`,\n root,\n referencedModulePaths,\n modelsWithInput: relevantInputModels,\n });\n\n units.push({\n key: `models::${relPath}`,\n fingerprint,\n render: () => [\n {\n relativePath: relPath,\n content: generatePydanticModels(root, {\n modelModulePaths,\n currentModule: `.${moduleName}`,\n modelsWithInput,\n }),\n },\n ],\n });\n }\n\n // ── Per-op-root client files ─────────────────────────────────────────────\n const clientInfos: { moduleName: string; className: string; propertyName: string }[] = [];\n\n for (const root of opRoots) {\n if (!hasPublicOperations(root, config.includeInternal)) continue;\n const moduleName = deriveClientModuleName(root.file);\n const relPath = `${moduleName}.py`;\n clientInfos.push({\n moduleName,\n className: deriveClientClassName(root.file),\n propertyName: deriveClientPropertyName(root.file),\n });\n\n const referencedModels = collectOpRootModelRefs(root, modelMap);\n const referencedModulePaths: Record<string, string> = {};\n for (const ref of [...referencedModels].sort()) {\n const path = modelModulePaths.get(ref);\n if (path) referencedModulePaths[ref] = path;\n const inputPath = modelModulePaths.get(`${ref}Input`);\n if (inputPath) referencedModulePaths[`${ref}Input`] = inputPath;\n }\n const relevantInputModels = modelsWithInputArray.filter(name => referencedModels.has(name));\n\n const fingerprint = hashFingerprint({\n kind: 'client',\n v: PYTHON_CODEGEN_VERSION,\n relPath,\n currentModule: `.${moduleName}`,\n root,\n referencedModulePaths,\n modelsWithInput: relevantInputModels,\n includeInternal: config.includeInternal ?? false,\n });\n\n units.push({\n key: `client::${relPath}`,\n fingerprint,\n render: () => [\n {\n relativePath: relPath,\n content: generatePythonClient(root, {\n modelModulePaths,\n currentModule: `.${moduleName}`,\n modelsWithInput,\n includeInternal: config.includeInternal,\n }),\n },\n ],\n });\n }\n\n // ── Global files: base client, requirements, aggregator ──────────────────\n // The aggregator (__init__.py) depends on the public-clients list. Writing it\n // every run is cheap (a few imports + a class body), so we skip a separate\n // unit for it. base_client.py and requirements.txt are constants.\n const sdkClassName = config.packageName\n ? config.packageName\n .split(/[-._\\s]+/)\n .map(s => s.charAt(0).toUpperCase() + s.slice(1))\n .join('') + 'Sdk'\n : 'Sdk';\n\n const initLines: string[] = [\n '# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.',\n 'from ._base_client import BaseClient, SdkError',\n ];\n for (const c of clientInfos) {\n initLines.push(`from .${c.moduleName} import ${c.className}`);\n }\n initLines.push('');\n initLines.push('');\n if (clientInfos.length > 0) {\n initLines.push(`class ${sdkClassName}(BaseClient):`);\n initLines.push(` def __init__(self, base_url: str, headers: dict[str, str] | None = None):`);\n initLines.push(` super().__init__(base_url, headers)`);\n for (const c of clientInfos) {\n initLines.push(` self.${c.propertyName} = ${c.className}(base_url, headers)`);\n }\n initLines.push('');\n } else {\n initLines.push(`class ${sdkClassName}(BaseClient):`);\n initLines.push(` pass`);\n initLines.push('');\n }\n const allNames = ['BaseClient', 'SdkError', sdkClassName, ...clientInfos.map(c => c.className)];\n initLines.push(`__all__ = [${allNames.map(n => JSON.stringify(n)).join(', ')}]`);\n initLines.push('');\n\n const globalFiles = [\n { relativePath: '_base_client.py', content: BASE_CLIENT_PY },\n { relativePath: 'requirements.txt', content: 'httpx\\npydantic>=2.0\\n' },\n { relativePath: '__init__.py', content: initLines.join('\\n') },\n ];\n\n const result = runIncrementalCodegen({\n codegenVersion: PYTHON_CODEGEN_VERSION,\n prevManifest,\n globalFiles,\n units,\n fileExists: relPath => existsSync(resolve(outDir, relPath)),\n });\n\n deleteStalePaths(outDir, result.deletedPaths);\n\n for (const { relativePath, content } of result.filesToWrite) {\n ctx.emitFile(resolve(outDir, relativePath), content);\n }\n\n writeManifest(manifestPath, result.manifest);\n // Suppress unused import warning — `relative` is reserved for future use.\n void relative;\n}\n\n/** Collect every model name referenced by the contract root that isn't defined within it. */\nfunction collectExternalRefsFromContract(root: ContractRootNode, ownNames: Set<string>): Set<string> {\n const refs = new Set<string>();\n for (const m of root.models) {\n if (m.type) collectTypeRefs(m.type, refs);\n for (const f of m.fields) collectTypeRefs(f.type, refs);\n if (m.bases) {\n for (const b of m.bases) refs.add(b);\n }\n }\n for (const own of ownNames) refs.delete(own);\n return refs;\n}\n\n/** Collect every model name referenced (transitively) by an op root. */\nfunction collectOpRootModelRefs(root: OpRootNode, modelMap: Map<string, ModelNode>): Set<string> {\n const seeds = [];\n for (const route of root.routes) {\n if (route.params) seeds.push(...paramSourceTypes(route.params));\n for (const op of route.operations) {\n if (op.query) seeds.push(...paramSourceTypes(op.query));\n if (op.headers) seeds.push(...paramSourceTypes(op.headers));\n if (op.request) {\n for (const body of op.request.bodies) seeds.push(body.bodyType);\n }\n for (const resp of op.responses) {\n for (const body of resp.bodies) seeds.push(body.bodyType);\n if (resp.headers) {\n for (const h of resp.headers) seeds.push(h.type);\n }\n }\n }\n }\n return collectTransitiveModelRefs(seeds, modelMap);\n}\n\nfunction paramSourceTypes(src: NonNullable<OpRootNode['routes'][number]['params']>): Parameters<typeof collectTypeRefs>[0][] {\n const out: Parameters<typeof collectTypeRefs>[0][] = [];\n if (src.kind === 'params') {\n for (const n of src.nodes) out.push(n.type);\n } else if (src.kind === 'ref') {\n out.push({ kind: 'ref', name: src.name } as Parameters<typeof collectTypeRefs>[0]);\n } else if (src.kind === 'type') {\n out.push(src.node);\n }\n return out;\n}\n\n/** Read the previous run's manifest from `manifestPath`. Returns an empty manifest when missing or unreadable. */\nfunction readManifest(manifestPath: string): IncrementalManifest {\n if (!existsSync(manifestPath)) return emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);\n try {\n return parseIncrementalManifest(readFileSync(manifestPath, 'utf-8'));\n } catch {\n return emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);\n }\n}\n\n/** Write the manifest to `manifestPath`. Creates parent dirs as needed. Errors are swallowed so a broken cache never blocks the build. */\nfunction writeManifest(manifestPath: string, manifest: IncrementalManifest): void {\n try {\n mkdirSync(dirname(manifestPath), { recursive: true });\n writeFileSync(manifestPath, serializeIncrementalManifest(manifest), 'utf-8');\n } catch {\n // best-effort\n }\n}\n\n/** Delete paths from the prior manifest that aren't produced this run. Mirrors the Bruno cleanup approach. */\nfunction deleteStalePaths(outDir: string, relPaths: string[]): void {\n if (relPaths.length === 0) return;\n const removedDirs = new Set<string>();\n for (const rel of relPaths) {\n const abs = resolve(outDir, rel);\n if (existsSync(abs)) {\n rmSync(abs, { force: true });\n removedDirs.add(join(abs, '..'));\n }\n }\n for (const dir of removedDirs) {\n let current = dir;\n while (current.startsWith(outDir) && current !== outDir) {\n try {\n if (readdirSync(current).length === 0) {\n rmdirSync(current);\n current = join(current, '..');\n } else {\n break;\n }\n } catch {\n break;\n }\n }\n }\n}\n","import type { ContractRootNode, ModelNode, FieldNode, ContractTypeNode, ScalarTypeNode } from '@contractkit/core';\nimport { computeModelsWithInput, topoSortModels, collectExternalRefs, collectExternalInputRefs } from '@contractkit/core';\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\nexport interface ModelCodegenOptions {\n /** Map from model name → output module name (for cross-file imports) */\n modelModulePaths?: Map<string, string>;\n /** Current output module name (used to skip self-imports) */\n currentModule?: string;\n /** Set of model names that have Input variants (cross-file) */\n modelsWithInput?: Set<string>;\n}\n\n/**\n * Generate Pydantic v2 model classes from a ContractRootNode.\n */\nexport function generatePydanticModels(root: ContractRootNode, opts: ModelCodegenOptions = {}): string {\n const externalRefs = collectExternalRefs(root);\n const externalModelsWithInput = opts.modelsWithInput ?? new Set<string>();\n const localModelsWithInput = computeModelsWithInput(root.models, externalModelsWithInput);\n const allModelsWithInput = new Set([...localModelsWithInput, ...externalModelsWithInput]);\n\n const externalInputRefs = allModelsWithInput.size > 0 ? collectExternalInputRefs(root, allModelsWithInput) : [];\n const allExternalRefs = [...new Set([...externalRefs, ...externalInputRefs])].sort();\n\n // Track needed imports\n const imports = new ImportTracker();\n imports.add('pydantic', 'BaseModel');\n\n // Pre-scan all models to determine what imports will be needed\n for (const model of root.models) {\n if (model.type) {\n scanTypeImports(model.type, imports);\n } else {\n for (const f of model.fields) {\n scanTypeImports(f.type, imports);\n }\n }\n }\n\n const lines: string[] = [];\n lines.push('# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.');\n lines.push('from __future__ import annotations');\n\n // Cross-file imports for external model refs\n const crossFileImports: string[] = [];\n for (const ref of allExternalRefs) {\n const modulePath = opts.modelModulePaths?.get(ref);\n if (modulePath && modulePath !== opts.currentModule) {\n crossFileImports.push(`from ${modulePath} import ${ref}`);\n }\n }\n\n // We'll prepend stdlib/typing imports after, once we know what's needed\n // Build model output first\n const modelLines: string[] = [];\n for (const model of topoSortModels(root.models)) {\n modelLines.push('');\n modelLines.push(...generateModel(model, allModelsWithInput, imports));\n }\n\n // Now emit stdlib imports\n const stdlibLines = imports.render();\n lines.push(...stdlibLines);\n if (crossFileImports.length > 0) {\n lines.push('');\n lines.push(...crossFileImports);\n }\n lines.push(...modelLines);\n lines.push('');\n\n return lines.join('\\n');\n}\n\n// ─── Import tracking ──────────────────────────────────────────────────────\n\nclass ImportTracker {\n private groups: Map<string, Set<string>> = new Map();\n\n add(module: string, name: string): void {\n let s = this.groups.get(module);\n if (!s) {\n s = new Set();\n this.groups.set(module, s);\n }\n s.add(name);\n }\n\n has(module: string, name: string): boolean {\n return this.groups.get(module)?.has(name) ?? false;\n }\n\n render(): string[] {\n // Order: stdlib → typing → pydantic\n const ORDER = ['__future__', 'datetime', 'uuid', 'typing', 'pydantic'];\n const lines: string[] = [];\n lines.push('');\n for (const mod of ORDER) {\n const names = this.groups.get(mod);\n if (!names || names.size === 0) continue;\n const sorted = [...names].sort().join(', ');\n lines.push(`from ${mod} import ${sorted}`);\n }\n // Any remaining\n for (const [mod, names] of this.groups) {\n if (ORDER.includes(mod)) continue;\n const sorted = [...names].sort().join(', ');\n lines.push(`from ${mod} import ${sorted}`);\n }\n return lines;\n }\n}\n\nfunction scanTypeImports(type: ContractTypeNode, imports: ImportTracker): void {\n switch (type.kind) {\n case 'scalar':\n switch (type.name) {\n case 'date':\n imports.add('datetime', 'date');\n break;\n case 'time':\n imports.add('datetime', 'time');\n break;\n case 'datetime':\n imports.add('datetime', 'datetime');\n break;\n case 'duration':\n imports.add('datetime', 'timedelta');\n break;\n case 'uuid':\n imports.add('uuid', 'UUID');\n break;\n case 'unknown':\n case 'json':\n case 'object':\n imports.add('typing', 'Any');\n break;\n }\n break;\n case 'enum':\n imports.add('typing', 'Literal');\n break;\n case 'union':\n type.members.forEach(m => scanTypeImports(m, imports));\n break;\n case 'discriminatedUnion':\n imports.add('typing', 'Annotated');\n imports.add('pydantic', 'Field');\n type.members.forEach(m => scanTypeImports(m, imports));\n break;\n case 'intersection':\n imports.add('typing', 'Any');\n break;\n case 'array':\n scanTypeImports(type.item, imports);\n break;\n case 'tuple':\n type.items.forEach(t => scanTypeImports(t, imports));\n break;\n case 'record':\n scanTypeImports(type.key, imports);\n scanTypeImports(type.value, imports);\n break;\n case 'lazy':\n scanTypeImports(type.inner, imports);\n break;\n case 'inlineObject':\n imports.add('typing', 'Any');\n break;\n }\n}\n\n// ─── Type rendering ───────────────────────────────────────────────────────\n\n/**\n * Render a ContractKit type node as its Python type annotation (Pydantic v2 conventions).\n *\n * @param modelsWithInput - Model names that have a distinct `Input` variant; a `ref` to one of\n * these renders as `<Name>Input` when `forInput` is set.\n * @param forInput - When true, request-side refs use their `Input` variant.\n * @throws {Error} Via the scalar renderer, if a scalar name has no Python mapping (guards against\n * a scalar being added to core without updating this plugin).\n */\nexport function renderPyType(type: ContractTypeNode, modelsWithInput?: Set<string>, forInput = false): string {\n switch (type.kind) {\n case 'scalar':\n return renderScalar(type.name);\n case 'enum':\n return `Literal[${type.values.map(v => JSON.stringify(v)).join(', ')}]`;\n case 'literal':\n return typeof type.value === 'string' ? JSON.stringify(type.value) : String(type.value);\n case 'array':\n return `list[${renderPyType(type.item, modelsWithInput, forInput)}]`;\n case 'tuple':\n if (type.items.length === 0) return 'tuple[()]';\n return `tuple[${type.items.map(t => renderPyType(t, modelsWithInput, forInput)).join(', ')}]`;\n case 'record':\n return `dict[${renderPyType(type.key, modelsWithInput, forInput)}, ${renderPyType(type.value, modelsWithInput, forInput)}]`;\n case 'union':\n return type.members.map(m => renderPyType(m, modelsWithInput, forInput)).join(' | ');\n case 'discriminatedUnion': {\n const inner = type.members.map(m => renderPyType(m, modelsWithInput, forInput)).join(' | ');\n return `Annotated[${inner}, Field(discriminator=${JSON.stringify(type.discriminator)})]`;\n }\n case 'intersection':\n return 'dict[str, Any]';\n case 'ref': {\n if (forInput && modelsWithInput?.has(type.name)) {\n return `${type.name}Input`;\n }\n return type.name;\n }\n case 'inlineObject':\n return 'dict[str, Any]';\n case 'lazy':\n return renderPyType(type.inner, modelsWithInput, forInput);\n }\n}\n\nfunction renderScalar(name: ScalarTypeNode['name']): string {\n switch (name) {\n case 'string':\n case 'email':\n case 'url':\n return 'str';\n case 'number':\n return 'float';\n case 'int':\n return 'int';\n case 'bigint':\n return 'int';\n case 'boolean':\n return 'bool';\n case 'date':\n return 'date';\n case 'time':\n return 'time';\n case 'datetime':\n return 'datetime';\n case 'duration':\n return 'timedelta';\n case 'interval':\n return 'str';\n case 'uuid':\n return 'UUID';\n case 'null':\n return 'None';\n case 'binary':\n return 'bytes';\n case 'unknown':\n case 'json':\n case 'object':\n return 'Any';\n default: {\n const _exhaustive: never = name;\n throw new Error(`plugin-python: unmapped scalar '${String(_exhaustive)}' — add a case`);\n }\n }\n}\n\n// ─── Field name conversion ────────────────────────────────────────────────\n\n/** Convert a field name to a valid Python identifier in snake_case. */\nexport function toPythonFieldName(name: string): string {\n // Replace hyphens and non-alphanumeric chars (except underscore) with underscore\n let result = name.replace(/[^a-zA-Z0-9_]/g, '_');\n // camelCase → snake_case\n result = result.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();\n // Collapse multiple underscores\n result = result.replace(/_+/g, '_').replace(/^_|_$/g, '');\n // Prefix if starts with digit\n if (/^\\d/.test(result)) result = 'f_' + result;\n return result;\n}\n\n// ─── Comment emission ─────────────────────────────────────────────────────\n\n/**\n * Render `text` as one `#`-prefixed Python comment line per source line.\n * Descriptions come from `#` doc comments and may contain embedded newlines;\n * emitting them verbatim would leave every line after the first uncommented\n * (a SyntaxError in the generated module). `indent` is the whitespace prefix\n * that precedes `# ` at the call site.\n */\nfunction commentLines(text: string, indent: string): string[] {\n return text.split('\\n').map(line => `${indent}# ${line}`);\n}\n\n// ─── Model generation ─────────────────────────────────────────────────────\n\nfunction generateModel(model: ModelNode, allModelsWithInput: Set<string>, imports: ImportTracker): string[] {\n if (model.type) {\n return generateTypeAlias(model, allModelsWithInput, imports);\n }\n\n const needsInputSplit = model.fields.some(f => f.visibility !== 'normal') || allModelsWithInput.has(model.name);\n\n if (needsInputSplit) {\n return generateSplitModel(model, allModelsWithInput, imports);\n }\n return generateSimpleModel(model, allModelsWithInput, imports);\n}\n\nfunction generateTypeAlias(model: ModelNode, allModelsWithInput: Set<string>, _: ImportTracker): string[] {\n const lines: string[] = [];\n if (model.description) lines.push(...commentLines(model.description, ''));\n if (model.deprecated) lines.push('# @deprecated');\n lines.push(`${model.name} = ${renderPyType(model.type!, allModelsWithInput)}`);\n if (allModelsWithInput.has(model.name)) {\n lines.push(`${model.name}Input = ${renderPyType(model.type!, allModelsWithInput, true)}`);\n }\n return lines;\n}\n\nfunction generateSimpleModel(model: ModelNode, allModelsWithInput: Set<string>, imports: ImportTracker): string[] {\n const lines: string[] = [];\n if (model.description) lines.push(...commentLines(model.description, ''));\n if (model.deprecated) lines.push('# @deprecated');\n\n const baseList = model.bases && model.bases.length > 0 ? model.bases.join(', ') : 'BaseModel';\n lines.push(`class ${model.name}(${baseList}):`);\n\n const fieldLines = renderFields(model.fields, allModelsWithInput, imports, false);\n const needsConfig = model.fields.some(f => toPythonFieldName(f.name) !== f.name);\n if (needsConfig) {\n imports.add('pydantic', 'ConfigDict');\n lines.push(` model_config = ConfigDict(populate_by_name=True)`);\n lines.push('');\n }\n\n if (fieldLines.length === 0) {\n lines.push(' pass');\n } else {\n lines.push(...fieldLines);\n }\n\n return lines;\n}\n\nfunction generateSplitModel(model: ModelNode, allModelsWithInput: Set<string>, imports: ImportTracker): string[] {\n const lines: string[] = [];\n\n // Read model — omit writeonly fields\n const readFields = model.fields.filter(f => f.visibility !== 'writeonly');\n if (model.description) lines.push(...commentLines(model.description, ''));\n if (model.deprecated) lines.push('# @deprecated');\n\n const readBaseList = model.bases && model.bases.length > 0 ? model.bases.join(', ') : 'BaseModel';\n lines.push(`class ${model.name}(${readBaseList}):`);\n const readNeedsConfig = readFields.some(f => toPythonFieldName(f.name) !== f.name);\n if (readNeedsConfig) {\n imports.add('pydantic', 'ConfigDict');\n lines.push(` model_config = ConfigDict(populate_by_name=True)`);\n lines.push('');\n }\n const readFieldLines = renderFields(readFields, allModelsWithInput, imports, false);\n if (readFieldLines.length === 0) {\n lines.push(' pass');\n } else {\n lines.push(...readFieldLines);\n }\n\n lines.push('');\n\n // Input model — omit readonly fields\n const writeFields = model.fields.filter(f => f.visibility !== 'readonly');\n const inputBaseList =\n model.bases && model.bases.length > 0 ? model.bases.map(b => (allModelsWithInput.has(b) ? `${b}Input` : b)).join(', ') : 'BaseModel';\n lines.push(`class ${model.name}Input(${inputBaseList}):`);\n const writeNeedsConfig = writeFields.some(f => toPythonFieldName(f.name) !== f.name);\n if (writeNeedsConfig) {\n imports.add('pydantic', 'ConfigDict');\n lines.push(` model_config = ConfigDict(populate_by_name=True)`);\n lines.push('');\n }\n const writeFieldLines = renderFields(writeFields, allModelsWithInput, imports, true);\n if (writeFieldLines.length === 0) {\n lines.push(' pass');\n } else {\n lines.push(...writeFieldLines);\n }\n\n return lines;\n}\n\nfunction renderFields(fields: FieldNode[], allModelsWithInput: Set<string>, imports: ImportTracker, forInput: boolean): string[] {\n const lines: string[] = [];\n for (const f of fields) {\n lines.push(...renderField(f, allModelsWithInput, imports, forInput));\n }\n return lines;\n}\n\nfunction renderField(field: FieldNode, allModelsWithInput: Set<string>, imports: ImportTracker, forInput: boolean): string[] {\n const lines: string[] = [];\n const pyName = toPythonFieldName(field.name);\n const needsAlias = pyName !== field.name;\n\n let typeStr = renderPyType(field.type, allModelsWithInput, forInput);\n if (field.nullable) typeStr = `${typeStr} | None`;\n\n const isOptional = field.optional || field.default !== undefined;\n\n const fieldAnnotations: string[] = [];\n if (needsAlias) {\n imports.add('pydantic', 'Field');\n fieldAnnotations.push(`alias=${JSON.stringify(field.name)}`);\n }\n if (field.default !== undefined) {\n const def = typeof field.default === 'string' ? JSON.stringify(field.default) : String(field.default);\n fieldAnnotations.push(`default=${def}`);\n }\n\n if (field.deprecated) lines.push(` # @deprecated`);\n if (field.description) lines.push(...commentLines(field.description, ' '));\n\n let rhs: string;\n if (fieldAnnotations.length > 0) {\n imports.add('pydantic', 'Field');\n rhs = `Field(${fieldAnnotations.join(', ')})`;\n } else if (isOptional) {\n rhs = 'None';\n } else {\n rhs = '';\n }\n\n const optSuffix = isOptional && !field.nullable ? ` | None` : '';\n const fullType = typeStr + optSuffix;\n\n if (rhs) {\n lines.push(` ${pyName}: ${fullType} = ${rhs}`);\n } else {\n lines.push(` ${pyName}: ${fullType}`);\n }\n\n return lines;\n}\n\n// ─── Module name helpers ──────────────────────────────────────────────────\n\n/** Derive a Python module name from a .ck file path, e.g. \"ledger.categories.ck\" → \"_models_ledger_categories\" */\nexport function deriveModelsModuleName(file: string): string {\n const base =\n file\n .split('/')\n .pop()\n ?.replace(/\\.(op\\.)?ck$/, '') ?? 'models';\n const clean = base.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase();\n return `_models_${clean}`;\n}\n","import type {\n OpRootNode,\n OpRouteNode,\n OpOperationNode,\n OpResponseNode,\n OpResponseBodyNode,\n OpResponseHeaderNode,\n ContractTypeNode,\n ParamSource,\n} from '@contractkit/core';\nimport { resolveModifiers, classifyContentType, observableResponses } from '@contractkit/core';\nimport { renderPyType, toPythonFieldName } from './codegen-models.js';\n\n// ─── Response shape ────────────────────────────────────────────────────────\n\n/**\n * How a method reports what came back, mirroring the TypeScript SDK.\n *\n * `simple` is the overwhelmingly common case and generates exactly what it always has: the body\n * itself, or a `(data, headers)` tuple. The other two exist because the caller cannot otherwise\n * know which status or which mime it received.\n */\ntype PyResponseShape =\n | { kind: 'simple'; resp?: OpResponseNode }\n | { kind: 'multiMime'; resp: OpResponseNode }\n | { kind: 'multiStatus'; responses: OpResponseNode[] };\n\nfunction headersClassName(methodBase: string, statusCode?: number): string {\n return statusCode === undefined ? `${methodBase}Headers` : `${methodBase}${statusCode}Headers`;\n}\n\nfunction responseClassName(methodBase: string, statusCode?: number): string {\n return statusCode === undefined ? `${methodBase}Response` : `${methodBase}${statusCode}Response`;\n}\n\n/** The Python type of one response body — non-JSON mimes ignore the schema, as elsewhere. */\nfunction pyBodyType(body: OpResponseBodyNode, modelsWithInput?: Set<string>): string {\n const category = classifyContentType(body.contentType);\n if (category === 'text') return 'str';\n if (category === 'binary') return 'bytes';\n return renderPyType(body.bodyType, modelsWithInput);\n}\n\nfunction pyDataAnnotation(bodies: OpResponseBodyNode[], modelsWithInput?: Set<string>): string {\n const types = [...new Set(bodies.map(b => pyBodyType(b, modelsWithInput)))];\n return types.join(' | ');\n}\n\nfunction pyContentTypeAnnotation(bodies: OpResponseBodyNode[]): string {\n return `Literal[${bodies.map(b => JSON.stringify(b.contentType)).join(', ')}]`;\n}\n\nfunction responseShape(op: OpOperationNode): PyResponseShape {\n const observable = observableResponses(op);\n if (observable.length > 1) return { kind: 'multiStatus', responses: observable };\n const resp = observable[0];\n if (resp && resp.bodies.length > 1) return { kind: 'multiMime', resp };\n return { kind: 'simple', resp };\n}\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\nexport interface ClientCodegenOptions {\n /** Map from model name → Python module path (e.g. \"._models_payments\") */\n modelModulePaths?: Map<string, string>;\n /** Current client's module name (e.g. \"_client_payments\") — used to avoid self-imports */\n currentModule?: string;\n /** Set of model names that have Input variants */\n modelsWithInput?: Set<string>;\n /**\n * Whether to emit client methods for operations marked `internal`. Defaults to `false` —\n * internal ops are omitted so consumers don't pick them up. Set to `true` for an\n * internal-use SDK that should expose them.\n */\n includeInternal?: boolean;\n}\n\n/**\n * Returns true if the root contains at least one operation eligible for client emission.\n * With `includeInternal: false` (default) that means at least one non-internal op; with\n * `includeInternal: true` any op qualifies.\n */\nexport function hasPublicOperations(root: OpRootNode, includeInternal = false): boolean {\n for (const route of root.routes) {\n for (const op of route.operations) {\n if (includeInternal || !resolveModifiers(route, op).includes('internal')) return true;\n }\n }\n return false;\n}\n\n/**\n * Generate a Pydantic/httpx async Python client class from an OpRootNode.\n */\nexport function generatePythonClient(root: OpRootNode, opts: ClientCodegenOptions = {}): string {\n const clientClassName = deriveClientClassName(root.file);\n const { modelsWithInput } = opts;\n const includeInternal = opts.includeInternal ?? false;\n\n // Collect all model types referenced in public ops\n const referencedModels = collectReferencedModels(root, modelsWithInput, includeInternal);\n\n const lines: string[] = [];\n lines.push('# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.');\n lines.push('from __future__ import annotations');\n lines.push('');\n\n // stdlib imports\n const needsDatetime = referencedModels.has('__datetime__');\n const needsDate = referencedModels.has('__date__');\n const needsTime = referencedModels.has('__time__');\n const needsUUID = referencedModels.has('__uuid__');\n const needsAny = referencedModels.has('__any__');\n\n if (needsDatetime || needsDate || needsTime) {\n const dtParts: string[] = [];\n if (needsDate) dtParts.push('date');\n if (needsDatetime) dtParts.push('datetime');\n if (needsTime) dtParts.push('time');\n lines.push(`from datetime import ${dtParts.join(', ')}`);\n }\n if (needsUUID) lines.push('from uuid import UUID');\n\n // Collect public ops once — used both for TypedDict emission and method generation.\n const publicOps: Array<{ route: OpRouteNode; op: OpOperationNode }> = [];\n for (const route of root.routes) {\n for (const op of route.operations) {\n if (!includeInternal && resolveModifiers(route, op).includes('internal')) continue;\n publicOps.push({ route, op });\n }\n }\n const opShapes = new Map<OpOperationNode, PyResponseShape>(publicOps.map(({ op }) => [op, responseShape(op)]));\n const opsWithRespHeaders = publicOps.filter(({ op }) => {\n const shape = opShapes.get(op)!;\n if (shape.kind === 'multiStatus') return shape.responses.some(r => (r.headers?.length ?? 0) > 0);\n return (shape.resp?.headers?.length ?? 0) > 0;\n });\n const opsWithResponseDict = publicOps.filter(({ op }) => opShapes.get(op)!.kind !== 'simple');\n const needsTypedDict = opsWithRespHeaders.length > 0 || opsWithResponseDict.length > 0;\n const needsLiteral = opsWithResponseDict.length > 0;\n\n if (needsAny || needsTypedDict) {\n const typingImports: string[] = [];\n if (needsAny) typingImports.push('Any');\n if (needsLiteral) typingImports.push('Literal');\n if (needsTypedDict) typingImports.push('TypedDict');\n lines.push(`from typing import ${typingImports.join(', ')}`);\n }\n lines.push('from ._base_client import BaseClient, SdkError # noqa: F401');\n\n // Model imports grouped by module\n const modelImportsByModule = new Map<string, Set<string>>();\n for (const name of referencedModels) {\n if (name.startsWith('__')) continue; // sentinel keys\n const modulePath = opts.modelModulePaths?.get(name);\n if (modulePath) {\n let s = modelImportsByModule.get(modulePath);\n if (!s) {\n s = new Set();\n modelImportsByModule.set(modulePath, s);\n }\n s.add(name);\n }\n }\n for (const [mod, names] of [...modelImportsByModule].sort((a, b) => a[0].localeCompare(b[0]))) {\n const sorted = [...names].sort().join(', ');\n lines.push(`from ${mod} import ${sorted}`);\n }\n\n // Per-method response-header TypedDicts. Multi-status methods get one per status, since\n // each status declares its own headers.\n for (const { route, op } of opsWithRespHeaders) {\n const shape = opShapes.get(op)!;\n const base = snakeToPascal(deriveMethodName(op, route));\n const targets =\n shape.kind === 'multiStatus'\n ? shape.responses.filter(r => (r.headers?.length ?? 0) > 0).map(r => ({ name: headersClassName(base, r.statusCode), resp: r }))\n : [{ name: headersClassName(base), resp: shape.resp! }];\n for (const { name, resp } of targets) {\n lines.push('');\n lines.push('');\n lines.push(`class ${name}(TypedDict, total=False):`);\n for (const h of resp.headers!) {\n const pyName = toPythonFieldName(h.name);\n const tag = h.optional ? 'optional' : 'required';\n lines.push(` ${pyName}: str # ${h.name} (${tag})`);\n }\n }\n }\n\n // Per-method response TypedDicts for the shapes that have to report status or mime.\n for (const { route, op } of opsWithResponseDict) {\n const shape = opShapes.get(op)!;\n const base = snakeToPascal(deriveMethodName(op, route));\n const targets: OpResponseNode[] = shape.kind === 'multiStatus' ? shape.responses : shape.kind === 'multiMime' ? [shape.resp] : [];\n for (const resp of targets) {\n lines.push('');\n lines.push('');\n lines.push(`class ${responseClassName(base, shape.kind === 'multiStatus' ? resp.statusCode : undefined)}(TypedDict):`);\n if (shape.kind === 'multiStatus') lines.push(` status: Literal[${resp.statusCode}]`);\n const bodies = resp.bodies;\n if (bodies.length > 0) {\n lines.push(` content_type: ${pyContentTypeAnnotation(bodies)}`);\n lines.push(` data: ${pyDataAnnotation(bodies, opts.modelsWithInput)}`);\n }\n if ((resp.headers?.length ?? 0) > 0) {\n lines.push(` headers: ${headersClassName(base, shape.kind === 'multiStatus' ? resp.statusCode : undefined)}`);\n }\n if (shape.kind !== 'multiStatus' && bodies.length === 0 && (resp.headers?.length ?? 0) === 0) {\n lines.push(' pass');\n }\n }\n }\n\n lines.push('');\n lines.push('');\n lines.push(`class ${clientClassName}(BaseClient):`);\n\n let hasAnyMethod = false;\n for (const route of root.routes) {\n for (const op of route.operations) {\n const mods = resolveModifiers(route, op);\n if (!includeInternal && mods.includes('internal')) continue;\n hasAnyMethod = true;\n lines.push('');\n if (mods.includes('deprecated')) lines.push(' # @deprecated');\n lines.push(...generateMethod(route, op, opts));\n }\n }\n\n if (!hasAnyMethod) {\n lines.push(' pass');\n }\n\n lines.push('');\n\n return lines.join('\\n');\n}\n\n// ─── Method generation ────────────────────────────────────────────────────\n\ninterface MethodParam {\n name: string;\n type: string;\n optional: boolean;\n isModel: boolean; // Pydantic BaseModel → use .model_dump(mode=\"json\")\n}\n\nfunction generateMethod(route: OpRouteNode, op: OpOperationNode, opts: ClientCodegenOptions): string[] {\n const lines: string[] = [];\n const { modelsWithInput } = opts;\n const methodName = deriveMethodName(op, route);\n const httpMethod = op.method.toUpperCase();\n\n const params = buildMethodParams(route, op, modelsWithInput);\n const selfParam = 'self';\n const allParams = params.map(p => {\n if (p.optional) return `${p.name}: ${p.type} | None = None`;\n return `${p.name}: ${p.type}`;\n });\n const paramStr = allParams.length > 0 ? `, ${allParams.join(', ')}` : '';\n\n // Return type — non-JSON responses ignore the schema and return raw bytes/str.\n //\n // `observableResponses` is shared with the Koa router and the TypeScript SDK, so all three\n // agree on which statuses are values and which are errors.\n const shape = responseShape(op);\n const methodBase = snakeToPascal(methodName);\n const primaryResponse = shape.kind === 'multiStatus' ? undefined : shape.resp;\n const primaryBodies = primaryResponse ? primaryResponse.bodies : [];\n const isVoid = primaryBodies.length === 0;\n const respCategory = primaryBodies[0] ? classifyContentType(primaryBodies[0].contentType) : 'json';\n const dataType = isVoid ? 'None' : pyBodyType(primaryBodies[0]!, modelsWithInput);\n const isModelReturn = !isVoid && respCategory === 'json' && isModelRef(primaryBodies[0]!.bodyType, modelsWithInput);\n const isListModelReturn = !isVoid && respCategory === 'json' && isListModelRef(primaryBodies[0]!.bodyType, modelsWithInput);\n const respHeaders = primaryResponse?.headers ?? [];\n const hasRespHeaders = respHeaders.length > 0;\n const headersTypeName = hasRespHeaders ? headersClassName(methodBase) : '';\n const returnType =\n shape.kind === 'multiStatus'\n ? shape.responses.map(r => responseClassName(methodBase, r.statusCode)).join(' | ')\n : shape.kind === 'multiMime'\n ? responseClassName(methodBase)\n : hasRespHeaders\n ? isVoid\n ? headersTypeName\n : `tuple[${dataType}, ${headersTypeName}]`\n : dataType;\n\n // Description\n const desc = op.description ?? route.description;\n if (op.name || desc) {\n lines.push(` async def ${methodName}(${selfParam}${paramStr}) -> ${returnType}:`);\n lines.push(` \"\"\"`);\n if (op.name) lines.push(...docstringLines(op.name, ' '));\n if (desc) lines.push(...docstringLines(desc, ' '));\n lines.push(` \"\"\"`);\n } else {\n lines.push(` async def ${methodName}(${selfParam}${paramStr}) -> ${returnType}:`);\n }\n\n // Build URL\n const urlExpr = buildUrlExpression(route.path);\n\n // Query params\n const hasQuery = !!op.query;\n const primaryBody = op.request?.bodies[0];\n const hasBody = !!primaryBody;\n const isMultipart = primaryBody?.contentType === 'multipart/form-data';\n const hasCustomHeaders = !!op.headers;\n\n // Build kwargs for _fetch\n const fetchKwargs: string[] = [];\n fetchKwargs.push(`method=\"${httpMethod}\"`);\n\n const reqCategory = primaryBody?.contentType ? classifyContentType(primaryBody.contentType) : 'json';\n if (hasBody) {\n const bodyParam = params.find(p => p.name === 'body');\n if (isMultipart) {\n fetchKwargs.push('body=body');\n } else if (reqCategory === 'text' || reqCategory === 'binary') {\n // Pass-through: caller supplies a str / bytes payload that goes on the wire as-is.\n fetchKwargs.push('body=body');\n } else if (bodyParam?.isModel) {\n fetchKwargs.push('body=body.model_dump(mode=\"json\")');\n } else {\n fetchKwargs.push('body=body');\n }\n // Forward the declared content-type so `_fetch` sets the correct Content-Type header\n // (vendor JSON types like `application/vnd.api+json` still serialize as JSON but need\n // their literal mime on the wire).\n if (primaryBody.contentType !== 'application/json') {\n fetchKwargs.push(`content_type=${JSON.stringify(primaryBody.contentType)}`);\n }\n if (reqCategory === 'text' || reqCategory === 'binary') {\n fetchKwargs.push(`body_kind=\"${reqCategory}\"`);\n }\n }\n if (shape.kind !== 'simple') {\n // Several mimes or statuses in play — only the response knows how to read itself.\n fetchKwargs.push(`response_kind=\"auto\"`);\n } else if (respCategory === 'text' || respCategory === 'binary') {\n fetchKwargs.push(`response_kind=\"${respCategory}\"`);\n }\n\n const observable = shape.kind === 'multiStatus' ? shape.responses : shape.resp ? [shape.resp] : [];\n const expectStatuses = observable.filter(r => r.statusCode < 200 || r.statusCode >= 300).map(r => r.statusCode);\n if (expectStatuses.length > 0) {\n // A single-element tuple needs the trailing comma or Python reads it as parentheses.\n const tuple = expectStatuses.length === 1 ? `(${expectStatuses[0]},)` : `(${expectStatuses.join(', ')})`;\n fetchKwargs.push(`expect_statuses=${tuple}`);\n }\n\n if (hasQuery) {\n fetchKwargs.push('params=query');\n }\n\n if (hasCustomHeaders) {\n fetchKwargs.push('extra_headers=custom_headers');\n }\n\n const kwargsStr = fetchKwargs.length > 1 ? fetchKwargs.join(', ') : (fetchKwargs[0] ?? '');\n\n if (shape.kind !== 'simple') {\n lines.push(` _status, _content_type, result, _response_headers = await self._fetch_full(${urlExpr}, ${kwargsStr})`);\n lines.push(...buildMultiReturnLines(shape, methodBase, modelsWithInput));\n return lines;\n }\n\n if (hasRespHeaders) {\n lines.push(` result, _response_headers = await self._fetch_with_headers(${urlExpr}, ${kwargsStr})`);\n lines.push(...buildHeadersDictLines(respHeaders, headersTypeName));\n } else {\n lines.push(` result = await self._fetch(${urlExpr}, ${kwargsStr})`);\n }\n\n if (isVoid) {\n if (hasRespHeaders) {\n lines.push(` return headers`);\n } else {\n lines.push(` return None`);\n }\n } else {\n let dataExpr: string;\n if (isListModelReturn) {\n const innerType = getListItemType(primaryBodies[0]!.bodyType, modelsWithInput);\n dataExpr = `[${innerType}.model_validate(item) for item in result]`;\n } else if (isModelReturn) {\n dataExpr = `${dataType}.model_validate(result)`;\n } else {\n dataExpr = 'result';\n }\n if (hasRespHeaders) {\n lines.push(` return ${dataExpr}, headers`);\n } else {\n lines.push(` return ${dataExpr}`);\n }\n }\n\n return lines;\n}\n\n/** The expression that turns a decoded body into the declared type, validating models. */\nfunction pyDataExpr(body: OpResponseBodyNode, modelsWithInput?: Set<string>): string {\n if (classifyContentType(body.contentType) !== 'json') return 'result';\n if (isListModelRef(body.bodyType, modelsWithInput)) {\n return `[${getListItemType(body.bodyType, modelsWithInput)}.model_validate(item) for item in result]`;\n }\n if (isModelRef(body.bodyType, modelsWithInput)) {\n return `${renderPyType(body.bodyType, modelsWithInput)}.model_validate(result)`;\n }\n return 'result';\n}\n\n/**\n * Return statements for a method that reports its status or mime.\n *\n * Dispatch is a chain of `if`s on the runtime status (or content type), with the first declared\n * alternative as the fall-through so the function always returns.\n */\nfunction buildMultiReturnLines(\n shape: Extract<PyResponseShape, { kind: 'multiMime' | 'multiStatus' }>,\n methodBase: string,\n modelsWithInput?: Set<string>,\n): string[] {\n const lines: string[] = [];\n\n const returnFor = (resp: OpResponseNode, body: OpResponseBodyNode | undefined, indent: string, includeStatus: boolean, headersVar?: string): string[] => {\n const entries: string[] = [];\n if (includeStatus) entries.push(`\"status\": ${resp.statusCode}`);\n if (body) {\n entries.push(`\"content_type\": ${JSON.stringify(body.contentType)}`);\n entries.push(`\"data\": ${pyDataExpr(body, modelsWithInput)}`);\n }\n if (headersVar) entries.push(`\"headers\": ${headersVar}`);\n return [`${indent}return {${entries.length > 0 ? ` ${entries.join(', ')} ` : ''}}`];\n };\n\n /** One status, dispatching over its mimes when they do not all decode the same way. */\n const emitStatus = (resp: OpResponseNode, indent: string, includeStatus: boolean): string[] => {\n const out: string[] = [];\n // Built once per status, under a name of its own: two statuses in the same method can\n // declare different headers, and Python has no block scope to keep them apart.\n let headersVar: string | undefined;\n if ((resp.headers?.length ?? 0) > 0) {\n headersVar = includeStatus ? `headers_${resp.statusCode}` : 'headers';\n const typeName = headersClassName(methodBase, includeStatus ? resp.statusCode : undefined);\n out.push(...buildHeadersDictLines(resp.headers!, typeName, indent, headersVar));\n }\n\n const bodies = resp.bodies;\n if (bodies.length <= 1) {\n out.push(...returnFor(resp, bodies[0], indent, includeStatus, headersVar));\n return out;\n }\n for (const body of bodies.slice(1)) {\n out.push(`${indent}if _content_type == ${JSON.stringify(body.contentType)}:`);\n out.push(...returnFor(resp, body, `${indent} `, includeStatus, headersVar));\n }\n out.push(...returnFor(resp, bodies[0], indent, includeStatus, headersVar));\n return out;\n };\n\n if (shape.kind === 'multiMime') {\n lines.push(...emitStatus(shape.resp, ' ', false));\n return lines;\n }\n\n const [fallback, ...rest] = shape.responses;\n for (const resp of rest) {\n lines.push(` if _status == ${resp.statusCode}:`);\n lines.push(...emitStatus(resp, ' ', true));\n }\n lines.push(...emitStatus(fallback!, ' ', true));\n return lines;\n}\n\n/** Build the lines that construct a TypedDict literal of declared response headers. */\nfunction buildHeadersDictLines(headers: OpResponseHeaderNode[], typeName: string, indent = ' ', varName = 'headers'): string[] {\n const lines: string[] = [];\n lines.push(`${indent}${varName}: ${typeName} = {}`);\n for (const h of headers) {\n const pyName = toPythonFieldName(h.name);\n lines.push(`${indent}if ${JSON.stringify(h.name.toLowerCase())} in _response_headers:`);\n lines.push(`${indent} ${varName}[${JSON.stringify(pyName)}] = _response_headers[${JSON.stringify(h.name.toLowerCase())}]`);\n }\n return lines;\n}\n\n/**\n * Render `text` as indented docstring body lines, neutralizing anything that\n * could terminate the enclosing `\"\"\"` docstring early. `op.name` / descriptions\n * come from user `.ck` source and may contain `\"\"\"` runs or embedded newlines.\n * Each `\"` is escaped to `\\\"` (inside a Python string `\\\"` cannot close a `\"\"\"`),\n * and a trailing backslash is guarded with a space so it can't escape the delimiter.\n */\nfunction docstringLines(text: string, indent: string): string[] {\n return text.split('\\n').map(line => {\n let safe = line.replace(/\"/g, '\\\\\"');\n if (/\\\\$/.test(safe)) safe += ' ';\n return `${indent}${safe}`;\n });\n}\n\n/** snake_case → PascalCase. */\nfunction snakeToPascal(s: string): string {\n return s\n .split('_')\n .filter(Boolean)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n}\n\n// ─── URL building ─────────────────────────────────────────────────────────\n\nfunction buildUrlExpression(path: string): string {\n // Replace {paramName} with Python f-string interpolation\n const hasBraces = /\\{[a-zA-Z_][a-zA-Z0-9_]*\\}/.test(path);\n if (!hasBraces) return `\"${path}\"`;\n const interpolated = path.replace(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g, (_m, name) => `{${name}}`);\n return `f\"${interpolated}\"`;\n}\n\n// ─── Parameter building ───────────────────────────────────────────────────\n\nfunction buildMethodParams(route: OpRouteNode, op: OpOperationNode, modelsWithInput?: Set<string>): MethodParam[] {\n const params: MethodParam[] = [];\n\n // Path params\n if (route.params) {\n if (route.params.kind === 'params') {\n for (const p of route.params.nodes) {\n params.push({\n name: toPythonFieldName(p.name),\n type: renderPyType(p.type, modelsWithInput),\n optional: false,\n isModel: false,\n });\n }\n } else if (route.params.kind === 'ref') {\n const typeName = modelsWithInput?.has(route.params.name) ? `${route.params.name}Input` : route.params.name;\n params.push({ name: 'params', type: typeName, optional: false, isModel: true });\n } else {\n params.push({ name: 'params', type: renderPyType(route.params.node, modelsWithInput), optional: false, isModel: false });\n }\n }\n\n // Body — use the first declared MIME's body type as the parameter type.\n // Multi-MIME support in Python collapses to a single signature using the primary body.\n const primaryBody = op.request?.bodies[0];\n if (primaryBody) {\n const cat = classifyContentType(primaryBody.contentType);\n if (cat === 'multipart' || cat === 'binary') {\n params.push({ name: 'body', type: 'bytes', optional: false, isModel: false });\n } else if (cat === 'text') {\n params.push({ name: 'body', type: 'str', optional: false, isModel: false });\n } else {\n const bodyType = renderInputPyType(primaryBody.bodyType, modelsWithInput);\n const isModel = isModelRef(primaryBody.bodyType, modelsWithInput);\n params.push({ name: 'body', type: bodyType, optional: false, isModel });\n }\n }\n\n // Query\n if (op.query) {\n const queryType = renderParamSourceType(op.query, modelsWithInput, true);\n params.push({ name: 'query', type: queryType, optional: true, isModel: false });\n }\n\n // Headers\n if (op.headers) {\n const headersType = renderParamSourceType(op.headers, modelsWithInput, true);\n params.push({ name: 'custom_headers', type: headersType, optional: true, isModel: false });\n }\n\n return params;\n}\n\nfunction renderParamSourceType(source: ParamSource, modelsWithInput?: Set<string>, forInput = false): string {\n if (source.kind === 'ref') {\n const typeName = forInput && modelsWithInput?.has(source.name) ? `${source.name}Input` : source.name;\n return typeName;\n }\n if (source.kind === 'params') {\n // const fields = source.nodes.map(p => {\n // const pyName = toPythonFieldName(p.name);\n // return `\"${pyName}\": ${renderPyType(p.type, modelsWithInput, forInput)}`;\n // });\n return `dict`; // simplified — inline dicts are hard to type concisely in Python signatures\n }\n return renderPyType(source.node, modelsWithInput, forInput);\n}\n\nfunction renderInputPyType(type: ContractTypeNode, modelsWithInput?: Set<string>): string {\n return renderPyType(type, modelsWithInput, true);\n}\n\n// ─── Model reference detection ────────────────────────────────────────────\n\nfunction isModelRef(type: ContractTypeNode, modelsWithInput?: Set<string>): boolean {\n if (type.kind === 'ref') return /^[A-Z]/.test(type.name);\n if (type.kind === 'lazy') return isModelRef(type.inner, modelsWithInput);\n return false;\n}\n\nfunction isListModelRef(type: ContractTypeNode, modelsWithInput?: Set<string>): boolean {\n if (type.kind === 'array') return isModelRef(type.item, modelsWithInput);\n if (type.kind === 'lazy') return isListModelRef(type.inner, modelsWithInput);\n return false;\n}\n\nfunction getListItemType(type: ContractTypeNode, modelsWithInput?: Set<string>): string {\n if (type.kind === 'array') return renderPyType(type.item, modelsWithInput);\n return 'dict';\n}\n\n// ─── Referenced model collection ─────────────────────────────────────────\n\n/**\n * Collect all model names and scalar sentinels referenced in public operations.\n * Sentinels: __datetime__, __date__, __time__, __uuid__, __any__\n */\nfunction collectReferencedModels(root: OpRootNode, modelsWithInput?: Set<string>, includeInternal = false): Set<string> {\n const refs = new Set<string>();\n\n for (const route of root.routes) {\n for (const op of route.operations) {\n if (!includeInternal && resolveModifiers(route, op).includes('internal')) continue;\n\n if (route.params) collectParamSourceRefs(route.params, refs, modelsWithInput);\n if (op.request) {\n for (const body of op.request.bodies) collectTypeRefs(body.bodyType, refs, modelsWithInput, true);\n }\n for (const resp of op.responses) {\n for (const body of resp.bodies) collectTypeRefs(body.bodyType, refs, modelsWithInput, false);\n }\n if (op.query) collectParamSourceRefs(op.query, refs, modelsWithInput);\n if (op.headers) collectParamSourceRefs(op.headers, refs, modelsWithInput);\n }\n }\n\n return refs;\n}\n\nfunction collectParamSourceRefs(source: ParamSource, out: Set<string>, modelsWithInput?: Set<string>): void {\n if (source.kind === 'ref') {\n addModelRef(source.name, out, modelsWithInput);\n } else if (source.kind === 'params') {\n for (const p of source.nodes) collectTypeRefs(p.type, out, modelsWithInput);\n } else {\n collectTypeRefs(source.node, out, modelsWithInput);\n }\n}\n\nfunction addModelRef(name: string, out: Set<string>, modelsWithInput?: Set<string>): void {\n if (/^[A-Z]/.test(name)) {\n out.add(name);\n if (modelsWithInput?.has(name)) out.add(`${name}Input`);\n }\n}\n\nfunction collectTypeRefs(type: ContractTypeNode, out: Set<string>, modelsWithInput?: Set<string>, forInput = false): void {\n switch (type.kind) {\n case 'scalar':\n switch (type.name) {\n case 'date':\n out.add('__date__');\n break;\n case 'time':\n out.add('__time__');\n break;\n case 'datetime':\n out.add('__datetime__');\n break;\n case 'uuid':\n out.add('__uuid__');\n break;\n case 'unknown':\n case 'json':\n case 'object':\n out.add('__any__');\n break;\n }\n break;\n case 'ref':\n if (forInput && modelsWithInput?.has(type.name)) {\n out.add(`${type.name}Input`);\n } else {\n addModelRef(type.name, out, modelsWithInput);\n }\n break;\n case 'array':\n collectTypeRefs(type.item, out, modelsWithInput, forInput);\n break;\n case 'tuple':\n type.items.forEach(t => collectTypeRefs(t, out, modelsWithInput, forInput));\n break;\n case 'record':\n collectTypeRefs(type.key, out, modelsWithInput, forInput);\n collectTypeRefs(type.value, out, modelsWithInput, forInput);\n break;\n case 'union':\n type.members.forEach(m => collectTypeRefs(m, out, modelsWithInput, forInput));\n break;\n case 'discriminatedUnion':\n type.members.forEach(m => collectTypeRefs(m, out, modelsWithInput, forInput));\n break;\n case 'intersection':\n out.add('__any__');\n break;\n case 'lazy':\n collectTypeRefs(type.inner, out, modelsWithInput, forInput);\n break;\n case 'inlineObject':\n out.add('__any__');\n break;\n }\n}\n\n// ─── Naming helpers ───────────────────────────────────────────────────────\n\nfunction deriveBaseName(file: string): string {\n const base =\n file\n .split('/')\n .pop()\n ?.replace(/\\.(op\\.)?ck$/, '') ?? 'Resource';\n return base\n .split('.')\n .map(s => s.charAt(0).toUpperCase() + s.slice(1))\n .join('');\n}\n\nexport function deriveClientClassName(file: string): string {\n return `${deriveBaseName(file)}Client`;\n}\n\nexport function deriveClientModuleName(file: string): string {\n const base =\n file\n .split('/')\n .pop()\n ?.replace(/\\.(op\\.)?ck$/, '') ?? 'client';\n const clean = base.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase();\n return `_client_${clean}`;\n}\n\nexport function deriveClientPropertyName(file: string): string {\n const base = deriveBaseName(file);\n return base.charAt(0).toLowerCase() + base.slice(1);\n}\n\nfunction deriveMethodName(op: OpOperationNode, route: OpRouteNode): string {\n if (op.sdk) return toSnakeCase(op.sdk);\n if (op.name) return toSnakeCase(op.name);\n return inferMethodName(op.method, route.path);\n}\n\nfunction inferMethodName(method: string, path: string): string {\n const segments = path.split('/').filter(s => s.length > 0);\n const parts: string[] = [method.toLowerCase()];\n\n for (const seg of segments) {\n if (seg.startsWith('{')) {\n const paramName = seg.slice(1, -1);\n parts.push('by_' + toSnakeCase(paramName));\n } else {\n parts.push(toSnakeCase(seg.replace(/[.-]/g, '_')));\n }\n }\n\n return parts.join('_').replace(/_+/g, '_');\n}\n\nfunction toSnakeCase(s: string): string {\n return s\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[^a-zA-Z0-9]/g, '_')\n .toLowerCase()\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n}\n\n// ─── Shared base client content ───────────────────────────────────────────\n\nexport const BASE_CLIENT_PY = `# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.\nfrom __future__ import annotations\n\nimport httpx\nfrom typing import Any\n\n\nclass SdkError(Exception):\n def __init__(self, status: int, status_text: str, body: Any):\n super().__init__(f\"{status} {status_text}\")\n self.status = status\n self.status_text = status_text\n self.body = body\n\n\nclass BaseClient:\n def __init__(self, base_url: str, headers: dict[str, str] | None = None):\n self._base_url = base_url.rstrip(\"/\")\n self._headers = headers or {}\n self._http = httpx.AsyncClient()\n self._last_status = 0\n self._last_content_type = \"\"\n\n async def _fetch(\n self,\n path: str,\n *,\n method: str,\n body: Any = None,\n params: dict | None = None,\n extra_headers: dict | None = None,\n content_type: str | None = None,\n body_kind: str = \"json\",\n response_kind: str = \"json\",\n expect_statuses: tuple[int, ...] = (),\n ) -> Any:\n result, _ = await self._fetch_with_headers(\n path,\n method=method,\n body=body,\n params=params,\n extra_headers=extra_headers,\n content_type=content_type,\n body_kind=body_kind,\n response_kind=response_kind,\n expect_statuses=expect_statuses,\n )\n return result\n\n async def _fetch_full(\n self,\n path: str,\n *,\n method: str,\n body: Any = None,\n params: dict | None = None,\n extra_headers: dict | None = None,\n content_type: str | None = None,\n body_kind: str = \"json\",\n response_kind: str = \"json\",\n expect_statuses: tuple[int, ...] = (),\n ) -> tuple[int, str, Any, dict[str, str]]:\n \"\"\"Like _fetch_with_headers, but also reports the status and content type.\n\n Used by operations that declare more than one status, or more than one mime for a\n status, where the caller cannot know which it got without being told.\n \"\"\"\n result, headers = await self._fetch_with_headers(\n path,\n method=method,\n body=body,\n params=params,\n extra_headers=extra_headers,\n content_type=content_type,\n body_kind=body_kind,\n response_kind=response_kind,\n expect_statuses=expect_statuses,\n )\n return self._last_status, self._last_content_type, result, headers\n\n async def _fetch_with_headers(\n self,\n path: str,\n *,\n method: str,\n body: Any = None,\n params: dict | None = None,\n extra_headers: dict | None = None,\n content_type: str | None = None,\n body_kind: str = \"json\",\n response_kind: str = \"json\",\n expect_statuses: tuple[int, ...] = (),\n ) -> tuple[Any, dict[str, str]]:\n headers = {**self._headers, **(extra_headers or {})}\n if body is not None:\n headers[\"Content-Type\"] = content_type or \"application/json\"\n # body_kind controls how httpx serializes the request body:\n # \"json\" — body is a JSON-serializable object, sent via httpx's json= kwarg\n # \"text\"/\"binary\" — body is a raw str/bytes payload, sent via content= unchanged\n request_kwargs: dict[str, Any] = {\"method\": method, \"url\": f\"{self._base_url}{path}\", \"params\": params, \"headers\": headers}\n if body is not None:\n if body_kind == \"json\":\n request_kwargs[\"json\"] = body\n else:\n request_kwargs[\"content\"] = body\n response = await self._http.request(**request_kwargs)\n # expect_statuses carries the codes this operation declares as values rather than\n # errors — a 304 from conditional-GET middleware, or an error status the service\n # returns deliberately. Anything else outside 2xx still raises.\n if not response.is_success and response.status_code not in expect_statuses:\n try:\n error_body = response.json()\n except Exception:\n error_body = response.text\n raise SdkError(response.status_code, response.reason_phrase, error_body)\n # HTTP headers are case-insensitive — normalize to lowercase keys for stable lookup.\n response_headers = {k.lower(): v for k, v in response.headers.items()}\n self._last_status = response.status_code\n self._last_content_type = response.headers.get(\"content-type\", \"\").split(\";\")[0].strip()\n if response.status_code == 204 or not response.content:\n return None, response_headers\n # \"auto\" is for a status declaring several mimes that do not read the same way: the\n # response itself is the only thing that knows which one came back.\n kind = response_kind\n if kind == \"auto\":\n ct = self._last_content_type\n if ct.startswith(\"text/\"):\n kind = \"text\"\n elif ct == \"application/json\" or ct.endswith(\"+json\"):\n kind = \"json\"\n else:\n kind = \"binary\"\n if kind == \"text\":\n return response.text, response_headers\n if kind == \"binary\":\n return response.content, response_headers\n return response.json(), response_headers\n`;\n"],"mappings":"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","names":["resolve","join","relative","dirname","existsSync","readFileSync","writeFileSync","mkdirSync","rmSync","readdirSync","rmdirSync","runIncrementalCodegen","parseIncrementalManifest","emptyIncrementalManifest","serializeIncrementalManifest","hashFingerprint","collectTransitiveModelRefs","collectTypeRefs","computeModelsWithInput","topoSortModels","collectExternalRefs","collectExternalInputRefs","generatePydanticModels","root","opts","externalRefs","collectExternalRefs","externalModelsWithInput","modelsWithInput","Set","localModelsWithInput","computeModelsWithInput","models","allModelsWithInput","externalInputRefs","size","collectExternalInputRefs","allExternalRefs","sort","imports","ImportTracker","add","model","type","scanTypeImports","f","fields","lines","push","crossFileImports","ref","modulePath","modelModulePaths","get","currentModule","modelLines","topoSortModels","generateModel","stdlibLines","render","length","join","groups","Map","module","name","s","set","has","ORDER","mod","names","sorted","includes","kind","members","forEach","m","item","items","t","key","value","inner","renderPyType","forInput","renderScalar","values","map","v","JSON","stringify","String","discriminator","_exhaustive","Error","toPythonFieldName","result","replace","toLowerCase","test","commentLines","text","indent","split","line","generateTypeAlias","needsInputSplit","some","visibility","generateSplitModel","generateSimpleModel","_","description","deprecated","baseList","bases","fieldLines","renderFields","needsConfig","readFields","filter","readBaseList","readNeedsConfig","readFieldLines","writeFields","inputBaseList","b","writeNeedsConfig","writeFieldLines","renderField","field","pyName","needsAlias","typeStr","nullable","isOptional","optional","default","undefined","fieldAnnotations","def","rhs","optSuffix","fullType","deriveModelsModuleName","file","base","pop","clean","resolveModifiers","classifyContentType","observableResponses","headersClassName","methodBase","statusCode","undefined","responseClassName","pyBodyType","body","modelsWithInput","category","classifyContentType","contentType","renderPyType","bodyType","pyDataAnnotation","bodies","types","Set","map","b","join","pyContentTypeAnnotation","JSON","stringify","responseShape","op","observable","observableResponses","length","kind","responses","resp","hasPublicOperations","root","includeInternal","route","routes","operations","resolveModifiers","includes","generatePythonClient","opts","clientClassName","deriveClientClassName","file","referencedModels","collectReferencedModels","lines","push","needsDatetime","has","needsDate","needsTime","needsUUID","needsAny","dtParts","publicOps","opShapes","Map","opsWithRespHeaders","filter","shape","get","some","r","headers","opsWithResponseDict","needsTypedDict","needsLiteral","typingImports","modelImportsByModule","name","startsWith","modulePath","modelModulePaths","s","set","add","mod","names","sort","a","localeCompare","sorted","base","snakeToPascal","deriveMethodName","targets","h","pyName","toPythonFieldName","tag","optional","hasAnyMethod","mods","generateMethod","methodName","httpMethod","method","toUpperCase","params","buildMethodParams","selfParam","allParams","p","type","paramStr","primaryResponse","primaryBodies","isVoid","respCategory","dataType","isModelReturn","isModelRef","isListModelReturn","isListModelRef","respHeaders","hasRespHeaders","headersTypeName","returnType","desc","description","docstringLines","urlExpr","buildUrlExpression","path","hasQuery","query","primaryBody","request","hasBody","isMultipart","hasCustomHeaders","fetchKwargs","reqCategory","bodyParam","find","isModel","expectStatuses","tuple","kwargsStr","buildMultiReturnLines","buildHeadersDictLines","dataExpr","innerType","getListItemType","pyDataExpr","returnFor","indent","includeStatus","headersVar","entries","emitStatus","out","typeName","slice","fallback","rest","varName","toLowerCase","text","split","line","safe","replace","test","Boolean","charAt","hasBraces","interpolated","_m","nodes","node","cat","renderInputPyType","queryType","renderParamSourceType","headersType","source","forInput","inner","item","refs","collectParamSourceRefs","collectTypeRefs","addModelRef","items","forEach","t","key","value","members","m","deriveBaseName","pop","deriveClientModuleName","clean","deriveClientPropertyName","sdk","toSnakeCase","inferMethodName","segments","parts","seg","paramName","BASE_CLIENT_PY","PYTHON_CODEGEN_VERSION","CACHE_MANIFEST_FILENAME","plugin","name","generateTargets","inputs","ctx","config","options","runPythonCodegen","rootDir","createPythonSdkPlugin","contractRoots","opRoots","modelsWithInput","outDir","resolve","baseDir","manifestPath","cacheDir","modelModulePaths","Map","modelMap","contractEntries","root","moduleName","deriveModelsModuleName","file","push","relPath","model","models","set","has","modelsWithInputArray","sort","prevManifest","cacheEnabled","readManifest","emptyIncrementalManifest","units","ownNames","Set","map","m","externalRefs","collectExternalRefsFromContract","referencedModulePaths","ref","path","get","inputPath","relevantInputModels","filter","fingerprint","hashFingerprint","kind","v","currentModule","key","render","relativePath","content","generatePydanticModels","clientInfos","hasPublicOperations","includeInternal","deriveClientModuleName","className","deriveClientClassName","propertyName","deriveClientPropertyName","referencedModels","collectOpRootModelRefs","generatePythonClient","sdkClassName","packageName","split","s","charAt","toUpperCase","slice","join","initLines","c","length","allNames","n","JSON","stringify","globalFiles","BASE_CLIENT_PY","result","runIncrementalCodegen","codegenVersion","fileExists","existsSync","deleteStalePaths","deletedPaths","filesToWrite","emitFile","writeManifest","manifest","relative","refs","type","collectTypeRefs","f","fields","bases","b","add","own","delete","seeds","route","routes","params","paramSourceTypes","op","operations","query","headers","request","body","bodies","bodyType","resp","responses","h","collectTransitiveModelRefs","src","out","nodes","node","parseIncrementalManifest","readFileSync","mkdirSync","dirname","recursive","writeFileSync","serializeIncrementalManifest","relPaths","removedDirs","rel","abs","rmSync","force","dir","current","startsWith","readdirSync","rmdirSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/codegen-models.ts","../src/codegen-client.ts"],"sourcesContent":["import { resolve, join, relative, dirname } from 'node:path';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, rmdirSync } from 'node:fs';\nimport type {\n ContractKitPlugin,\n PluginContext,\n ContractRootNode,\n OpRootNode,\n ModelNode,\n IncrementalManifest,\n IncrementalUnit,\n} from '@contractkit/core';\nimport {\n runIncrementalCodegen,\n parseIncrementalManifest,\n emptyIncrementalManifest,\n serializeIncrementalManifest,\n hashFingerprint,\n collectTransitiveModelRefs,\n collectTypeRefs,\n} from '@contractkit/core';\nimport { generatePydanticModels, deriveModelsModuleName } from './codegen-models.js';\nimport {\n generatePythonClient,\n deriveClientClassName,\n deriveClientModuleName,\n deriveClientPropertyName,\n hasPublicOperations,\n BASE_CLIENT_PY,\n} from './codegen-client.js';\n\nexport interface PythonSdkPluginConfig {\n /** Output directory relative to rootDir (default: \"python-sdk\") */\n baseDir?: string;\n /** Python package name used in the aggregator class name (default: \"Sdk\") */\n packageName?: string;\n /**\n * Whether to emit client methods for operations marked `internal`. Defaults to `false` —\n * internal ops are omitted so consumers don't pick them up. Set to `true` for an\n * internal-use SDK that should expose them.\n */\n includeInternal?: boolean;\n}\n\n/**\n * Bumped when the Python codegen output shape changes in a way that should\n * invalidate every per-file fingerprint. Mixed into the manifest's\n * `codegenVersion`, so a plugin upgrade forces full regeneration even when no\n * `.ck` files have changed.\n */\nexport const PYTHON_CODEGEN_VERSION = '1';\n\n/** Filename for the persisted Python manifest under the CLI cache directory. */\nconst CACHE_MANIFEST_FILENAME = 'python-manifest.json';\n\nconst plugin: ContractKitPlugin = {\n name: 'python-sdk',\n async generateTargets(inputs, ctx) {\n const config = ctx.options as PythonSdkPluginConfig;\n await runPythonCodegen(inputs, ctx, config, ctx.rootDir);\n },\n};\n\nexport default plugin;\n\nexport function createPythonSdkPlugin(config: PythonSdkPluginConfig, rootDir: string): ContractKitPlugin {\n return {\n name: 'python-sdk',\n async generateTargets(inputs, ctx) {\n await runPythonCodegen(inputs, ctx, config, rootDir);\n },\n };\n}\n\n/**\n * Shared orchestration. Builds per-file fingerprints, reuses unchanged outputs from\n * the manifest, regenerates only the affected client/model files, and rewrites the\n * shared aggregator + base files (cheap, depend only on the set of public clients).\n *\n * Honors `ctx.cacheEnabled` so `--force` bypasses the per-file cache.\n */\nasync function runPythonCodegen(\n inputs: Parameters<NonNullable<ContractKitPlugin['generateTargets']>>[0],\n ctx: PluginContext,\n config: PythonSdkPluginConfig,\n rootDir: string,\n): Promise<void> {\n const { contractRoots, opRoots } = inputs;\n const modelsWithInput = inputs.modelsWithInput as Set<string>;\n const outDir = resolve(rootDir, config.baseDir ?? 'python-sdk');\n const manifestPath = resolve(ctx.cacheDir, CACHE_MANIFEST_FILENAME);\n\n // ── Build cross-file lookup tables ───────────────────────────────────────\n const modelModulePaths = new Map<string, string>();\n const modelMap = new Map<string, ModelNode>();\n const contractEntries: { moduleName: string; relPath: string; root: ContractRootNode }[] = [];\n\n for (const root of contractRoots) {\n const moduleName = deriveModelsModuleName(root.file);\n contractEntries.push({ moduleName, relPath: `${moduleName}.py`, root });\n for (const model of root.models) {\n modelMap.set(model.name, model);\n modelModulePaths.set(model.name, `.${moduleName}`);\n if (modelsWithInput.has(model.name)) {\n modelModulePaths.set(`${model.name}Input`, `.${moduleName}`);\n }\n }\n }\n\n // Stable, sorted view of modelsWithInput for fingerprint slicing — only the\n // intersection with each unit's referenced names ends up in its fingerprint.\n const modelsWithInputArray = [...modelsWithInput].sort();\n\n const prevManifest: IncrementalManifest = ctx.cacheEnabled ? readManifest(manifestPath) : emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);\n const units: IncrementalUnit[] = [];\n\n // ── Per-contract-root model files ────────────────────────────────────────\n for (const { moduleName, relPath, root } of contractEntries) {\n const ownNames = new Set(root.models.map(m => m.name));\n const externalRefs = collectExternalRefsFromContract(root, ownNames);\n // Module paths that this file actually imports — excludes self-refs and any\n // cross-file refs not used by this file's models.\n const referencedModulePaths: Record<string, string> = {};\n for (const ref of [...externalRefs].sort()) {\n const path = modelModulePaths.get(ref);\n if (path) referencedModulePaths[ref] = path;\n const inputPath = modelModulePaths.get(`${ref}Input`);\n if (inputPath) referencedModulePaths[`${ref}Input`] = inputPath;\n }\n const relevantInputModels = modelsWithInputArray.filter(name => ownNames.has(name) || externalRefs.has(name));\n\n const fingerprint = hashFingerprint({\n kind: 'models',\n v: PYTHON_CODEGEN_VERSION,\n relPath,\n currentModule: `.${moduleName}`,\n root,\n referencedModulePaths,\n modelsWithInput: relevantInputModels,\n });\n\n units.push({\n key: `models::${relPath}`,\n fingerprint,\n render: () => [\n {\n relativePath: relPath,\n content: generatePydanticModels(root, {\n modelModulePaths,\n currentModule: `.${moduleName}`,\n modelsWithInput,\n }),\n },\n ],\n });\n }\n\n // ── Per-op-root client files ─────────────────────────────────────────────\n const clientInfos: { moduleName: string; className: string; propertyName: string }[] = [];\n\n for (const root of opRoots) {\n if (!hasPublicOperations(root, config.includeInternal)) continue;\n const moduleName = deriveClientModuleName(root.file);\n const relPath = `${moduleName}.py`;\n clientInfos.push({\n moduleName,\n className: deriveClientClassName(root.file),\n propertyName: deriveClientPropertyName(root.file),\n });\n\n const referencedModels = collectOpRootModelRefs(root, modelMap);\n const referencedModulePaths: Record<string, string> = {};\n for (const ref of [...referencedModels].sort()) {\n const path = modelModulePaths.get(ref);\n if (path) referencedModulePaths[ref] = path;\n const inputPath = modelModulePaths.get(`${ref}Input`);\n if (inputPath) referencedModulePaths[`${ref}Input`] = inputPath;\n }\n const relevantInputModels = modelsWithInputArray.filter(name => referencedModels.has(name));\n\n const fingerprint = hashFingerprint({\n kind: 'client',\n v: PYTHON_CODEGEN_VERSION,\n relPath,\n currentModule: `.${moduleName}`,\n root,\n referencedModulePaths,\n modelsWithInput: relevantInputModels,\n includeInternal: config.includeInternal ?? false,\n });\n\n units.push({\n key: `client::${relPath}`,\n fingerprint,\n render: () => [\n {\n relativePath: relPath,\n content: generatePythonClient(root, {\n modelModulePaths,\n currentModule: `.${moduleName}`,\n modelsWithInput,\n includeInternal: config.includeInternal,\n }),\n },\n ],\n });\n }\n\n // ── Global files: base client, requirements, aggregator ──────────────────\n // The aggregator (__init__.py) depends on the public-clients list. Writing it\n // every run is cheap (a few imports + a class body), so we skip a separate\n // unit for it. base_client.py and requirements.txt are constants.\n const sdkClassName = config.packageName\n ? config.packageName\n .split(/[-._\\s]+/)\n .map(s => s.charAt(0).toUpperCase() + s.slice(1))\n .join('') + 'Sdk'\n : 'Sdk';\n\n const initLines: string[] = [\n '# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.',\n 'from ._base_client import BaseClient, SdkError',\n ];\n for (const c of clientInfos) {\n initLines.push(`from .${c.moduleName} import ${c.className}`);\n }\n initLines.push('');\n initLines.push('');\n if (clientInfos.length > 0) {\n initLines.push(`class ${sdkClassName}(BaseClient):`);\n initLines.push(` def __init__(self, base_url: str, headers: dict[str, str] | None = None):`);\n initLines.push(` super().__init__(base_url, headers)`);\n for (const c of clientInfos) {\n initLines.push(` self.${c.propertyName} = ${c.className}(base_url, headers)`);\n }\n initLines.push('');\n } else {\n initLines.push(`class ${sdkClassName}(BaseClient):`);\n initLines.push(` pass`);\n initLines.push('');\n }\n const allNames = ['BaseClient', 'SdkError', sdkClassName, ...clientInfos.map(c => c.className)];\n initLines.push(`__all__ = [${allNames.map(n => JSON.stringify(n)).join(', ')}]`);\n initLines.push('');\n\n const globalFiles = [\n { relativePath: '_base_client.py', content: BASE_CLIENT_PY },\n { relativePath: 'requirements.txt', content: 'httpx\\npydantic>=2.0\\n' },\n { relativePath: '__init__.py', content: initLines.join('\\n') },\n ];\n\n const result = runIncrementalCodegen({\n codegenVersion: PYTHON_CODEGEN_VERSION,\n prevManifest,\n globalFiles,\n units,\n fileExists: relPath => existsSync(resolve(outDir, relPath)),\n });\n\n deleteStalePaths(outDir, result.deletedPaths);\n\n for (const { relativePath, content } of result.filesToWrite) {\n ctx.emitFile(resolve(outDir, relativePath), content);\n }\n\n writeManifest(manifestPath, result.manifest);\n // Suppress unused import warning — `relative` is reserved for future use.\n void relative;\n}\n\n/** Collect every model name referenced by the contract root that isn't defined within it. */\nfunction collectExternalRefsFromContract(root: ContractRootNode, ownNames: Set<string>): Set<string> {\n const refs = new Set<string>();\n for (const m of root.models) {\n if (m.type) collectTypeRefs(m.type, refs);\n for (const f of m.fields) collectTypeRefs(f.type, refs);\n if (m.bases) {\n for (const b of m.bases) refs.add(b);\n }\n }\n for (const own of ownNames) refs.delete(own);\n return refs;\n}\n\n/** Collect every model name referenced (transitively) by an op root. */\nfunction collectOpRootModelRefs(root: OpRootNode, modelMap: Map<string, ModelNode>): Set<string> {\n const seeds = [];\n for (const route of root.routes) {\n if (route.params) seeds.push(...paramSourceTypes(route.params));\n for (const op of route.operations) {\n if (op.query) seeds.push(...paramSourceTypes(op.query));\n if (op.headers) seeds.push(...paramSourceTypes(op.headers));\n if (op.request) {\n for (const body of op.request.bodies) seeds.push(body.bodyType);\n }\n for (const resp of op.responses) {\n for (const body of resp.bodies) seeds.push(body.bodyType);\n if (resp.headers) {\n for (const h of resp.headers) seeds.push(h.type);\n }\n }\n }\n }\n return collectTransitiveModelRefs(seeds, modelMap);\n}\n\nfunction paramSourceTypes(src: NonNullable<OpRootNode['routes'][number]['params']>): Parameters<typeof collectTypeRefs>[0][] {\n const out: Parameters<typeof collectTypeRefs>[0][] = [];\n if (src.kind === 'params') {\n for (const n of src.nodes) out.push(n.type);\n } else if (src.kind === 'ref') {\n out.push({ kind: 'ref', name: src.name } as Parameters<typeof collectTypeRefs>[0]);\n } else if (src.kind === 'type') {\n out.push(src.node);\n }\n return out;\n}\n\n/** Read the previous run's manifest from `manifestPath`. Returns an empty manifest when missing or unreadable. */\nfunction readManifest(manifestPath: string): IncrementalManifest {\n if (!existsSync(manifestPath)) return emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);\n try {\n return parseIncrementalManifest(readFileSync(manifestPath, 'utf-8'));\n } catch {\n return emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);\n }\n}\n\n/** Write the manifest to `manifestPath`. Creates parent dirs as needed. Errors are swallowed so a broken cache never blocks the build. */\nfunction writeManifest(manifestPath: string, manifest: IncrementalManifest): void {\n try {\n mkdirSync(dirname(manifestPath), { recursive: true });\n writeFileSync(manifestPath, serializeIncrementalManifest(manifest), 'utf-8');\n } catch {\n // best-effort\n }\n}\n\n/** Delete paths from the prior manifest that aren't produced this run. Mirrors the Bruno cleanup approach. */\nfunction deleteStalePaths(outDir: string, relPaths: string[]): void {\n if (relPaths.length === 0) return;\n const removedDirs = new Set<string>();\n for (const rel of relPaths) {\n const abs = resolve(outDir, rel);\n if (existsSync(abs)) {\n rmSync(abs, { force: true });\n removedDirs.add(join(abs, '..'));\n }\n }\n for (const dir of removedDirs) {\n let current = dir;\n while (current.startsWith(outDir) && current !== outDir) {\n try {\n if (readdirSync(current).length === 0) {\n rmdirSync(current);\n current = join(current, '..');\n } else {\n break;\n }\n } catch {\n break;\n }\n }\n }\n}\n","import type { ContractRootNode, ModelNode, FieldNode, ContractTypeNode, ScalarTypeNode } from '@contractkit/core';\nimport { computeModelsWithInput, topoSortModels, collectExternalRefs, collectExternalInputRefs } from '@contractkit/core';\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\nexport interface ModelCodegenOptions {\n /** Map from model name → output module name (for cross-file imports) */\n modelModulePaths?: Map<string, string>;\n /** Current output module name (used to skip self-imports) */\n currentModule?: string;\n /** Set of model names that have Input variants (cross-file) */\n modelsWithInput?: Set<string>;\n}\n\n/**\n * Generate Pydantic v2 model classes from a ContractRootNode.\n */\nexport function generatePydanticModels(root: ContractRootNode, opts: ModelCodegenOptions = {}): string {\n const externalRefs = collectExternalRefs(root);\n const externalModelsWithInput = opts.modelsWithInput ?? new Set<string>();\n const localModelsWithInput = computeModelsWithInput(root.models, externalModelsWithInput);\n const allModelsWithInput = new Set([...localModelsWithInput, ...externalModelsWithInput]);\n\n const externalInputRefs = allModelsWithInput.size > 0 ? collectExternalInputRefs(root, allModelsWithInput) : [];\n const allExternalRefs = [...new Set([...externalRefs, ...externalInputRefs])].sort();\n\n // Track needed imports\n const imports = new ImportTracker();\n imports.add('pydantic', 'BaseModel');\n\n // Pre-scan all models to determine what imports will be needed\n for (const model of root.models) {\n if (model.type) {\n scanTypeImports(model.type, imports);\n } else {\n for (const f of model.fields) {\n scanTypeImports(f.type, imports);\n }\n }\n }\n\n const lines: string[] = [];\n lines.push('# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.');\n lines.push('from __future__ import annotations');\n\n // Cross-file imports for external model refs\n const crossFileImports: string[] = [];\n for (const ref of allExternalRefs) {\n const modulePath = opts.modelModulePaths?.get(ref);\n if (modulePath && modulePath !== opts.currentModule) {\n crossFileImports.push(`from ${modulePath} import ${ref}`);\n }\n }\n\n // We'll prepend stdlib/typing imports after, once we know what's needed\n // Build model output first\n const modelLines: string[] = [];\n for (const model of topoSortModels(root.models)) {\n modelLines.push('');\n modelLines.push(...generateModel(model, allModelsWithInput, imports));\n }\n\n // Now emit stdlib imports\n const stdlibLines = imports.render();\n lines.push(...stdlibLines);\n if (crossFileImports.length > 0) {\n lines.push('');\n lines.push(...crossFileImports);\n }\n lines.push(...modelLines);\n lines.push('');\n\n return lines.join('\\n');\n}\n\n// ─── Import tracking ──────────────────────────────────────────────────────\n\nclass ImportTracker {\n private groups: Map<string, Set<string>> = new Map();\n\n add(module: string, name: string): void {\n let s = this.groups.get(module);\n if (!s) {\n s = new Set();\n this.groups.set(module, s);\n }\n s.add(name);\n }\n\n has(module: string, name: string): boolean {\n return this.groups.get(module)?.has(name) ?? false;\n }\n\n render(): string[] {\n // Order: stdlib → typing → pydantic\n const ORDER = ['__future__', 'datetime', 'uuid', 'typing', 'pydantic'];\n const lines: string[] = [];\n lines.push('');\n for (const mod of ORDER) {\n const names = this.groups.get(mod);\n if (!names || names.size === 0) continue;\n const sorted = [...names].sort().join(', ');\n lines.push(`from ${mod} import ${sorted}`);\n }\n // Any remaining\n for (const [mod, names] of this.groups) {\n if (ORDER.includes(mod)) continue;\n const sorted = [...names].sort().join(', ');\n lines.push(`from ${mod} import ${sorted}`);\n }\n return lines;\n }\n}\n\nfunction scanTypeImports(type: ContractTypeNode, imports: ImportTracker): void {\n switch (type.kind) {\n case 'scalar':\n switch (type.name) {\n case 'date':\n imports.add('datetime', 'date');\n break;\n case 'time':\n imports.add('datetime', 'time');\n break;\n case 'datetime':\n imports.add('datetime', 'datetime');\n break;\n case 'duration':\n imports.add('datetime', 'timedelta');\n break;\n case 'decimal':\n imports.add('decimal', 'Decimal');\n break;\n case 'uuid':\n imports.add('uuid', 'UUID');\n break;\n case 'unknown':\n case 'json':\n case 'object':\n imports.add('typing', 'Any');\n break;\n }\n break;\n case 'enum':\n imports.add('typing', 'Literal');\n break;\n case 'union':\n type.members.forEach(m => scanTypeImports(m, imports));\n break;\n case 'discriminatedUnion':\n imports.add('typing', 'Annotated');\n imports.add('pydantic', 'Field');\n type.members.forEach(m => scanTypeImports(m, imports));\n break;\n case 'intersection':\n imports.add('typing', 'Any');\n break;\n case 'array':\n scanTypeImports(type.item, imports);\n break;\n case 'tuple':\n type.items.forEach(t => scanTypeImports(t, imports));\n break;\n case 'record':\n scanTypeImports(type.key, imports);\n scanTypeImports(type.value, imports);\n break;\n case 'lazy':\n scanTypeImports(type.inner, imports);\n break;\n case 'inlineObject':\n imports.add('typing', 'Any');\n break;\n }\n}\n\n// ─── Type rendering ───────────────────────────────────────────────────────\n\n/**\n * Render a ContractKit type node as its Python type annotation (Pydantic v2 conventions).\n *\n * @param modelsWithInput - Model names that have a distinct `Input` variant; a `ref` to one of\n * these renders as `<Name>Input` when `forInput` is set.\n * @param forInput - When true, request-side refs use their `Input` variant.\n * @throws {Error} Via the scalar renderer, if a scalar name has no Python mapping (guards against\n * a scalar being added to core without updating this plugin).\n */\nexport function renderPyType(type: ContractTypeNode, modelsWithInput?: Set<string>, forInput = false): string {\n switch (type.kind) {\n case 'scalar':\n return renderScalar(type.name);\n case 'enum':\n return `Literal[${type.values.map(v => JSON.stringify(v)).join(', ')}]`;\n case 'literal':\n return typeof type.value === 'string' ? JSON.stringify(type.value) : String(type.value);\n case 'array':\n return `list[${renderPyType(type.item, modelsWithInput, forInput)}]`;\n case 'tuple':\n if (type.items.length === 0) return 'tuple[()]';\n return `tuple[${type.items.map(t => renderPyType(t, modelsWithInput, forInput)).join(', ')}]`;\n case 'record':\n return `dict[${renderPyType(type.key, modelsWithInput, forInput)}, ${renderPyType(type.value, modelsWithInput, forInput)}]`;\n case 'union':\n return type.members.map(m => renderPyType(m, modelsWithInput, forInput)).join(' | ');\n case 'discriminatedUnion': {\n const inner = type.members.map(m => renderPyType(m, modelsWithInput, forInput)).join(' | ');\n return `Annotated[${inner}, Field(discriminator=${JSON.stringify(type.discriminator)})]`;\n }\n case 'intersection':\n return 'dict[str, Any]';\n case 'ref': {\n if (forInput && modelsWithInput?.has(type.name)) {\n return `${type.name}Input`;\n }\n return type.name;\n }\n case 'inlineObject':\n return 'dict[str, Any]';\n case 'lazy':\n return renderPyType(type.inner, modelsWithInput, forInput);\n }\n}\n\nfunction renderScalar(name: ScalarTypeNode['name']): string {\n switch (name) {\n case 'string':\n case 'email':\n case 'url':\n return 'str';\n case 'number':\n return 'float';\n case 'int':\n return 'int';\n case 'bigint':\n return 'int';\n case 'decimal':\n return 'Decimal';\n case 'boolean':\n return 'bool';\n case 'date':\n return 'date';\n case 'time':\n return 'time';\n case 'datetime':\n return 'datetime';\n case 'duration':\n return 'timedelta';\n case 'interval':\n return 'str';\n case 'uuid':\n return 'UUID';\n case 'null':\n return 'None';\n case 'binary':\n return 'bytes';\n case 'unknown':\n case 'json':\n case 'object':\n return 'Any';\n default: {\n const _exhaustive: never = name;\n throw new Error(`plugin-python: unmapped scalar '${String(_exhaustive)}' — add a case`);\n }\n }\n}\n\n// ─── Field name conversion ────────────────────────────────────────────────\n\n/** Convert a field name to a valid Python identifier in snake_case. */\nexport function toPythonFieldName(name: string): string {\n // Replace hyphens and non-alphanumeric chars (except underscore) with underscore\n let result = name.replace(/[^a-zA-Z0-9_]/g, '_');\n // camelCase → snake_case\n result = result.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();\n // Collapse multiple underscores\n result = result.replace(/_+/g, '_').replace(/^_|_$/g, '');\n // Prefix if starts with digit\n if (/^\\d/.test(result)) result = 'f_' + result;\n return result;\n}\n\n// ─── Comment emission ─────────────────────────────────────────────────────\n\n/**\n * Render `text` as one `#`-prefixed Python comment line per source line.\n * Descriptions come from `#` doc comments and may contain embedded newlines;\n * emitting them verbatim would leave every line after the first uncommented\n * (a SyntaxError in the generated module). `indent` is the whitespace prefix\n * that precedes `# ` at the call site.\n */\nfunction commentLines(text: string, indent: string): string[] {\n return text.split('\\n').map(line => `${indent}# ${line}`);\n}\n\n// ─── Model generation ─────────────────────────────────────────────────────\n\nfunction generateModel(model: ModelNode, allModelsWithInput: Set<string>, imports: ImportTracker): string[] {\n if (model.type) {\n return generateTypeAlias(model, allModelsWithInput, imports);\n }\n\n const needsInputSplit = model.fields.some(f => f.visibility !== 'normal') || allModelsWithInput.has(model.name);\n\n if (needsInputSplit) {\n return generateSplitModel(model, allModelsWithInput, imports);\n }\n return generateSimpleModel(model, allModelsWithInput, imports);\n}\n\nfunction generateTypeAlias(model: ModelNode, allModelsWithInput: Set<string>, _: ImportTracker): string[] {\n const lines: string[] = [];\n if (model.description) lines.push(...commentLines(model.description, ''));\n if (model.deprecated) lines.push('# @deprecated');\n lines.push(`${model.name} = ${renderPyType(model.type!, allModelsWithInput)}`);\n if (allModelsWithInput.has(model.name)) {\n lines.push(`${model.name}Input = ${renderPyType(model.type!, allModelsWithInput, true)}`);\n }\n return lines;\n}\n\nfunction generateSimpleModel(model: ModelNode, allModelsWithInput: Set<string>, imports: ImportTracker): string[] {\n const lines: string[] = [];\n if (model.description) lines.push(...commentLines(model.description, ''));\n if (model.deprecated) lines.push('# @deprecated');\n\n const baseList = model.bases && model.bases.length > 0 ? model.bases.join(', ') : 'BaseModel';\n lines.push(`class ${model.name}(${baseList}):`);\n\n const fieldLines = renderFields(model.fields, allModelsWithInput, imports, false);\n const needsConfig = model.fields.some(f => toPythonFieldName(f.name) !== f.name);\n if (needsConfig) {\n imports.add('pydantic', 'ConfigDict');\n lines.push(` model_config = ConfigDict(populate_by_name=True)`);\n lines.push('');\n }\n\n if (fieldLines.length === 0) {\n lines.push(' pass');\n } else {\n lines.push(...fieldLines);\n }\n\n return lines;\n}\n\nfunction generateSplitModel(model: ModelNode, allModelsWithInput: Set<string>, imports: ImportTracker): string[] {\n const lines: string[] = [];\n\n // Read model — omit writeonly fields\n const readFields = model.fields.filter(f => f.visibility !== 'writeonly');\n if (model.description) lines.push(...commentLines(model.description, ''));\n if (model.deprecated) lines.push('# @deprecated');\n\n const readBaseList = model.bases && model.bases.length > 0 ? model.bases.join(', ') : 'BaseModel';\n lines.push(`class ${model.name}(${readBaseList}):`);\n const readNeedsConfig = readFields.some(f => toPythonFieldName(f.name) !== f.name);\n if (readNeedsConfig) {\n imports.add('pydantic', 'ConfigDict');\n lines.push(` model_config = ConfigDict(populate_by_name=True)`);\n lines.push('');\n }\n const readFieldLines = renderFields(readFields, allModelsWithInput, imports, false);\n if (readFieldLines.length === 0) {\n lines.push(' pass');\n } else {\n lines.push(...readFieldLines);\n }\n\n lines.push('');\n\n // Input model — omit readonly fields\n const writeFields = model.fields.filter(f => f.visibility !== 'readonly');\n const inputBaseList =\n model.bases && model.bases.length > 0 ? model.bases.map(b => (allModelsWithInput.has(b) ? `${b}Input` : b)).join(', ') : 'BaseModel';\n lines.push(`class ${model.name}Input(${inputBaseList}):`);\n const writeNeedsConfig = writeFields.some(f => toPythonFieldName(f.name) !== f.name);\n if (writeNeedsConfig) {\n imports.add('pydantic', 'ConfigDict');\n lines.push(` model_config = ConfigDict(populate_by_name=True)`);\n lines.push('');\n }\n const writeFieldLines = renderFields(writeFields, allModelsWithInput, imports, true);\n if (writeFieldLines.length === 0) {\n lines.push(' pass');\n } else {\n lines.push(...writeFieldLines);\n }\n\n return lines;\n}\n\nfunction renderFields(fields: FieldNode[], allModelsWithInput: Set<string>, imports: ImportTracker, forInput: boolean): string[] {\n const lines: string[] = [];\n for (const f of fields) {\n lines.push(...renderField(f, allModelsWithInput, imports, forInput));\n }\n return lines;\n}\n\nfunction renderField(field: FieldNode, allModelsWithInput: Set<string>, imports: ImportTracker, forInput: boolean): string[] {\n const lines: string[] = [];\n const pyName = toPythonFieldName(field.name);\n const needsAlias = pyName !== field.name;\n\n let typeStr = renderPyType(field.type, allModelsWithInput, forInput);\n if (field.nullable) typeStr = `${typeStr} | None`;\n\n const isOptional = field.optional || field.default !== undefined;\n\n const fieldAnnotations: string[] = [];\n if (needsAlias) {\n imports.add('pydantic', 'Field');\n fieldAnnotations.push(`alias=${JSON.stringify(field.name)}`);\n }\n if (field.default !== undefined) {\n const def = typeof field.default === 'string' ? JSON.stringify(field.default) : String(field.default);\n fieldAnnotations.push(`default=${def}`);\n }\n\n if (field.deprecated) lines.push(` # @deprecated`);\n if (field.description) lines.push(...commentLines(field.description, ' '));\n\n let rhs: string;\n if (fieldAnnotations.length > 0) {\n imports.add('pydantic', 'Field');\n rhs = `Field(${fieldAnnotations.join(', ')})`;\n } else if (isOptional) {\n rhs = 'None';\n } else {\n rhs = '';\n }\n\n const optSuffix = isOptional && !field.nullable ? ` | None` : '';\n const fullType = typeStr + optSuffix;\n\n if (rhs) {\n lines.push(` ${pyName}: ${fullType} = ${rhs}`);\n } else {\n lines.push(` ${pyName}: ${fullType}`);\n }\n\n return lines;\n}\n\n// ─── Module name helpers ──────────────────────────────────────────────────\n\n/** Derive a Python module name from a .ck file path, e.g. \"ledger.categories.ck\" → \"_models_ledger_categories\" */\nexport function deriveModelsModuleName(file: string): string {\n const base =\n file\n .split('/')\n .pop()\n ?.replace(/\\.(op\\.)?ck$/, '') ?? 'models';\n const clean = base.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase();\n return `_models_${clean}`;\n}\n","import type {\n OpRootNode,\n OpRouteNode,\n OpOperationNode,\n OpResponseNode,\n OpResponseBodyNode,\n OpResponseHeaderNode,\n ContractTypeNode,\n ParamSource,\n} from '@contractkit/core';\nimport { resolveModifiers, classifyContentType, observableResponses } from '@contractkit/core';\nimport { renderPyType, toPythonFieldName } from './codegen-models.js';\n\n// ─── Response shape ────────────────────────────────────────────────────────\n\n/**\n * How a method reports what came back, mirroring the TypeScript SDK.\n *\n * `simple` is the overwhelmingly common case and generates exactly what it always has: the body\n * itself, or a `(data, headers)` tuple. The other two exist because the caller cannot otherwise\n * know which status or which mime it received.\n */\ntype PyResponseShape =\n | { kind: 'simple'; resp?: OpResponseNode }\n | { kind: 'multiMime'; resp: OpResponseNode }\n | { kind: 'multiStatus'; responses: OpResponseNode[] };\n\nfunction headersClassName(methodBase: string, statusCode?: number): string {\n return statusCode === undefined ? `${methodBase}Headers` : `${methodBase}${statusCode}Headers`;\n}\n\nfunction responseClassName(methodBase: string, statusCode?: number): string {\n return statusCode === undefined ? `${methodBase}Response` : `${methodBase}${statusCode}Response`;\n}\n\n/** The Python type of one response body — non-JSON mimes ignore the schema, as elsewhere. */\nfunction pyBodyType(body: OpResponseBodyNode, modelsWithInput?: Set<string>): string {\n const category = classifyContentType(body.contentType);\n if (category === 'text') return 'str';\n if (category === 'binary') return 'bytes';\n return renderPyType(body.bodyType, modelsWithInput);\n}\n\nfunction pyDataAnnotation(bodies: OpResponseBodyNode[], modelsWithInput?: Set<string>): string {\n const types = [...new Set(bodies.map(b => pyBodyType(b, modelsWithInput)))];\n return types.join(' | ');\n}\n\nfunction pyContentTypeAnnotation(bodies: OpResponseBodyNode[]): string {\n return `Literal[${bodies.map(b => JSON.stringify(b.contentType)).join(', ')}]`;\n}\n\nfunction responseShape(op: OpOperationNode): PyResponseShape {\n const observable = observableResponses(op);\n if (observable.length > 1) return { kind: 'multiStatus', responses: observable };\n const resp = observable[0];\n if (resp && resp.bodies.length > 1) return { kind: 'multiMime', resp };\n return { kind: 'simple', resp };\n}\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\nexport interface ClientCodegenOptions {\n /** Map from model name → Python module path (e.g. \"._models_payments\") */\n modelModulePaths?: Map<string, string>;\n /** Current client's module name (e.g. \"_client_payments\") — used to avoid self-imports */\n currentModule?: string;\n /** Set of model names that have Input variants */\n modelsWithInput?: Set<string>;\n /**\n * Whether to emit client methods for operations marked `internal`. Defaults to `false` —\n * internal ops are omitted so consumers don't pick them up. Set to `true` for an\n * internal-use SDK that should expose them.\n */\n includeInternal?: boolean;\n}\n\n/**\n * Returns true if the root contains at least one operation eligible for client emission.\n * With `includeInternal: false` (default) that means at least one non-internal op; with\n * `includeInternal: true` any op qualifies.\n */\nexport function hasPublicOperations(root: OpRootNode, includeInternal = false): boolean {\n for (const route of root.routes) {\n for (const op of route.operations) {\n if (includeInternal || !resolveModifiers(route, op).includes('internal')) return true;\n }\n }\n return false;\n}\n\n/**\n * Generate a Pydantic/httpx async Python client class from an OpRootNode.\n */\nexport function generatePythonClient(root: OpRootNode, opts: ClientCodegenOptions = {}): string {\n const clientClassName = deriveClientClassName(root.file);\n const { modelsWithInput } = opts;\n const includeInternal = opts.includeInternal ?? false;\n\n // Collect all model types referenced in public ops\n const referencedModels = collectReferencedModels(root, modelsWithInput, includeInternal);\n\n const lines: string[] = [];\n lines.push('# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.');\n lines.push('from __future__ import annotations');\n lines.push('');\n\n // stdlib imports\n const needsDatetime = referencedModels.has('__datetime__');\n const needsDate = referencedModels.has('__date__');\n const needsTime = referencedModels.has('__time__');\n const needsDecimal = referencedModels.has('__decimal__');\n const needsUUID = referencedModels.has('__uuid__');\n const needsAny = referencedModels.has('__any__');\n\n if (needsDatetime || needsDate || needsTime) {\n const dtParts: string[] = [];\n if (needsDate) dtParts.push('date');\n if (needsDatetime) dtParts.push('datetime');\n if (needsTime) dtParts.push('time');\n lines.push(`from datetime import ${dtParts.join(', ')}`);\n }\n if (needsDecimal) lines.push('from decimal import Decimal');\n if (needsUUID) lines.push('from uuid import UUID');\n\n // Collect public ops once — used both for TypedDict emission and method generation.\n const publicOps: Array<{ route: OpRouteNode; op: OpOperationNode }> = [];\n for (const route of root.routes) {\n for (const op of route.operations) {\n if (!includeInternal && resolveModifiers(route, op).includes('internal')) continue;\n publicOps.push({ route, op });\n }\n }\n const opShapes = new Map<OpOperationNode, PyResponseShape>(publicOps.map(({ op }) => [op, responseShape(op)]));\n const opsWithRespHeaders = publicOps.filter(({ op }) => {\n const shape = opShapes.get(op)!;\n if (shape.kind === 'multiStatus') return shape.responses.some(r => (r.headers?.length ?? 0) > 0);\n return (shape.resp?.headers?.length ?? 0) > 0;\n });\n const opsWithResponseDict = publicOps.filter(({ op }) => opShapes.get(op)!.kind !== 'simple');\n const needsTypedDict = opsWithRespHeaders.length > 0 || opsWithResponseDict.length > 0;\n const needsLiteral = opsWithResponseDict.length > 0;\n\n if (needsAny || needsTypedDict) {\n const typingImports: string[] = [];\n if (needsAny) typingImports.push('Any');\n if (needsLiteral) typingImports.push('Literal');\n if (needsTypedDict) typingImports.push('TypedDict');\n lines.push(`from typing import ${typingImports.join(', ')}`);\n }\n lines.push('from ._base_client import BaseClient, SdkError # noqa: F401');\n\n // Model imports grouped by module\n const modelImportsByModule = new Map<string, Set<string>>();\n for (const name of referencedModels) {\n if (name.startsWith('__')) continue; // sentinel keys\n const modulePath = opts.modelModulePaths?.get(name);\n if (modulePath) {\n let s = modelImportsByModule.get(modulePath);\n if (!s) {\n s = new Set();\n modelImportsByModule.set(modulePath, s);\n }\n s.add(name);\n }\n }\n for (const [mod, names] of [...modelImportsByModule].sort((a, b) => a[0].localeCompare(b[0]))) {\n const sorted = [...names].sort().join(', ');\n lines.push(`from ${mod} import ${sorted}`);\n }\n\n // Per-method response-header TypedDicts. Multi-status methods get one per status, since\n // each status declares its own headers.\n for (const { route, op } of opsWithRespHeaders) {\n const shape = opShapes.get(op)!;\n const base = snakeToPascal(deriveMethodName(op, route));\n const targets =\n shape.kind === 'multiStatus'\n ? shape.responses.filter(r => (r.headers?.length ?? 0) > 0).map(r => ({ name: headersClassName(base, r.statusCode), resp: r }))\n : [{ name: headersClassName(base), resp: shape.resp! }];\n for (const { name, resp } of targets) {\n lines.push('');\n lines.push('');\n lines.push(`class ${name}(TypedDict, total=False):`);\n for (const h of resp.headers!) {\n const pyName = toPythonFieldName(h.name);\n const tag = h.optional ? 'optional' : 'required';\n lines.push(` ${pyName}: str # ${h.name} (${tag})`);\n }\n }\n }\n\n // Per-method response TypedDicts for the shapes that have to report status or mime.\n for (const { route, op } of opsWithResponseDict) {\n const shape = opShapes.get(op)!;\n const base = snakeToPascal(deriveMethodName(op, route));\n const targets: OpResponseNode[] = shape.kind === 'multiStatus' ? shape.responses : shape.kind === 'multiMime' ? [shape.resp] : [];\n for (const resp of targets) {\n lines.push('');\n lines.push('');\n lines.push(`class ${responseClassName(base, shape.kind === 'multiStatus' ? resp.statusCode : undefined)}(TypedDict):`);\n if (shape.kind === 'multiStatus') lines.push(` status: Literal[${resp.statusCode}]`);\n const bodies = resp.bodies;\n if (bodies.length > 0) {\n lines.push(` content_type: ${pyContentTypeAnnotation(bodies)}`);\n lines.push(` data: ${pyDataAnnotation(bodies, opts.modelsWithInput)}`);\n }\n if ((resp.headers?.length ?? 0) > 0) {\n lines.push(` headers: ${headersClassName(base, shape.kind === 'multiStatus' ? resp.statusCode : undefined)}`);\n }\n if (shape.kind !== 'multiStatus' && bodies.length === 0 && (resp.headers?.length ?? 0) === 0) {\n lines.push(' pass');\n }\n }\n }\n\n lines.push('');\n lines.push('');\n lines.push(`class ${clientClassName}(BaseClient):`);\n\n let hasAnyMethod = false;\n for (const route of root.routes) {\n for (const op of route.operations) {\n const mods = resolveModifiers(route, op);\n if (!includeInternal && mods.includes('internal')) continue;\n hasAnyMethod = true;\n lines.push('');\n if (mods.includes('deprecated')) lines.push(' # @deprecated');\n lines.push(...generateMethod(route, op, opts));\n }\n }\n\n if (!hasAnyMethod) {\n lines.push(' pass');\n }\n\n lines.push('');\n\n return lines.join('\\n');\n}\n\n// ─── Method generation ────────────────────────────────────────────────────\n\ninterface MethodParam {\n name: string;\n type: string;\n optional: boolean;\n isModel: boolean; // Pydantic BaseModel → use .model_dump(mode=\"json\")\n}\n\nfunction generateMethod(route: OpRouteNode, op: OpOperationNode, opts: ClientCodegenOptions): string[] {\n const lines: string[] = [];\n const { modelsWithInput } = opts;\n const methodName = deriveMethodName(op, route);\n const httpMethod = op.method.toUpperCase();\n\n const params = buildMethodParams(route, op, modelsWithInput);\n const selfParam = 'self';\n const allParams = params.map(p => {\n if (p.optional) return `${p.name}: ${p.type} | None = None`;\n return `${p.name}: ${p.type}`;\n });\n const paramStr = allParams.length > 0 ? `, ${allParams.join(', ')}` : '';\n\n // Return type — non-JSON responses ignore the schema and return raw bytes/str.\n //\n // `observableResponses` is shared with the Koa router and the TypeScript SDK, so all three\n // agree on which statuses are values and which are errors.\n const shape = responseShape(op);\n const methodBase = snakeToPascal(methodName);\n const primaryResponse = shape.kind === 'multiStatus' ? undefined : shape.resp;\n const primaryBodies = primaryResponse ? primaryResponse.bodies : [];\n const isVoid = primaryBodies.length === 0;\n const respCategory = primaryBodies[0] ? classifyContentType(primaryBodies[0].contentType) : 'json';\n const dataType = isVoid ? 'None' : pyBodyType(primaryBodies[0]!, modelsWithInput);\n const isModelReturn = !isVoid && respCategory === 'json' && isModelRef(primaryBodies[0]!.bodyType, modelsWithInput);\n const isListModelReturn = !isVoid && respCategory === 'json' && isListModelRef(primaryBodies[0]!.bodyType, modelsWithInput);\n const respHeaders = primaryResponse?.headers ?? [];\n const hasRespHeaders = respHeaders.length > 0;\n const headersTypeName = hasRespHeaders ? headersClassName(methodBase) : '';\n const returnType =\n shape.kind === 'multiStatus'\n ? shape.responses.map(r => responseClassName(methodBase, r.statusCode)).join(' | ')\n : shape.kind === 'multiMime'\n ? responseClassName(methodBase)\n : hasRespHeaders\n ? isVoid\n ? headersTypeName\n : `tuple[${dataType}, ${headersTypeName}]`\n : dataType;\n\n // Description\n const desc = op.description ?? route.description;\n if (op.name || desc) {\n lines.push(` async def ${methodName}(${selfParam}${paramStr}) -> ${returnType}:`);\n lines.push(` \"\"\"`);\n if (op.name) lines.push(...docstringLines(op.name, ' '));\n if (desc) lines.push(...docstringLines(desc, ' '));\n lines.push(` \"\"\"`);\n } else {\n lines.push(` async def ${methodName}(${selfParam}${paramStr}) -> ${returnType}:`);\n }\n\n // Build URL\n const urlExpr = buildUrlExpression(route.path);\n\n // Query params\n const hasQuery = !!op.query;\n const primaryBody = op.request?.bodies[0];\n const hasBody = !!primaryBody;\n const isMultipart = primaryBody?.contentType === 'multipart/form-data';\n const hasCustomHeaders = !!op.headers;\n\n // Build kwargs for _fetch\n const fetchKwargs: string[] = [];\n fetchKwargs.push(`method=\"${httpMethod}\"`);\n\n const reqCategory = primaryBody?.contentType ? classifyContentType(primaryBody.contentType) : 'json';\n if (hasBody) {\n const bodyParam = params.find(p => p.name === 'body');\n if (isMultipart) {\n fetchKwargs.push('body=body');\n } else if (reqCategory === 'text' || reqCategory === 'binary') {\n // Pass-through: caller supplies a str / bytes payload that goes on the wire as-is.\n fetchKwargs.push('body=body');\n } else if (bodyParam?.isModel) {\n fetchKwargs.push('body=body.model_dump(mode=\"json\")');\n } else {\n fetchKwargs.push('body=body');\n }\n // Forward the declared content-type so `_fetch` sets the correct Content-Type header\n // (vendor JSON types like `application/vnd.api+json` still serialize as JSON but need\n // their literal mime on the wire).\n if (primaryBody.contentType !== 'application/json') {\n fetchKwargs.push(`content_type=${JSON.stringify(primaryBody.contentType)}`);\n }\n if (reqCategory === 'text' || reqCategory === 'binary') {\n fetchKwargs.push(`body_kind=\"${reqCategory}\"`);\n }\n }\n if (shape.kind !== 'simple') {\n // Several mimes or statuses in play — only the response knows how to read itself.\n fetchKwargs.push(`response_kind=\"auto\"`);\n } else if (respCategory === 'text' || respCategory === 'binary') {\n fetchKwargs.push(`response_kind=\"${respCategory}\"`);\n }\n\n const observable = shape.kind === 'multiStatus' ? shape.responses : shape.resp ? [shape.resp] : [];\n const expectStatuses = observable.filter(r => r.statusCode < 200 || r.statusCode >= 300).map(r => r.statusCode);\n if (expectStatuses.length > 0) {\n // A single-element tuple needs the trailing comma or Python reads it as parentheses.\n const tuple = expectStatuses.length === 1 ? `(${expectStatuses[0]},)` : `(${expectStatuses.join(', ')})`;\n fetchKwargs.push(`expect_statuses=${tuple}`);\n }\n\n if (hasQuery) {\n fetchKwargs.push('params=query');\n }\n\n if (hasCustomHeaders) {\n fetchKwargs.push('extra_headers=custom_headers');\n }\n\n const kwargsStr = fetchKwargs.length > 1 ? fetchKwargs.join(', ') : (fetchKwargs[0] ?? '');\n\n if (shape.kind !== 'simple') {\n lines.push(` _status, _content_type, result, _response_headers = await self._fetch_full(${urlExpr}, ${kwargsStr})`);\n lines.push(...buildMultiReturnLines(shape, methodBase, modelsWithInput));\n return lines;\n }\n\n if (hasRespHeaders) {\n lines.push(` result, _response_headers = await self._fetch_with_headers(${urlExpr}, ${kwargsStr})`);\n lines.push(...buildHeadersDictLines(respHeaders, headersTypeName));\n } else {\n lines.push(` result = await self._fetch(${urlExpr}, ${kwargsStr})`);\n }\n\n if (isVoid) {\n if (hasRespHeaders) {\n lines.push(` return headers`);\n } else {\n lines.push(` return None`);\n }\n } else {\n let dataExpr: string;\n if (isListModelReturn) {\n const innerType = getListItemType(primaryBodies[0]!.bodyType, modelsWithInput);\n dataExpr = `[${innerType}.model_validate(item) for item in result]`;\n } else if (isModelReturn) {\n dataExpr = `${dataType}.model_validate(result)`;\n } else {\n dataExpr = 'result';\n }\n if (hasRespHeaders) {\n lines.push(` return ${dataExpr}, headers`);\n } else {\n lines.push(` return ${dataExpr}`);\n }\n }\n\n return lines;\n}\n\n/** The expression that turns a decoded body into the declared type, validating models. */\nfunction pyDataExpr(body: OpResponseBodyNode, modelsWithInput?: Set<string>): string {\n if (classifyContentType(body.contentType) !== 'json') return 'result';\n if (isListModelRef(body.bodyType, modelsWithInput)) {\n return `[${getListItemType(body.bodyType, modelsWithInput)}.model_validate(item) for item in result]`;\n }\n if (isModelRef(body.bodyType, modelsWithInput)) {\n return `${renderPyType(body.bodyType, modelsWithInput)}.model_validate(result)`;\n }\n return 'result';\n}\n\n/**\n * Return statements for a method that reports its status or mime.\n *\n * Dispatch is a chain of `if`s on the runtime status (or content type), with the first declared\n * alternative as the fall-through so the function always returns.\n */\nfunction buildMultiReturnLines(\n shape: Extract<PyResponseShape, { kind: 'multiMime' | 'multiStatus' }>,\n methodBase: string,\n modelsWithInput?: Set<string>,\n): string[] {\n const lines: string[] = [];\n\n const returnFor = (resp: OpResponseNode, body: OpResponseBodyNode | undefined, indent: string, includeStatus: boolean, headersVar?: string): string[] => {\n const entries: string[] = [];\n if (includeStatus) entries.push(`\"status\": ${resp.statusCode}`);\n if (body) {\n entries.push(`\"content_type\": ${JSON.stringify(body.contentType)}`);\n entries.push(`\"data\": ${pyDataExpr(body, modelsWithInput)}`);\n }\n if (headersVar) entries.push(`\"headers\": ${headersVar}`);\n return [`${indent}return {${entries.length > 0 ? ` ${entries.join(', ')} ` : ''}}`];\n };\n\n /** One status, dispatching over its mimes when they do not all decode the same way. */\n const emitStatus = (resp: OpResponseNode, indent: string, includeStatus: boolean): string[] => {\n const out: string[] = [];\n // Built once per status, under a name of its own: two statuses in the same method can\n // declare different headers, and Python has no block scope to keep them apart.\n let headersVar: string | undefined;\n if ((resp.headers?.length ?? 0) > 0) {\n headersVar = includeStatus ? `headers_${resp.statusCode}` : 'headers';\n const typeName = headersClassName(methodBase, includeStatus ? resp.statusCode : undefined);\n out.push(...buildHeadersDictLines(resp.headers!, typeName, indent, headersVar));\n }\n\n const bodies = resp.bodies;\n if (bodies.length <= 1) {\n out.push(...returnFor(resp, bodies[0], indent, includeStatus, headersVar));\n return out;\n }\n for (const body of bodies.slice(1)) {\n out.push(`${indent}if _content_type == ${JSON.stringify(body.contentType)}:`);\n out.push(...returnFor(resp, body, `${indent} `, includeStatus, headersVar));\n }\n out.push(...returnFor(resp, bodies[0], indent, includeStatus, headersVar));\n return out;\n };\n\n if (shape.kind === 'multiMime') {\n lines.push(...emitStatus(shape.resp, ' ', false));\n return lines;\n }\n\n const [fallback, ...rest] = shape.responses;\n for (const resp of rest) {\n lines.push(` if _status == ${resp.statusCode}:`);\n lines.push(...emitStatus(resp, ' ', true));\n }\n lines.push(...emitStatus(fallback!, ' ', true));\n return lines;\n}\n\n/** Build the lines that construct a TypedDict literal of declared response headers. */\nfunction buildHeadersDictLines(headers: OpResponseHeaderNode[], typeName: string, indent = ' ', varName = 'headers'): string[] {\n const lines: string[] = [];\n lines.push(`${indent}${varName}: ${typeName} = {}`);\n for (const h of headers) {\n const pyName = toPythonFieldName(h.name);\n lines.push(`${indent}if ${JSON.stringify(h.name.toLowerCase())} in _response_headers:`);\n lines.push(`${indent} ${varName}[${JSON.stringify(pyName)}] = _response_headers[${JSON.stringify(h.name.toLowerCase())}]`);\n }\n return lines;\n}\n\n/**\n * Render `text` as indented docstring body lines, neutralizing anything that\n * could terminate the enclosing `\"\"\"` docstring early. `op.name` / descriptions\n * come from user `.ck` source and may contain `\"\"\"` runs or embedded newlines.\n * Each `\"` is escaped to `\\\"` (inside a Python string `\\\"` cannot close a `\"\"\"`),\n * and a trailing backslash is guarded with a space so it can't escape the delimiter.\n */\nfunction docstringLines(text: string, indent: string): string[] {\n return text.split('\\n').map(line => {\n let safe = line.replace(/\"/g, '\\\\\"');\n if (/\\\\$/.test(safe)) safe += ' ';\n return `${indent}${safe}`;\n });\n}\n\n/** snake_case → PascalCase. */\nfunction snakeToPascal(s: string): string {\n return s\n .split('_')\n .filter(Boolean)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n}\n\n// ─── URL building ─────────────────────────────────────────────────────────\n\nfunction buildUrlExpression(path: string): string {\n // Replace {paramName} with Python f-string interpolation\n const hasBraces = /\\{[a-zA-Z_][a-zA-Z0-9_]*\\}/.test(path);\n if (!hasBraces) return `\"${path}\"`;\n const interpolated = path.replace(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g, (_m, name) => `{${name}}`);\n return `f\"${interpolated}\"`;\n}\n\n// ─── Parameter building ───────────────────────────────────────────────────\n\nfunction buildMethodParams(route: OpRouteNode, op: OpOperationNode, modelsWithInput?: Set<string>): MethodParam[] {\n const params: MethodParam[] = [];\n\n // Path params\n if (route.params) {\n if (route.params.kind === 'params') {\n for (const p of route.params.nodes) {\n params.push({\n name: toPythonFieldName(p.name),\n type: renderPyType(p.type, modelsWithInput),\n optional: false,\n isModel: false,\n });\n }\n } else if (route.params.kind === 'ref') {\n const typeName = modelsWithInput?.has(route.params.name) ? `${route.params.name}Input` : route.params.name;\n params.push({ name: 'params', type: typeName, optional: false, isModel: true });\n } else {\n params.push({ name: 'params', type: renderPyType(route.params.node, modelsWithInput), optional: false, isModel: false });\n }\n }\n\n // Body — use the first declared MIME's body type as the parameter type.\n // Multi-MIME support in Python collapses to a single signature using the primary body.\n const primaryBody = op.request?.bodies[0];\n if (primaryBody) {\n const cat = classifyContentType(primaryBody.contentType);\n if (cat === 'multipart' || cat === 'binary') {\n params.push({ name: 'body', type: 'bytes', optional: false, isModel: false });\n } else if (cat === 'text') {\n params.push({ name: 'body', type: 'str', optional: false, isModel: false });\n } else {\n const bodyType = renderInputPyType(primaryBody.bodyType, modelsWithInput);\n const isModel = isModelRef(primaryBody.bodyType, modelsWithInput);\n params.push({ name: 'body', type: bodyType, optional: false, isModel });\n }\n }\n\n // Query\n if (op.query) {\n const queryType = renderParamSourceType(op.query, modelsWithInput, true);\n params.push({ name: 'query', type: queryType, optional: true, isModel: false });\n }\n\n // Headers\n if (op.headers) {\n const headersType = renderParamSourceType(op.headers, modelsWithInput, true);\n params.push({ name: 'custom_headers', type: headersType, optional: true, isModel: false });\n }\n\n return params;\n}\n\nfunction renderParamSourceType(source: ParamSource, modelsWithInput?: Set<string>, forInput = false): string {\n if (source.kind === 'ref') {\n const typeName = forInput && modelsWithInput?.has(source.name) ? `${source.name}Input` : source.name;\n return typeName;\n }\n if (source.kind === 'params') {\n // const fields = source.nodes.map(p => {\n // const pyName = toPythonFieldName(p.name);\n // return `\"${pyName}\": ${renderPyType(p.type, modelsWithInput, forInput)}`;\n // });\n return `dict`; // simplified — inline dicts are hard to type concisely in Python signatures\n }\n return renderPyType(source.node, modelsWithInput, forInput);\n}\n\nfunction renderInputPyType(type: ContractTypeNode, modelsWithInput?: Set<string>): string {\n return renderPyType(type, modelsWithInput, true);\n}\n\n// ─── Model reference detection ────────────────────────────────────────────\n\nfunction isModelRef(type: ContractTypeNode, modelsWithInput?: Set<string>): boolean {\n if (type.kind === 'ref') return /^[A-Z]/.test(type.name);\n if (type.kind === 'lazy') return isModelRef(type.inner, modelsWithInput);\n return false;\n}\n\nfunction isListModelRef(type: ContractTypeNode, modelsWithInput?: Set<string>): boolean {\n if (type.kind === 'array') return isModelRef(type.item, modelsWithInput);\n if (type.kind === 'lazy') return isListModelRef(type.inner, modelsWithInput);\n return false;\n}\n\nfunction getListItemType(type: ContractTypeNode, modelsWithInput?: Set<string>): string {\n if (type.kind === 'array') return renderPyType(type.item, modelsWithInput);\n return 'dict';\n}\n\n// ─── Referenced model collection ─────────────────────────────────────────\n\n/**\n * Collect all model names and scalar sentinels referenced in public operations.\n * Sentinels: __datetime__, __date__, __time__, __decimal__, __uuid__, __any__\n */\nfunction collectReferencedModels(root: OpRootNode, modelsWithInput?: Set<string>, includeInternal = false): Set<string> {\n const refs = new Set<string>();\n\n for (const route of root.routes) {\n for (const op of route.operations) {\n if (!includeInternal && resolveModifiers(route, op).includes('internal')) continue;\n\n if (route.params) collectParamSourceRefs(route.params, refs, modelsWithInput);\n if (op.request) {\n for (const body of op.request.bodies) collectTypeRefs(body.bodyType, refs, modelsWithInput, true);\n }\n for (const resp of op.responses) {\n for (const body of resp.bodies) collectTypeRefs(body.bodyType, refs, modelsWithInput, false);\n }\n if (op.query) collectParamSourceRefs(op.query, refs, modelsWithInput);\n if (op.headers) collectParamSourceRefs(op.headers, refs, modelsWithInput);\n }\n }\n\n return refs;\n}\n\nfunction collectParamSourceRefs(source: ParamSource, out: Set<string>, modelsWithInput?: Set<string>): void {\n if (source.kind === 'ref') {\n addModelRef(source.name, out, modelsWithInput);\n } else if (source.kind === 'params') {\n for (const p of source.nodes) collectTypeRefs(p.type, out, modelsWithInput);\n } else {\n collectTypeRefs(source.node, out, modelsWithInput);\n }\n}\n\nfunction addModelRef(name: string, out: Set<string>, modelsWithInput?: Set<string>): void {\n if (/^[A-Z]/.test(name)) {\n out.add(name);\n if (modelsWithInput?.has(name)) out.add(`${name}Input`);\n }\n}\n\nfunction collectTypeRefs(type: ContractTypeNode, out: Set<string>, modelsWithInput?: Set<string>, forInput = false): void {\n switch (type.kind) {\n case 'scalar':\n switch (type.name) {\n case 'date':\n out.add('__date__');\n break;\n case 'time':\n out.add('__time__');\n break;\n case 'datetime':\n out.add('__datetime__');\n break;\n case 'decimal':\n out.add('__decimal__');\n break;\n case 'uuid':\n out.add('__uuid__');\n break;\n case 'unknown':\n case 'json':\n case 'object':\n out.add('__any__');\n break;\n }\n break;\n case 'ref':\n if (forInput && modelsWithInput?.has(type.name)) {\n out.add(`${type.name}Input`);\n } else {\n addModelRef(type.name, out, modelsWithInput);\n }\n break;\n case 'array':\n collectTypeRefs(type.item, out, modelsWithInput, forInput);\n break;\n case 'tuple':\n type.items.forEach(t => collectTypeRefs(t, out, modelsWithInput, forInput));\n break;\n case 'record':\n collectTypeRefs(type.key, out, modelsWithInput, forInput);\n collectTypeRefs(type.value, out, modelsWithInput, forInput);\n break;\n case 'union':\n type.members.forEach(m => collectTypeRefs(m, out, modelsWithInput, forInput));\n break;\n case 'discriminatedUnion':\n type.members.forEach(m => collectTypeRefs(m, out, modelsWithInput, forInput));\n break;\n case 'intersection':\n out.add('__any__');\n break;\n case 'lazy':\n collectTypeRefs(type.inner, out, modelsWithInput, forInput);\n break;\n case 'inlineObject':\n out.add('__any__');\n break;\n }\n}\n\n// ─── Naming helpers ───────────────────────────────────────────────────────\n\nfunction deriveBaseName(file: string): string {\n const base =\n file\n .split('/')\n .pop()\n ?.replace(/\\.(op\\.)?ck$/, '') ?? 'Resource';\n return base\n .split('.')\n .map(s => s.charAt(0).toUpperCase() + s.slice(1))\n .join('');\n}\n\nexport function deriveClientClassName(file: string): string {\n return `${deriveBaseName(file)}Client`;\n}\n\nexport function deriveClientModuleName(file: string): string {\n const base =\n file\n .split('/')\n .pop()\n ?.replace(/\\.(op\\.)?ck$/, '') ?? 'client';\n const clean = base.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase();\n return `_client_${clean}`;\n}\n\nexport function deriveClientPropertyName(file: string): string {\n const base = deriveBaseName(file);\n return base.charAt(0).toLowerCase() + base.slice(1);\n}\n\nfunction deriveMethodName(op: OpOperationNode, route: OpRouteNode): string {\n if (op.sdk) return toSnakeCase(op.sdk);\n if (op.name) return toSnakeCase(op.name);\n return inferMethodName(op.method, route.path);\n}\n\nfunction inferMethodName(method: string, path: string): string {\n const segments = path.split('/').filter(s => s.length > 0);\n const parts: string[] = [method.toLowerCase()];\n\n for (const seg of segments) {\n if (seg.startsWith('{')) {\n const paramName = seg.slice(1, -1);\n parts.push('by_' + toSnakeCase(paramName));\n } else {\n parts.push(toSnakeCase(seg.replace(/[.-]/g, '_')));\n }\n }\n\n return parts.join('_').replace(/_+/g, '_');\n}\n\nfunction toSnakeCase(s: string): string {\n return s\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[^a-zA-Z0-9]/g, '_')\n .toLowerCase()\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n}\n\n// ─── Shared base client content ───────────────────────────────────────────\n\nexport const BASE_CLIENT_PY = `# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.\nfrom __future__ import annotations\n\nimport httpx\nfrom typing import Any\n\n\nclass SdkError(Exception):\n def __init__(self, status: int, status_text: str, body: Any):\n super().__init__(f\"{status} {status_text}\")\n self.status = status\n self.status_text = status_text\n self.body = body\n\n\nclass BaseClient:\n def __init__(self, base_url: str, headers: dict[str, str] | None = None):\n self._base_url = base_url.rstrip(\"/\")\n self._headers = headers or {}\n self._http = httpx.AsyncClient()\n self._last_status = 0\n self._last_content_type = \"\"\n\n async def _fetch(\n self,\n path: str,\n *,\n method: str,\n body: Any = None,\n params: dict | None = None,\n extra_headers: dict | None = None,\n content_type: str | None = None,\n body_kind: str = \"json\",\n response_kind: str = \"json\",\n expect_statuses: tuple[int, ...] = (),\n ) -> Any:\n result, _ = await self._fetch_with_headers(\n path,\n method=method,\n body=body,\n params=params,\n extra_headers=extra_headers,\n content_type=content_type,\n body_kind=body_kind,\n response_kind=response_kind,\n expect_statuses=expect_statuses,\n )\n return result\n\n async def _fetch_full(\n self,\n path: str,\n *,\n method: str,\n body: Any = None,\n params: dict | None = None,\n extra_headers: dict | None = None,\n content_type: str | None = None,\n body_kind: str = \"json\",\n response_kind: str = \"json\",\n expect_statuses: tuple[int, ...] = (),\n ) -> tuple[int, str, Any, dict[str, str]]:\n \"\"\"Like _fetch_with_headers, but also reports the status and content type.\n\n Used by operations that declare more than one status, or more than one mime for a\n status, where the caller cannot know which it got without being told.\n \"\"\"\n result, headers = await self._fetch_with_headers(\n path,\n method=method,\n body=body,\n params=params,\n extra_headers=extra_headers,\n content_type=content_type,\n body_kind=body_kind,\n response_kind=response_kind,\n expect_statuses=expect_statuses,\n )\n return self._last_status, self._last_content_type, result, headers\n\n async def _fetch_with_headers(\n self,\n path: str,\n *,\n method: str,\n body: Any = None,\n params: dict | None = None,\n extra_headers: dict | None = None,\n content_type: str | None = None,\n body_kind: str = \"json\",\n response_kind: str = \"json\",\n expect_statuses: tuple[int, ...] = (),\n ) -> tuple[Any, dict[str, str]]:\n headers = {**self._headers, **(extra_headers or {})}\n if body is not None:\n headers[\"Content-Type\"] = content_type or \"application/json\"\n # body_kind controls how httpx serializes the request body:\n # \"json\" — body is a JSON-serializable object, sent via httpx's json= kwarg\n # \"text\"/\"binary\" — body is a raw str/bytes payload, sent via content= unchanged\n request_kwargs: dict[str, Any] = {\"method\": method, \"url\": f\"{self._base_url}{path}\", \"params\": params, \"headers\": headers}\n if body is not None:\n if body_kind == \"json\":\n request_kwargs[\"json\"] = body\n else:\n request_kwargs[\"content\"] = body\n response = await self._http.request(**request_kwargs)\n # expect_statuses carries the codes this operation declares as values rather than\n # errors — a 304 from conditional-GET middleware, or an error status the service\n # returns deliberately. Anything else outside 2xx still raises.\n if not response.is_success and response.status_code not in expect_statuses:\n try:\n error_body = response.json()\n except Exception:\n error_body = response.text\n raise SdkError(response.status_code, response.reason_phrase, error_body)\n # HTTP headers are case-insensitive — normalize to lowercase keys for stable lookup.\n response_headers = {k.lower(): v for k, v in response.headers.items()}\n self._last_status = response.status_code\n self._last_content_type = response.headers.get(\"content-type\", \"\").split(\";\")[0].strip()\n if response.status_code == 204 or not response.content:\n return None, response_headers\n # \"auto\" is for a status declaring several mimes that do not read the same way: the\n # response itself is the only thing that knows which one came back.\n kind = response_kind\n if kind == \"auto\":\n ct = self._last_content_type\n if ct.startswith(\"text/\"):\n kind = \"text\"\n elif ct == \"application/json\" or ct.endswith(\"+json\"):\n kind = \"json\"\n else:\n kind = \"binary\"\n if kind == \"text\":\n return response.text, response_headers\n if kind == \"binary\":\n return response.content, response_headers\n return response.json(), response_headers\n`;\n"],"mappings":"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","names":["resolve","join","relative","dirname","existsSync","readFileSync","writeFileSync","mkdirSync","rmSync","readdirSync","rmdirSync","runIncrementalCodegen","parseIncrementalManifest","emptyIncrementalManifest","serializeIncrementalManifest","hashFingerprint","collectTransitiveModelRefs","collectTypeRefs","computeModelsWithInput","topoSortModels","collectExternalRefs","collectExternalInputRefs","generatePydanticModels","root","opts","externalRefs","collectExternalRefs","externalModelsWithInput","modelsWithInput","Set","localModelsWithInput","computeModelsWithInput","models","allModelsWithInput","externalInputRefs","size","collectExternalInputRefs","allExternalRefs","sort","imports","ImportTracker","add","model","type","scanTypeImports","f","fields","lines","push","crossFileImports","ref","modulePath","modelModulePaths","get","currentModule","modelLines","topoSortModels","generateModel","stdlibLines","render","length","join","groups","Map","module","name","s","set","has","ORDER","mod","names","sorted","includes","kind","members","forEach","m","item","items","t","key","value","inner","renderPyType","forInput","renderScalar","values","map","v","JSON","stringify","String","discriminator","_exhaustive","Error","toPythonFieldName","result","replace","toLowerCase","test","commentLines","text","indent","split","line","generateTypeAlias","needsInputSplit","some","visibility","generateSplitModel","generateSimpleModel","_","description","deprecated","baseList","bases","fieldLines","renderFields","needsConfig","readFields","filter","readBaseList","readNeedsConfig","readFieldLines","writeFields","inputBaseList","b","writeNeedsConfig","writeFieldLines","renderField","field","pyName","needsAlias","typeStr","nullable","isOptional","optional","default","undefined","fieldAnnotations","def","rhs","optSuffix","fullType","deriveModelsModuleName","file","base","pop","clean","resolveModifiers","classifyContentType","observableResponses","headersClassName","methodBase","statusCode","undefined","responseClassName","pyBodyType","body","modelsWithInput","category","classifyContentType","contentType","renderPyType","bodyType","pyDataAnnotation","bodies","types","Set","map","b","join","pyContentTypeAnnotation","JSON","stringify","responseShape","op","observable","observableResponses","length","kind","responses","resp","hasPublicOperations","root","includeInternal","route","routes","operations","resolveModifiers","includes","generatePythonClient","opts","clientClassName","deriveClientClassName","file","referencedModels","collectReferencedModels","lines","push","needsDatetime","has","needsDate","needsTime","needsDecimal","needsUUID","needsAny","dtParts","publicOps","opShapes","Map","opsWithRespHeaders","filter","shape","get","some","r","headers","opsWithResponseDict","needsTypedDict","needsLiteral","typingImports","modelImportsByModule","name","startsWith","modulePath","modelModulePaths","s","set","add","mod","names","sort","a","localeCompare","sorted","base","snakeToPascal","deriveMethodName","targets","h","pyName","toPythonFieldName","tag","optional","hasAnyMethod","mods","generateMethod","methodName","httpMethod","method","toUpperCase","params","buildMethodParams","selfParam","allParams","p","type","paramStr","primaryResponse","primaryBodies","isVoid","respCategory","dataType","isModelReturn","isModelRef","isListModelReturn","isListModelRef","respHeaders","hasRespHeaders","headersTypeName","returnType","desc","description","docstringLines","urlExpr","buildUrlExpression","path","hasQuery","query","primaryBody","request","hasBody","isMultipart","hasCustomHeaders","fetchKwargs","reqCategory","bodyParam","find","isModel","expectStatuses","tuple","kwargsStr","buildMultiReturnLines","buildHeadersDictLines","dataExpr","innerType","getListItemType","pyDataExpr","returnFor","indent","includeStatus","headersVar","entries","emitStatus","out","typeName","slice","fallback","rest","varName","toLowerCase","text","split","line","safe","replace","test","Boolean","charAt","hasBraces","interpolated","_m","nodes","node","cat","renderInputPyType","queryType","renderParamSourceType","headersType","source","forInput","inner","item","refs","collectParamSourceRefs","collectTypeRefs","addModelRef","items","forEach","t","key","value","members","m","deriveBaseName","pop","deriveClientModuleName","clean","deriveClientPropertyName","sdk","toSnakeCase","inferMethodName","segments","parts","seg","paramName","BASE_CLIENT_PY","PYTHON_CODEGEN_VERSION","CACHE_MANIFEST_FILENAME","plugin","name","generateTargets","inputs","ctx","config","options","runPythonCodegen","rootDir","createPythonSdkPlugin","contractRoots","opRoots","modelsWithInput","outDir","resolve","baseDir","manifestPath","cacheDir","modelModulePaths","Map","modelMap","contractEntries","root","moduleName","deriveModelsModuleName","file","push","relPath","model","models","set","has","modelsWithInputArray","sort","prevManifest","cacheEnabled","readManifest","emptyIncrementalManifest","units","ownNames","Set","map","m","externalRefs","collectExternalRefsFromContract","referencedModulePaths","ref","path","get","inputPath","relevantInputModels","filter","fingerprint","hashFingerprint","kind","v","currentModule","key","render","relativePath","content","generatePydanticModels","clientInfos","hasPublicOperations","includeInternal","deriveClientModuleName","className","deriveClientClassName","propertyName","deriveClientPropertyName","referencedModels","collectOpRootModelRefs","generatePythonClient","sdkClassName","packageName","split","s","charAt","toUpperCase","slice","join","initLines","c","length","allNames","n","JSON","stringify","globalFiles","BASE_CLIENT_PY","result","runIncrementalCodegen","codegenVersion","fileExists","existsSync","deleteStalePaths","deletedPaths","filesToWrite","emitFile","writeManifest","manifest","relative","refs","type","collectTypeRefs","f","fields","bases","b","add","own","delete","seeds","route","routes","params","paramSourceTypes","op","operations","query","headers","request","body","bodies","bodyType","resp","responses","h","collectTransitiveModelRefs","src","out","nodes","node","parseIncrementalManifest","readFileSync","mkdirSync","dirname","recursive","writeFileSync","serializeIncrementalManifest","relPaths","removedDirs","rel","abs","rmSync","force","dir","current","startsWith","readdirSync","rmdirSync"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractkit/plugin-python",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "ContractKit built-in plugin: Python SDK client generation (Pydantic v2 + httpx)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
".": "./dist/index.js"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@contractkit/core": "0.
|
|
30
|
+
"@contractkit/core": "0.28.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"unplugin-swc": "^1.5.9",
|
package/src/codegen-client.ts
CHANGED
|
@@ -109,6 +109,7 @@ export function generatePythonClient(root: OpRootNode, opts: ClientCodegenOption
|
|
|
109
109
|
const needsDatetime = referencedModels.has('__datetime__');
|
|
110
110
|
const needsDate = referencedModels.has('__date__');
|
|
111
111
|
const needsTime = referencedModels.has('__time__');
|
|
112
|
+
const needsDecimal = referencedModels.has('__decimal__');
|
|
112
113
|
const needsUUID = referencedModels.has('__uuid__');
|
|
113
114
|
const needsAny = referencedModels.has('__any__');
|
|
114
115
|
|
|
@@ -119,6 +120,7 @@ export function generatePythonClient(root: OpRootNode, opts: ClientCodegenOption
|
|
|
119
120
|
if (needsTime) dtParts.push('time');
|
|
120
121
|
lines.push(`from datetime import ${dtParts.join(', ')}`);
|
|
121
122
|
}
|
|
123
|
+
if (needsDecimal) lines.push('from decimal import Decimal');
|
|
122
124
|
if (needsUUID) lines.push('from uuid import UUID');
|
|
123
125
|
|
|
124
126
|
// Collect public ops once — used both for TypedDict emission and method generation.
|
|
@@ -618,7 +620,7 @@ function getListItemType(type: ContractTypeNode, modelsWithInput?: Set<string>):
|
|
|
618
620
|
|
|
619
621
|
/**
|
|
620
622
|
* Collect all model names and scalar sentinels referenced in public operations.
|
|
621
|
-
* Sentinels: __datetime__, __date__, __time__, __uuid__, __any__
|
|
623
|
+
* Sentinels: __datetime__, __date__, __time__, __decimal__, __uuid__, __any__
|
|
622
624
|
*/
|
|
623
625
|
function collectReferencedModels(root: OpRootNode, modelsWithInput?: Set<string>, includeInternal = false): Set<string> {
|
|
624
626
|
const refs = new Set<string>();
|
|
@@ -672,6 +674,9 @@ function collectTypeRefs(type: ContractTypeNode, out: Set<string>, modelsWithInp
|
|
|
672
674
|
case 'datetime':
|
|
673
675
|
out.add('__datetime__');
|
|
674
676
|
break;
|
|
677
|
+
case 'decimal':
|
|
678
|
+
out.add('__decimal__');
|
|
679
|
+
break;
|
|
675
680
|
case 'uuid':
|
|
676
681
|
out.add('__uuid__');
|
|
677
682
|
break;
|
package/src/codegen-models.ts
CHANGED
|
@@ -128,6 +128,9 @@ function scanTypeImports(type: ContractTypeNode, imports: ImportTracker): void {
|
|
|
128
128
|
case 'duration':
|
|
129
129
|
imports.add('datetime', 'timedelta');
|
|
130
130
|
break;
|
|
131
|
+
case 'decimal':
|
|
132
|
+
imports.add('decimal', 'Decimal');
|
|
133
|
+
break;
|
|
131
134
|
case 'uuid':
|
|
132
135
|
imports.add('uuid', 'UUID');
|
|
133
136
|
break;
|
|
@@ -230,6 +233,8 @@ function renderScalar(name: ScalarTypeNode['name']): string {
|
|
|
230
233
|
return 'int';
|
|
231
234
|
case 'bigint':
|
|
232
235
|
return 'int';
|
|
236
|
+
case 'decimal':
|
|
237
|
+
return 'Decimal';
|
|
233
238
|
case 'boolean':
|
|
234
239
|
return 'bool';
|
|
235
240
|
case 'date':
|
|
@@ -28,10 +28,11 @@ describe('renderPyType', () => {
|
|
|
28
28
|
expect(renderPyType(scalarType('json'))).toBe('Any');
|
|
29
29
|
expect(renderPyType(scalarType('object'))).toBe('Any');
|
|
30
30
|
expect(renderPyType(scalarType('interval'))).toBe('str');
|
|
31
|
+
expect(renderPyType(scalarType('decimal'))).toBe('Decimal');
|
|
31
32
|
});
|
|
32
33
|
|
|
33
34
|
it('throws on an unmapped scalar name', () => {
|
|
34
|
-
expect(() => renderPyType({ kind: 'scalar', name: '
|
|
35
|
+
expect(() => renderPyType({ kind: 'scalar', name: 'quaternion' } as any)).toThrow(/unmapped scalar 'quaternion'/);
|
|
35
36
|
});
|
|
36
37
|
|
|
37
38
|
it('renders enum', () => {
|
|
@@ -251,6 +252,13 @@ describe('generatePydanticModels', () => {
|
|
|
251
252
|
expect(output).toContain('timeout: timedelta');
|
|
252
253
|
});
|
|
253
254
|
|
|
255
|
+
it('generates the Decimal import for decimal fields', () => {
|
|
256
|
+
const root = contractRoot([model('Payslip', [field('gross', scalarType('decimal'))])]);
|
|
257
|
+
const output = generatePydanticModels(root);
|
|
258
|
+
expect(output).toContain('from decimal import Decimal');
|
|
259
|
+
expect(output).toContain('gross: Decimal');
|
|
260
|
+
});
|
|
261
|
+
|
|
254
262
|
it('includes deprecation comment', () => {
|
|
255
263
|
const root = contractRoot([
|
|
256
264
|
model('OldModel', [field('id', scalarType('uuid'))], { deprecated: true }),
|