From 766ef58ded15fb68c6329e5763c0fac20a1fb469 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 03:12:42 +0000 Subject: [PATCH 1/5] ci: remove hardcoded version from _version.py, use importlib.metadata Rewrites _version.py to resolve __version__ from installed package metadata (set at build time by uv-dynamic-versioning from the git tag) instead of hardcoding it. This matches the PyAirbyte pattern. Adds _version.py to .genignore so Speakeasy won't overwrite it with a hardcoded version on regeneration. Co-Authored-By: AJ Steers --- .genignore | 1 + src/airbyte_api/_version.py | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.genignore b/.genignore index cc736a36..c1bf5971 100644 --- a/.genignore +++ b/.genignore @@ -1 +1,2 @@ pyproject.toml +src/airbyte_api/_version.py diff --git a/src/airbyte_api/_version.py b/src/airbyte_api/_version.py index f8a8ca6e..f90adbb0 100644 --- a/src/airbyte_api/_version.py +++ b/src/airbyte_api/_version.py @@ -1,15 +1,22 @@ -"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" +"""Runtime version and Speakeasy generation metadata. + +__version__ is resolved from installed package metadata (set at build time +by uv-dynamic-versioning from the git tag). The remaining constants are +Speakeasy generation metadata updated on each regeneration. +""" import importlib.metadata __title__: str = "airbyte-api" -__version__: str = "1.0.0" -__openapi_doc_version__: str = "1.0.0" -__gen_version__: str = "2.911.0" -__user_agent__: str = "speakeasy-sdk/python 1.0.0 2.911.0 1.0.0 airbyte-api" try: - if __package__ is not None: - __version__ = importlib.metadata.version(__package__) + __version__: str = importlib.metadata.version(__title__) except importlib.metadata.PackageNotFoundError: - pass + __version__ = "0.0.0" + +__openapi_doc_version__: str = "1.0.0" +__gen_version__: str = "2.911.0" +__user_agent__: str = ( + f"speakeasy-sdk/python {__version__} {__gen_version__}" + f" {__openapi_doc_version__} {__title__}" +) From 5716852ab36d4d8b12cc605d366703045c2979be Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 03:31:45 +0000 Subject: [PATCH 2/5] ci: use post_generate.py to replace hardcoded __version__ with importlib.metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of .genignore (which prevents Speakeasy from updating generation metadata), let Speakeasy generate _version.py normally and then post_generate.py surgically replaces: - __version__: str = "X.Y.Z" → importlib.metadata.version(__title__) - __user_agent__ static string → f-string using dynamic version - Removes the stale try/except fallback block Generation metadata (__openapi_doc_version__, __gen_version__) stays intact and gets updated on each Speakeasy regeneration. Co-Authored-By: AJ Steers --- .genignore | 1 - scripts/post_generate.py | 73 +++++++++++++++++++++++++++++++++---- src/airbyte_api/_version.py | 15 ++------ 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/.genignore b/.genignore index c1bf5971..cc736a36 100644 --- a/.genignore +++ b/.genignore @@ -1,2 +1 @@ pyproject.toml -src/airbyte_api/_version.py diff --git a/scripts/post_generate.py b/scripts/post_generate.py index 47788292..4d2dbdad 100644 --- a/scripts/post_generate.py +++ b/scripts/post_generate.py @@ -1,15 +1,74 @@ -"""Post-generation patch pipeline (no-op placeholder). +"""Post-generation patch pipeline. -This script runs after Speakeasy code generation to apply any -Python SDK-specific patches. Currently no patches are needed. - -Add patch functions here when durable fixes to generated code are required. -See the terraform-provider-airbyte repo for examples of post-generation patches. +Runs after Speakeasy code generation to apply durable fixes to generated code. +See the terraform-provider-airbyte repo for more examples of post-generation patches. """ +import re +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +VERSION_FILE = REPO_ROOT / "src" / "airbyte_api" / "_version.py" + + +def patch_version_file() -> None: + """Replace the hardcoded `__version__` in `_version.py` with a dynamic lookup. + + Speakeasy generates a `_version.py` with a hardcoded `__version__` string + and a static `__user_agent__`. This patch rewrites both so that the + installed package version (set at build time by `uv-dynamic-versioning` + from the git tag) is used instead. Generation metadata + (`__openapi_doc_version__`, `__gen_version__`) is left intact. + """ + text = VERSION_FILE.read_text() + original = text + + # 1. Replace the hardcoded __version__ assignment with importlib.metadata lookup. + # Matches: __version__: str = "1.0.0" (any semver-ish string) + text = re.sub( + r'^__version__: str = ".*"$', + "__version__: str = importlib.metadata.version(__title__)", + text, + count=1, + flags=re.MULTILINE, + ) + + # 2. Replace the static __user_agent__ string with an f-string using the + # dynamic __version__. + # Matches: __user_agent__: str = "speakeasy-sdk/python 1.0.0 2.911.0 1.0.0 airbyte-api" + text = re.sub( + r'^__user_agent__: str = "speakeasy-sdk/python .+"$', + ( + "__user_agent__: str = (\n" + ' f"speakeasy-sdk/python {__version__} {__gen_version__}"\n' + ' f" {__openapi_doc_version__} {__title__}"\n' + ")" + ), + text, + count=1, + flags=re.MULTILINE, + ) + + # 3. Remove the stale try/except block that attempted to override __version__ + # at runtime (no longer needed since the assignment itself is now dynamic). + text = re.sub( + r"\ntry:\n if __package__.*?\nexcept.*?\n pass\n", + "\n", + text, + count=1, + flags=re.DOTALL, + ) + + if text == original: + print("post_generate: _version.py already patched (no changes)") + return + + VERSION_FILE.write_text(text) + print("post_generate: patched _version.py (hardcoded __version__ → importlib.metadata)") + def main() -> None: - print("post_generate: no patches to apply (no-op)") + patch_version_file() if __name__ == "__main__": diff --git a/src/airbyte_api/_version.py b/src/airbyte_api/_version.py index f90adbb0..1a6ddc25 100644 --- a/src/airbyte_api/_version.py +++ b/src/airbyte_api/_version.py @@ -1,22 +1,13 @@ -"""Runtime version and Speakeasy generation metadata. - -__version__ is resolved from installed package metadata (set at build time -by uv-dynamic-versioning from the git tag). The remaining constants are -Speakeasy generation metadata updated on each regeneration. -""" +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" import importlib.metadata __title__: str = "airbyte-api" - -try: - __version__: str = importlib.metadata.version(__title__) -except importlib.metadata.PackageNotFoundError: - __version__ = "0.0.0" - +__version__: str = importlib.metadata.version(__title__) __openapi_doc_version__: str = "1.0.0" __gen_version__: str = "2.911.0" __user_agent__: str = ( f"speakeasy-sdk/python {__version__} {__gen_version__}" f" {__openapi_doc_version__} {__title__}" ) + From 9ce4ee949d2f5b2c1fd5a2d1dd3c7a5cf8d95450 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 03:36:39 +0000 Subject: [PATCH 3/5] refactor: convert post_generate to standalone uv script (.uv extension) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renames post_generate.py → post_generate.uv with PEP 723 inline metadata and uv shebang. Updates all references in poe_tasks.toml, AGENTS.md, and CONTRIBUTING.md. Co-Authored-By: AJ Steers --- AGENTS.md | 2 +- CONTRIBUTING.md | 8 ++++---- poe_tasks.toml | 2 +- scripts/{post_generate.py => post_generate.uv} | 5 +++++ 4 files changed, 11 insertions(+), 6 deletions(-) rename scripts/{post_generate.py => post_generate.uv} (95%) mode change 100644 => 100755 diff --git a/AGENTS.md b/AGENTS.md index 6c037b99..7ee5276c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ Do not guess or iterate blindly. Download the artifact first. ## Files You Can Safely Edit - `overlays/python_speakeasy.yaml` — Speakeasy overlay -- `scripts/post_generate.py` — Post-generation patch script +- `scripts/post_generate.uv` — Post-generation patch script (standalone uv script) - `poe_tasks.toml` — Build task definitions - `.github/workflows/` — CI workflows - `.github/dependabot.yml` — Dependabot configuration diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 845e7b08..ae59b4d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ The Python SDK is generated through a multi-step pipeline: ▼ ┌──────────────────────────────────────────┐ │ 4. Post-Generation Patches │ -│ (scripts/post_generate.py) │ +│ (scripts/post_generate.uv) │ └──────────────────┬───────────────────────┘ │ ▼ @@ -49,15 +49,15 @@ The Python SDK is generated through a multi-step pipeline: 3. **Speakeasy Code Generation** — Speakeasy consumes the spec (+ overlay if enabled) and generates the Python SDK in `src/airbyte_api/`. These files should never be edited by hand. -4. **Post-Generation Patches** — A Python script applies any SDK-specific patches after generation (currently a no-op placeholder): - [`scripts/post_generate.py`](https://github.com/airbytehq/airbyte-api-python-sdk/blob/main/scripts/post_generate.py) +4. **Post-Generation Patches** — A standalone uv script applies SDK-specific patches after generation (e.g. replacing the hardcoded `__version__` with `importlib.metadata`): + [`scripts/post_generate.uv`](https://github.com/airbytehq/airbyte-api-python-sdk/blob/main/scripts/post_generate.uv) 5. **Package Build & Publish** — The generated SDK is built with `uv build` and published to PyPI via OIDC trusted publishing. > **Tip:** If you need to change SDK behavior, determine which layer is appropriate: > - **API changes** → submit to the [upstream OpenAPI spec](https://github.com/airbytehq/airbyte-platform/blob/main/airbyte-api/server-api/src/main/openapi/api_sdk.yaml) > - **Python SDK-specific schema tweaks** → modify the [overlay](https://github.com/airbytehq/airbyte-api-python-sdk/blob/main/overlays/python_speakeasy.yaml) -> - **Post-generation fixes** → modify the [post-generate script](https://github.com/airbytehq/airbyte-api-python-sdk/blob/main/scripts/post_generate.py) +> - **Post-generation fixes** → modify the [post-generate script](https://github.com/airbytehq/airbyte-api-python-sdk/blob/main/scripts/post_generate.uv) > - Then trigger regeneration (see below) ## For Maintainers diff --git a/poe_tasks.toml b/poe_tasks.toml index b0520fe2..0def9830 100644 --- a/poe_tasks.toml +++ b/poe_tasks.toml @@ -13,7 +13,7 @@ speakeasy run $ARGS [tasks._post-generate] help = "Run post-generation patches." shell = """ -uv run python scripts/post_generate.py +uv run scripts/post_generate.uv """ [tasks._generate-readme] diff --git a/scripts/post_generate.py b/scripts/post_generate.uv old mode 100644 new mode 100755 similarity index 95% rename from scripts/post_generate.py rename to scripts/post_generate.uv index 4d2dbdad..0aa283a3 --- a/scripts/post_generate.py +++ b/scripts/post_generate.uv @@ -1,3 +1,8 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.10,<3.14" +# dependencies = [] +# /// """Post-generation patch pipeline. Runs after Speakeasy code generation to apply durable fixes to generated code. From e62bc5d8a66e72e0bc680e0a71512bac67c3ec4c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 03:40:20 +0000 Subject: [PATCH 4/5] fix: keep Speakeasy try/except block, only replace hardcoded __version__ and __user_agent__ Co-Authored-By: AJ Steers --- scripts/post_generate.uv | 10 ---------- src/airbyte_api/_version.py | 5 +++++ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/scripts/post_generate.uv b/scripts/post_generate.uv index 0aa283a3..49d9a8bb 100755 --- a/scripts/post_generate.uv +++ b/scripts/post_generate.uv @@ -54,16 +54,6 @@ def patch_version_file() -> None: flags=re.MULTILINE, ) - # 3. Remove the stale try/except block that attempted to override __version__ - # at runtime (no longer needed since the assignment itself is now dynamic). - text = re.sub( - r"\ntry:\n if __package__.*?\nexcept.*?\n pass\n", - "\n", - text, - count=1, - flags=re.DOTALL, - ) - if text == original: print("post_generate: _version.py already patched (no changes)") return diff --git a/src/airbyte_api/_version.py b/src/airbyte_api/_version.py index 1a6ddc25..2742580e 100644 --- a/src/airbyte_api/_version.py +++ b/src/airbyte_api/_version.py @@ -11,3 +11,8 @@ f" {__openapi_doc_version__} {__title__}" ) +try: + if __package__ is not None: + __version__ = importlib.metadata.version(__package__) +except importlib.metadata.PackageNotFoundError: + pass From 60491c302bd7e64755aef57f8f56cca053fcdade Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 03:45:34 +0000 Subject: [PATCH 5/5] fix: pin Python 3.10 in post_generate.uv shebang Co-Authored-By: AJ Steers --- scripts/post_generate.uv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/post_generate.uv b/scripts/post_generate.uv index 49d9a8bb..9b1dbbf9 100755 --- a/scripts/post_generate.uv +++ b/scripts/post_generate.uv @@ -1,4 +1,4 @@ -#!/usr/bin/env -S uv run --script +#!/usr/bin/env -S uv run --python 3.10 --script # /// script # requires-python = ">=3.10,<3.14" # dependencies = []