From 51c4f0f0620f51b819d10de8006d38aff4a5cbe7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 15 Aug 2026 20:45:55 +0200 Subject: [PATCH 1/2] Default the SDK version to the contract's info.version --- README.md | 2 +- README.zh-CN.md | 2 +- lib/config.ts | 3 +-- lib/generators/python.ts | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 47d2aa7..15566d6 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Edit `openapi.config.json` to use your local or HTTPS OpenAPI specification and } ``` -`source`, `name`, `apiKey.environment`, and the `python` `client`, `package`, `project`, and `version` keys are required; everything else is optional. `python.install` defaults to `pip install `, `python.readme` replaces the generated package README, `repository` fills the package URLs, and `docs.basePath` mounts the documentation under a sub-path. Relative paths resolve against the configuration file. The first OpenAPI server becomes the SDK's default base URL. HTTP bearer authentication and header-based API keys are derived from `components.securitySchemes`. +`source`, `name`, `apiKey.environment`, and the `python` `client`, `package`, and `project` keys are required; everything else is optional. `python.version` defaults to the contract's `info.version` so one bump in the API releases the SDK, `python.install` defaults to `pip install `, `python.readme` replaces the generated package README, `repository` fills the package URLs, and `docs.basePath` mounts the documentation under a sub-path. Relative paths resolve against the configuration file. The first OpenAPI server becomes the SDK's default base URL. HTTP bearer authentication and header-based API keys are derived from `components.securitySchemes`. Set `OPENAPI_CONFIG` to use a configuration outside this repository, such as a product-specific consumer: ```bash diff --git a/README.zh-CN.md b/README.zh-CN.md index 5b6cc87..07e60cd 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -50,7 +50,7 @@ Ultralytics OpenAPI 可从声明为 OpenAPI 3.0 至 3.2.0 的规范中读取 `GE } ``` -`source`、`name`、`apiKey.environment` 以及 `python` 中的 `client`、`package`、`project` 和 `version` 为必填项,其余均为可选。`python.install` 默认为 `pip install `,`python.readme` 会替换生成包的 README,`repository` 用于填充包的 URL,`docs.basePath` 可将文档挂载到子路径。相对路径相对于配置文件解析。第一个 OpenAPI 服务器将成为 SDK 的默认基础 URL。HTTP Bearer 认证和基于请求头的 API 密钥均派生自 `components.securitySchemes`。 +`source`、`name`、`apiKey.environment` 以及 `python` 中的 `client`、`package` 和 `project` 为必填项,其余均为可选。`python.version` 默认为契约的 `info.version`,因此在 API 中升版一次即可发布 SDK;`python.install` 默认为 `pip install `,`python.readme` 会替换生成包的 README,`repository` 用于填充包的 URL,`docs.basePath` 可将文档挂载到子路径。相对路径相对于配置文件解析。第一个 OpenAPI 服务器将成为 SDK 的默认基础 URL。HTTP Bearer 认证和基于请求头的 API 密钥均派生自 `components.securitySchemes`。 设置 `OPENAPI_CONFIG` 可使用此仓库之外的配置,例如产品专属的使用方配置: ```bash diff --git a/lib/config.ts b/lib/config.ts index 51599b0..044b07c 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -23,7 +23,7 @@ export interface OpenApiConfig { project: string; readme?: string; requiresPython?: string; - version: string; + version?: string; }; source: string; } @@ -38,7 +38,6 @@ export function getConfig(): OpenApiConfig { "python.client": config.python?.client, "python.package": config.python?.package, "python.project": config.python?.project, - "python.version": config.python?.version, source: config.source, }; const missing = Object.entries(required).find(([, value]) => !value)?.[0]; diff --git a/lib/generators/python.ts b/lib/generators/python.ts index 1584fa4..9b899b2 100644 --- a/lib/generators/python.ts +++ b/lib/generators/python.ts @@ -844,7 +844,7 @@ export async function generatePython( await Promise.all([ Bun.write( `${output}/pyproject.toml`, - `[build-system]\nrequires = ["uv_build>=0.12.3,<0.13"]\nbuild-backend = "uv_build"\n\n[project]\nname = "${config.python.project}"\nversion = "${config.python.version}"\n${projectMetadata}\nreadme = "README.md"\nlicense = "${license.id}"\nlicense-files = ["LICENSE"]\ndependencies = ["httpx>=0.28,<1"]${projectUrls}\n\n[tool.ruff]\nline-length = 120\n\n[tool.uv.build-backend]\nmodule-name = "${config.python.package}"\n`, + `[build-system]\nrequires = ["uv_build>=0.12.3,<0.13"]\nbuild-backend = "uv_build"\n\n[project]\nname = "${config.python.project}"\nversion = "${config.python.version ?? document.info.version}"\n${projectMetadata}\nreadme = "README.md"\nlicense = "${license.id}"\nlicense-files = ["LICENSE"]\ndependencies = ["httpx>=0.28,<1"]${projectUrls}\n\n[tool.ruff]\nline-length = 120\n\n[tool.uv.build-backend]\nmodule-name = "${config.python.package}"\n`, ), Bun.write(`${output}/README.md`, readme), Bun.write(`${output}/LICENSE`, licenseText), From f0763b4f80be982717b3a7a86dc395c7826f7dca Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 15 Aug 2026 20:49:18 +0200 Subject: [PATCH 2/2] Require a valid Python package version when defaulting from the contract --- lib/generators/python.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/generators/python.ts b/lib/generators/python.ts index 9b899b2..d2c2caf 100644 --- a/lib/generators/python.ts +++ b/lib/generators/python.ts @@ -811,6 +811,10 @@ export async function generatePython( output: string, ): Promise { const resources = prepare(document); + const version = config.python.version ?? document.info.version; + if (!/^\d+(\.\d+)*((a|b|rc)\d+)?(\.post\d+)?(\.dev\d+)?$/.test(version)) { + throw new Error(`Set python.version: contract version "${version}" is not a valid Python package version`); + } const root = `${output}/src/${config.python.package}`; const baseUrl = resolveServerUrl(document); const readmeExample = [...resources] @@ -844,7 +848,7 @@ export async function generatePython( await Promise.all([ Bun.write( `${output}/pyproject.toml`, - `[build-system]\nrequires = ["uv_build>=0.12.3,<0.13"]\nbuild-backend = "uv_build"\n\n[project]\nname = "${config.python.project}"\nversion = "${config.python.version ?? document.info.version}"\n${projectMetadata}\nreadme = "README.md"\nlicense = "${license.id}"\nlicense-files = ["LICENSE"]\ndependencies = ["httpx>=0.28,<1"]${projectUrls}\n\n[tool.ruff]\nline-length = 120\n\n[tool.uv.build-backend]\nmodule-name = "${config.python.package}"\n`, + `[build-system]\nrequires = ["uv_build>=0.12.3,<0.13"]\nbuild-backend = "uv_build"\n\n[project]\nname = "${config.python.project}"\nversion = "${version}"\n${projectMetadata}\nreadme = "README.md"\nlicense = "${license.id}"\nlicense-files = ["LICENSE"]\ndependencies = ["httpx>=0.28,<1"]${projectUrls}\n\n[tool.ruff]\nline-length = 120\n\n[tool.uv.build-backend]\nmodule-name = "${config.python.package}"\n`, ), Bun.write(`${output}/README.md`, readme), Bun.write(`${output}/LICENSE`, licenseText),