@contractkit/plugin-python 0.9.4 → 0.10.1

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.
@@ -1,9 +1,9 @@
1
1
 
2
- > @contractkit/plugin-python@0.9.4 build:ci /home/runner/work/ContractKit/ContractKit/packages/plugin-python
2
+ > @contractkit/plugin-python@0.10.1 build:ci /home/runner/work/ContractKit/ContractKit/packages/plugin-python
3
3
  > eslint --max-warnings=0 && pnpm run build
4
4
 
5
5
 
6
- > @contractkit/plugin-python@0.9.4 build /home/runner/work/ContractKit/ContractKit/packages/plugin-python
6
+ > @contractkit/plugin-python@0.10.1 build /home/runner/work/ContractKit/ContractKit/packages/plugin-python
7
7
  > tsup src/index.ts --format esm --sourcemap --dts && tsc --emitDeclarationOnly --declaration
8
8
 
9
9
  CLI Building entry: src/index.ts
@@ -11,9 +11,9 @@
11
11
  CLI tsup v8.5.1
12
12
  CLI Target: esnext
13
13
  ESM Build start
14
- ESM dist/index.js 36.84 KB
15
- ESM dist/index.js.map 76.54 KB
16
- ESM ⚡️ Build success in 184ms
14
+ ESM dist/index.js 42.33 KB
15
+ ESM dist/index.js.map 89.19 KB
16
+ ESM ⚡️ Build success in 192ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 4343ms
19
- DTS dist/index.d.ts 801.00 B
18
+ DTS ⚡️ Build success in 3797ms
19
+ DTS dist/index.d.ts 1.10 KB
@@ -1,18 +1,18 @@
1
1
 
2
- > @contractkit/plugin-python@0.9.4 test:ci /home/runner/work/ContractKit/ContractKit/packages/plugin-python
2
+ > @contractkit/plugin-python@0.10.1 test:ci /home/runner/work/ContractKit/ContractKit/packages/plugin-python
3
3
  > vitest run --coverage
4
4
 
5
5
 
6
6
   RUN  v4.1.5 /home/runner/work/ContractKit/ContractKit/packages/plugin-python
7
7
  Coverage enabled with v8
8
8
 
9
- ✓ tests/codegen-models.test.ts (32 tests) 130ms
10
- ✓ tests/codegen-client.test.ts (27 tests) 63ms
9
+ ✓ tests/codegen-client.test.ts (27 tests) 94ms
10
+ ✓ tests/codegen-models.test.ts (32 tests) 116ms
11
11
 
12
12
   Test Files  2 passed (2)
13
13
   Tests  59 passed (59)
14
-  Start at  12:37:07
15
-  Duration  4.97s (transform 1.83s, setup 0ms, import 7.12s, tests 193ms, environment 0ms)
14
+  Start at  11:16:36
15
+  Duration  5.14s (transform 2.46s, setup 0ms, import 7.24s, tests 210ms, environment 0ms)
16
16
 
17
17
   % Coverage report from v8
18
18
  -------------------|---------|----------|---------|---------|-------------------
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @contractkit/contractkit-plugin-python
2
2
 
3
+ ## 0.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [130d53b]
8
+ - @contractkit/core@0.15.1
9
+
10
+ ## 0.10.0
11
+
12
+ ### Minor Changes
13
+
14
+ - 10ca07b: Add per-output incremental caching to the Bruno, Python, and TypeScript plugins. Editing a single contract or operation no longer regenerates every output file — only the units whose transitive inputs actually changed are re-rendered, with the rest reused from a per-plugin manifest. `@contractkit/core` exposes the shared utility (`runIncrementalCodegen`, `parseIncrementalManifest`, `hashFingerprint`, `collectTransitiveModelRefs`, manifest types) for plugin authors. `PluginContext` gains a `cacheEnabled` flag so plugins can honor `--force` / `cache: false`.
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [10ca07b]
19
+ - @contractkit/core@0.15.0
20
+
3
21
  ## 0.9.4
4
22
 
5
23
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <coverage generated="1778071032453" clover="3.2.0">
3
- <project timestamp="1778071032453" name="All files">
2
+ <coverage generated="1778152601456" clover="3.2.0">
3
+ <project timestamp="1778152601456" name="All files">
4
4
  <metrics statements="538" coveredstatements="456" conditionals="416" coveredconditionals="320" methods="91" coveredmethods="78" elements="1045" coveredelements="854" complexity="0" loc="538" ncloc="538" packages="2" files="3" classes="3"/>
5
5
  <package name="src">
6
6
  <metrics statements="500" coveredstatements="421" conditionals="385" coveredconditionals="297" methods="66" coveredmethods="55"/>
@@ -116,7 +116,7 @@
116
116
  <div class='footer quiet pad2 space-top1 center small'>
117
117
  Code coverage generated by
118
118
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
119
- at 2026-05-06T12:37:12.412Z
119
+ at 2026-05-07T11:16:41.420Z
120
120
  </div>
121
121
  <script src="prettify.js"></script>
122
122
  <script>
@@ -2056,7 +2056,7 @@ class BaseClient:
2056
2056
  <div class='footer quiet pad2 space-top1 center small'>
2057
2057
  Code coverage generated by
2058
2058
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
2059
- at 2026-05-06T12:37:12.412Z
2059
+ at 2026-05-07T11:16:41.420Z
2060
2060
  </div>
2061
2061
  <script src="../prettify.js"></script>
2062
2062
  <script>
@@ -1345,7 +1345,7 @@ export function deriveModelsModuleName(file: string): string {
1345
1345
  <div class='footer quiet pad2 space-top1 center small'>
1346
1346
  Code coverage generated by
1347
1347
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1348
- at 2026-05-06T12:37:12.412Z
1348
+ at 2026-05-07T11:16:41.420Z
1349
1349
  </div>
1350
1350
  <script src="../prettify.js"></script>
1351
1351
  <script>
@@ -116,7 +116,7 @@
116
116
  <div class='footer quiet pad2 space-top1 center small'>
117
117
  Code coverage generated by
118
118
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
119
- at 2026-05-06T12:37:12.412Z
119
+ at 2026-05-07T11:16:41.420Z
120
120
  </div>
121
121
  <script src="../prettify.js"></script>
122
122
  <script>
@@ -652,7 +652,7 @@ export function opRoot(routes: OpRouteNode[], file = 'payments.op.ck', meta: Rec
652
652
  <div class='footer quiet pad2 space-top1 center small'>
653
653
  Code coverage generated by
654
654
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
655
- at 2026-05-06T12:37:12.412Z
655
+ at 2026-05-07T11:16:41.420Z
656
656
  </div>
657
657
  <script src="../prettify.js"></script>
658
658
  <script>
@@ -101,7 +101,7 @@
101
101
  <div class='footer quiet pad2 space-top1 center small'>
102
102
  Code coverage generated by
103
103
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
104
- at 2026-05-06T12:37:12.412Z
104
+ at 2026-05-07T11:16:41.420Z
105
105
  </div>
106
106
  <script src="../prettify.js"></script>
107
107
  <script>
package/dist/index.d.ts CHANGED
@@ -11,6 +11,13 @@ export interface PythonSdkPluginConfig {
11
11
  */
12
12
  includeInternal?: boolean;
13
13
  }
14
+ /**
15
+ * Bumped when the Python codegen output shape changes in a way that should
16
+ * invalidate every per-file fingerprint. Mixed into the manifest's
17
+ * `codegenVersion`, so a plugin upgrade forces full regeneration even when no
18
+ * `.ck` files have changed.
19
+ */
20
+ export declare const PYTHON_CODEGEN_VERSION = "1";
14
21
  declare const plugin: ContractKitPlugin;
15
22
  export default plugin;
16
23
  export declare function createPythonSdkPlugin(config: PythonSdkPluginConfig, rootDir: string): ContractKitPlugin;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAW3D,MAAM,WAAW,qBAAqB;IAClC,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAID,QAAA,MAAM,MAAM,EAAE,iBAOb,CAAC;AAEF,eAAe,MAAM,CAAC;AAItB,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAsGvG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,iBAAiB,EAOpB,MAAM,mBAAmB,CAAC;AAmB3B,MAAM,WAAW,qBAAqB;IAClC,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAI1C,QAAA,MAAM,MAAM,EAAE,iBAMb,CAAC;AAEF,eAAe,MAAM,CAAC;AAEtB,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAOvG"}
package/dist/index.js CHANGED
@@ -2,7 +2,9 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
4
  // src/index.ts
5
- import { resolve, join } from "path";
5
+ import { resolve, join, relative } from "path";
6
+ import { existsSync, readFileSync, rmSync, readdirSync, rmdirSync } from "fs";
7
+ import { runIncrementalCodegen, parseIncrementalManifest, emptyIncrementalManifest, hashFingerprint, collectTransitiveModelRefs, collectTypeRefs as collectTypeRefs2 } from "@contractkit/core";
6
8
 
7
9
  // src/codegen-models.ts
8
10
  import { computeModelsWithInput, topoSortModels, collectExternalRefs, collectExternalInputRefs } from "@contractkit/core";
@@ -943,103 +945,286 @@ class BaseClient:
943
945
  `;
944
946
 
945
947
  // src/index.ts
948
+ var PYTHON_CODEGEN_VERSION = "1";
949
+ var MANIFEST_FILENAME = ".contractkit-python-manifest.json";
946
950
  var plugin = {
947
951
  name: "python-sdk",
948
- cacheKey: "python-sdk",
949
952
  async generateTargets(inputs, ctx) {
950
953
  const config = ctx.options;
951
- return createPythonSdkPlugin(config, ctx.rootDir).generateTargets(inputs, ctx);
954
+ await runPythonCodegen(inputs, ctx, config, ctx.rootDir);
952
955
  }
953
956
  };
954
957
  var index_default = plugin;
955
958
  function createPythonSdkPlugin(config, rootDir) {
956
959
  return {
957
960
  name: "python-sdk",
958
- cacheKey: `python-sdk:${JSON.stringify(config)}`,
959
- async generateTargets({ contractRoots, opRoots, modelsWithInput: _modelsWithInput }, ctx) {
960
- const modelsWithInput = _modelsWithInput;
961
- const outDir = resolve(rootDir, config.baseDir ?? "python-sdk");
962
- const modelModulePaths = /* @__PURE__ */ new Map();
963
- const contractEntries = [];
964
- for (const contractRoot of contractRoots) {
965
- const moduleName = deriveModelsModuleName(contractRoot.file);
966
- const outPath = join(outDir, `${moduleName}.py`);
967
- contractEntries.push({
968
- moduleName,
969
- outPath,
970
- root: contractRoot
971
- });
972
- for (const model of contractRoot.models) {
973
- modelModulePaths.set(model.name, `.${moduleName}`);
974
- if (modelsWithInput.has(model.name)) {
975
- modelModulePaths.set(`${model.name}Input`, `.${moduleName}`);
976
- }
977
- }
978
- }
979
- for (const { moduleName, outPath, root } of contractEntries) {
980
- const content = generatePydanticModels(root, {
981
- modelModulePaths,
982
- currentModule: `.${moduleName}`,
983
- modelsWithInput
984
- });
985
- ctx.emitFile(outPath, content);
961
+ async generateTargets(inputs, ctx) {
962
+ await runPythonCodegen(inputs, ctx, config, rootDir);
963
+ }
964
+ };
965
+ }
966
+ __name(createPythonSdkPlugin, "createPythonSdkPlugin");
967
+ async function runPythonCodegen(inputs, ctx, config, rootDir) {
968
+ const { contractRoots, opRoots } = inputs;
969
+ const modelsWithInput = inputs.modelsWithInput;
970
+ const outDir = resolve(rootDir, config.baseDir ?? "python-sdk");
971
+ const modelModulePaths = /* @__PURE__ */ new Map();
972
+ const modelMap = /* @__PURE__ */ new Map();
973
+ const contractEntries = [];
974
+ for (const root of contractRoots) {
975
+ const moduleName = deriveModelsModuleName(root.file);
976
+ contractEntries.push({
977
+ moduleName,
978
+ relPath: `${moduleName}.py`,
979
+ root
980
+ });
981
+ for (const model of root.models) {
982
+ modelMap.set(model.name, model);
983
+ modelModulePaths.set(model.name, `.${moduleName}`);
984
+ if (modelsWithInput.has(model.name)) {
985
+ modelModulePaths.set(`${model.name}Input`, `.${moduleName}`);
986
986
  }
987
- const clientInfos = [];
988
- for (const opRoot of opRoots) {
989
- if (!hasPublicOperations(opRoot, config.includeInternal)) continue;
990
- const moduleName = deriveClientModuleName(opRoot.file);
991
- const outPath = join(outDir, `${moduleName}.py`);
992
- clientInfos.push({
993
- moduleName,
994
- className: deriveClientClassName(opRoot.file),
995
- propertyName: deriveClientPropertyName(opRoot.file)
996
- });
997
- ctx.emitFile(outPath, generatePythonClient(opRoot, {
998
- modelModulePaths,
999
- currentModule: `.${moduleName}`,
1000
- modelsWithInput,
1001
- includeInternal: config.includeInternal
1002
- }));
987
+ }
988
+ }
989
+ const modelsWithInputArray = [
990
+ ...modelsWithInput
991
+ ].sort();
992
+ const prevManifest = ctx.cacheEnabled ? readManifest(outDir) : emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);
993
+ const units = [];
994
+ for (const { moduleName, relPath, root } of contractEntries) {
995
+ const ownNames = new Set(root.models.map((m) => m.name));
996
+ const externalRefs = collectExternalRefsFromContract(root, ownNames);
997
+ const referencedModulePaths = {};
998
+ for (const ref of [
999
+ ...externalRefs
1000
+ ].sort()) {
1001
+ const path = modelModulePaths.get(ref);
1002
+ if (path) referencedModulePaths[ref] = path;
1003
+ const inputPath = modelModulePaths.get(`${ref}Input`);
1004
+ if (inputPath) referencedModulePaths[`${ref}Input`] = inputPath;
1005
+ }
1006
+ const relevantInputModels = modelsWithInputArray.filter((name) => ownNames.has(name) || externalRefs.has(name));
1007
+ const fingerprint = hashFingerprint({
1008
+ kind: "models",
1009
+ v: PYTHON_CODEGEN_VERSION,
1010
+ relPath,
1011
+ currentModule: `.${moduleName}`,
1012
+ root,
1013
+ referencedModulePaths,
1014
+ modelsWithInput: relevantInputModels
1015
+ });
1016
+ units.push({
1017
+ key: `models::${relPath}`,
1018
+ fingerprint,
1019
+ render: /* @__PURE__ */ __name(() => [
1020
+ {
1021
+ relativePath: relPath,
1022
+ content: generatePydanticModels(root, {
1023
+ modelModulePaths,
1024
+ currentModule: `.${moduleName}`,
1025
+ modelsWithInput
1026
+ })
1027
+ }
1028
+ ], "render")
1029
+ });
1030
+ }
1031
+ const clientInfos = [];
1032
+ for (const root of opRoots) {
1033
+ if (!hasPublicOperations(root, config.includeInternal)) continue;
1034
+ const moduleName = deriveClientModuleName(root.file);
1035
+ const relPath = `${moduleName}.py`;
1036
+ clientInfos.push({
1037
+ moduleName,
1038
+ className: deriveClientClassName(root.file),
1039
+ propertyName: deriveClientPropertyName(root.file)
1040
+ });
1041
+ const referencedModels = collectOpRootModelRefs(root, modelMap);
1042
+ const referencedModulePaths = {};
1043
+ for (const ref of [
1044
+ ...referencedModels
1045
+ ].sort()) {
1046
+ const path = modelModulePaths.get(ref);
1047
+ if (path) referencedModulePaths[ref] = path;
1048
+ const inputPath = modelModulePaths.get(`${ref}Input`);
1049
+ if (inputPath) referencedModulePaths[`${ref}Input`] = inputPath;
1050
+ }
1051
+ const relevantInputModels = modelsWithInputArray.filter((name) => referencedModels.has(name));
1052
+ const fingerprint = hashFingerprint({
1053
+ kind: "client",
1054
+ v: PYTHON_CODEGEN_VERSION,
1055
+ relPath,
1056
+ currentModule: `.${moduleName}`,
1057
+ root,
1058
+ referencedModulePaths,
1059
+ modelsWithInput: relevantInputModels,
1060
+ includeInternal: config.includeInternal ?? false
1061
+ });
1062
+ units.push({
1063
+ key: `client::${relPath}`,
1064
+ fingerprint,
1065
+ render: /* @__PURE__ */ __name(() => [
1066
+ {
1067
+ relativePath: relPath,
1068
+ content: generatePythonClient(root, {
1069
+ modelModulePaths,
1070
+ currentModule: `.${moduleName}`,
1071
+ modelsWithInput,
1072
+ includeInternal: config.includeInternal
1073
+ })
1074
+ }
1075
+ ], "render")
1076
+ });
1077
+ }
1078
+ const sdkClassName = config.packageName ? config.packageName.split(/[-._\s]+/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("") + "Sdk" : "Sdk";
1079
+ const initLines = [
1080
+ "# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.",
1081
+ "from ._base_client import BaseClient, SdkError"
1082
+ ];
1083
+ for (const c of clientInfos) {
1084
+ initLines.push(`from .${c.moduleName} import ${c.className}`);
1085
+ }
1086
+ initLines.push("");
1087
+ initLines.push("");
1088
+ if (clientInfos.length > 0) {
1089
+ initLines.push(`class ${sdkClassName}(BaseClient):`);
1090
+ initLines.push(` def __init__(self, base_url: str, headers: dict[str, str] | None = None):`);
1091
+ initLines.push(` super().__init__(base_url, headers)`);
1092
+ for (const c of clientInfos) {
1093
+ initLines.push(` self.${c.propertyName} = ${c.className}(base_url, headers)`);
1094
+ }
1095
+ initLines.push("");
1096
+ } else {
1097
+ initLines.push(`class ${sdkClassName}(BaseClient):`);
1098
+ initLines.push(` pass`);
1099
+ initLines.push("");
1100
+ }
1101
+ const allNames = [
1102
+ "BaseClient",
1103
+ "SdkError",
1104
+ sdkClassName,
1105
+ ...clientInfos.map((c) => c.className)
1106
+ ];
1107
+ initLines.push(`__all__ = [${allNames.map((n) => JSON.stringify(n)).join(", ")}]`);
1108
+ initLines.push("");
1109
+ const globalFiles = [
1110
+ {
1111
+ relativePath: "_base_client.py",
1112
+ content: BASE_CLIENT_PY
1113
+ },
1114
+ {
1115
+ relativePath: "requirements.txt",
1116
+ content: "httpx\npydantic>=2.0\n"
1117
+ },
1118
+ {
1119
+ relativePath: "__init__.py",
1120
+ content: initLines.join("\n")
1121
+ }
1122
+ ];
1123
+ const result = runIncrementalCodegen({
1124
+ codegenVersion: PYTHON_CODEGEN_VERSION,
1125
+ manifestFilename: MANIFEST_FILENAME,
1126
+ prevManifest,
1127
+ globalFiles,
1128
+ units,
1129
+ fileExists: /* @__PURE__ */ __name((relPath) => existsSync(resolve(outDir, relPath)), "fileExists")
1130
+ });
1131
+ deleteStalePaths(outDir, result.deletedPaths);
1132
+ for (const { relativePath, content } of result.filesToWrite) {
1133
+ ctx.emitFile(resolve(outDir, relativePath), content);
1134
+ }
1135
+ void relative;
1136
+ }
1137
+ __name(runPythonCodegen, "runPythonCodegen");
1138
+ function collectExternalRefsFromContract(root, ownNames) {
1139
+ const refs = /* @__PURE__ */ new Set();
1140
+ for (const m of root.models) {
1141
+ if (m.type) collectTypeRefs2(m.type, refs);
1142
+ for (const f of m.fields) collectTypeRefs2(f.type, refs);
1143
+ if (m.bases) {
1144
+ for (const b of m.bases) refs.add(b);
1145
+ }
1146
+ }
1147
+ for (const own of ownNames) refs.delete(own);
1148
+ return refs;
1149
+ }
1150
+ __name(collectExternalRefsFromContract, "collectExternalRefsFromContract");
1151
+ function collectOpRootModelRefs(root, modelMap) {
1152
+ const seeds = [];
1153
+ for (const route of root.routes) {
1154
+ if (route.params) seeds.push(...paramSourceTypes(route.params));
1155
+ for (const op of route.operations) {
1156
+ if (op.query) seeds.push(...paramSourceTypes(op.query));
1157
+ if (op.headers) seeds.push(...paramSourceTypes(op.headers));
1158
+ if (op.request) {
1159
+ for (const body of op.request.bodies) seeds.push(body.bodyType);
1003
1160
  }
1004
- ctx.emitFile(join(outDir, "_base_client.py"), BASE_CLIENT_PY);
1005
- ctx.emitFile(join(outDir, "requirements.txt"), "httpx\npydantic>=2.0\n");
1006
- const sdkClassName = config.packageName ? config.packageName.split(/[-._\s]+/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("") + "Sdk" : "Sdk";
1007
- const initLines = [
1008
- "# Auto-generated by contractkit-plugin-python-sdk. Do not edit manually.",
1009
- "from ._base_client import BaseClient, SdkError"
1010
- ];
1011
- for (const c of clientInfos) {
1012
- initLines.push(`from .${c.moduleName} import ${c.className}`);
1161
+ for (const resp of op.responses) {
1162
+ if (resp.bodyType) seeds.push(resp.bodyType);
1163
+ if (resp.headers) {
1164
+ for (const h of resp.headers) seeds.push(h.type);
1165
+ }
1013
1166
  }
1014
- initLines.push("");
1015
- initLines.push("");
1016
- if (clientInfos.length > 0) {
1017
- initLines.push(`class ${sdkClassName}(BaseClient):`);
1018
- initLines.push(` def __init__(self, base_url: str, headers: dict[str, str] | None = None):`);
1019
- initLines.push(` super().__init__(base_url, headers)`);
1020
- for (const c of clientInfos) {
1021
- initLines.push(` self.${c.propertyName} = ${c.className}(base_url, headers)`);
1167
+ }
1168
+ }
1169
+ return collectTransitiveModelRefs(seeds, modelMap);
1170
+ }
1171
+ __name(collectOpRootModelRefs, "collectOpRootModelRefs");
1172
+ function paramSourceTypes(src) {
1173
+ const out = [];
1174
+ if (src.kind === "params") {
1175
+ for (const n of src.nodes) out.push(n.type);
1176
+ } else if (src.kind === "ref") {
1177
+ out.push({
1178
+ kind: "ref",
1179
+ name: src.name
1180
+ });
1181
+ } else if (src.kind === "type") {
1182
+ out.push(src.node);
1183
+ }
1184
+ return out;
1185
+ }
1186
+ __name(paramSourceTypes, "paramSourceTypes");
1187
+ function readManifest(outDir) {
1188
+ const manifestPath = resolve(outDir, MANIFEST_FILENAME);
1189
+ if (!existsSync(manifestPath)) return emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);
1190
+ try {
1191
+ return parseIncrementalManifest(readFileSync(manifestPath, "utf-8"));
1192
+ } catch {
1193
+ return emptyIncrementalManifest(PYTHON_CODEGEN_VERSION);
1194
+ }
1195
+ }
1196
+ __name(readManifest, "readManifest");
1197
+ function deleteStalePaths(outDir, relPaths) {
1198
+ if (relPaths.length === 0) return;
1199
+ const removedDirs = /* @__PURE__ */ new Set();
1200
+ for (const rel of relPaths) {
1201
+ const abs = resolve(outDir, rel);
1202
+ if (existsSync(abs)) {
1203
+ rmSync(abs, {
1204
+ force: true
1205
+ });
1206
+ removedDirs.add(join(abs, ".."));
1207
+ }
1208
+ }
1209
+ for (const dir of removedDirs) {
1210
+ let current = dir;
1211
+ while (current.startsWith(outDir) && current !== outDir) {
1212
+ try {
1213
+ if (readdirSync(current).length === 0) {
1214
+ rmdirSync(current);
1215
+ current = join(current, "..");
1216
+ } else {
1217
+ break;
1022
1218
  }
1023
- initLines.push("");
1024
- } else {
1025
- initLines.push(`class ${sdkClassName}(BaseClient):`);
1026
- initLines.push(` pass`);
1027
- initLines.push("");
1219
+ } catch {
1220
+ break;
1028
1221
  }
1029
- const allNames = [
1030
- "BaseClient",
1031
- "SdkError",
1032
- sdkClassName,
1033
- ...clientInfos.map((c) => c.className)
1034
- ];
1035
- initLines.push(`__all__ = [${allNames.map((n) => JSON.stringify(n)).join(", ")}]`);
1036
- initLines.push("");
1037
- ctx.emitFile(join(outDir, "__init__.py"), initLines.join("\n"));
1038
1222
  }
1039
- };
1223
+ }
1040
1224
  }
1041
- __name(createPythonSdkPlugin, "createPythonSdkPlugin");
1225
+ __name(deleteStalePaths, "deleteStalePaths");
1042
1226
  export {
1227
+ PYTHON_CODEGEN_VERSION,
1043
1228
  createPythonSdkPlugin,
1044
1229
  index_default as default
1045
1230
  };