diff --git a/sdk/python/_runtime_setup.py b/sdk/python/_runtime_setup.py index 8d33da6c88..fcccaddebd 100644 --- a/sdk/python/_runtime_setup.py +++ b/sdk/python/_runtime_setup.py @@ -27,16 +27,21 @@ class RuntimeSetupError(RuntimeError): def pinned_runtime_version() -> str: - source_version = _source_tree_project_version() - if source_version is not None: - return _normalized_package_version(source_version) + source_pin = _source_tree_runtime_dependency_version() + if source_pin is not None: + return _normalized_package_version(source_pin) try: - return _normalized_package_version(importlib.metadata.version(SDK_PACKAGE_NAME)) + installed_pin = _installed_sdk_runtime_dependency_version() except importlib.metadata.PackageNotFoundError as exc: raise RuntimeSetupError( - f"Unable to resolve {SDK_PACKAGE_NAME} version for runtime pinning." + f"Unable to resolve {SDK_PACKAGE_NAME} metadata for runtime pinning." ) from exc + if installed_pin is None: + raise RuntimeSetupError( + f"Unable to resolve {PACKAGE_NAME} dependency pin from {SDK_PACKAGE_NAME}." + ) + return _normalized_package_version(installed_pin) def ensure_runtime_package_installed( @@ -399,20 +404,30 @@ def _release_tag(version: str) -> str: return f"rust-v{_codex_release_version(version)}" -def _source_tree_project_version() -> str | None: +def _source_tree_runtime_dependency_version() -> str | None: pyproject_path = Path(__file__).resolve().parent / "pyproject.toml" if not pyproject_path.exists(): return None - match = re.search( - r'(?m)^version = "([^"]+)"$', - pyproject_path.read_text(encoding="utf-8"), - ) + match = re.search(_runtime_dependency_pin_pattern(), pyproject_path.read_text()) if match is None: return None return match.group(1) +def _installed_sdk_runtime_dependency_version() -> str | None: + requirements = importlib.metadata.requires(SDK_PACKAGE_NAME) or [] + for requirement in requirements: + match = re.search(_runtime_dependency_pin_pattern(), requirement) + if match is not None: + return match.group(1) + return None + + +def _runtime_dependency_pin_pattern() -> str: + return rf'{re.escape(PACKAGE_NAME)}\s*==\s*"?([^",;\s]+)"?' + + __all__ = [ "PACKAGE_NAME", "SDK_PACKAGE_NAME", diff --git a/sdk/python/examples/README.md b/sdk/python/examples/README.md index 59428ba322..3a93c28a0c 100644 --- a/sdk/python/examples/README.md +++ b/sdk/python/examples/README.md @@ -28,7 +28,7 @@ will download the matching GitHub release artifact, stage a temporary local `openai-codex-cli-bin` package, install it into your active interpreter, and clean up the temporary files afterward. -The pinned runtime version comes from the SDK package version. +The pinned runtime version comes from the SDK package dependency. ## Run examples diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index f54838bfa8..6b92983c91 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "openai-codex-app-server-sdk" -version = "0.116.0a1" +version = "0.131.0a4" description = "Python SDK for Codex app-server v2" readme = "README.md" requires-python = ">=3.10" @@ -22,7 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries :: Python Modules", ] -dependencies = ["pydantic>=2.12"] +dependencies = ["pydantic>=2.12", "openai-codex-cli-bin==0.131.0a4"] [project.urls] Homepage = "https://github.com/openai/codex" @@ -63,8 +63,10 @@ testpaths = ["tests"] [tool.uv] exclude-newer = "7 days" +exclude-newer-package = { openai-codex-cli-bin = "2026-05-10T00:00:00Z" } index-strategy = "first-index" [tool.uv.pip] exclude-newer = "7 days" +exclude-newer-package = { openai-codex-cli-bin = "2026-05-10T00:00:00Z" } index-strategy = "first-index" diff --git a/sdk/python/tests/test_artifact_workflow_and_binaries.py b/sdk/python/tests/test_artifact_workflow_and_binaries.py index 93be06ca8a..daa1f8f47a 100644 --- a/sdk/python/tests/test_artifact_workflow_and_binaries.py +++ b/sdk/python/tests/test_artifact_workflow_and_binaries.py @@ -164,7 +164,7 @@ def test_runtime_package_template_has_no_checked_in_binaries() -> None: def test_examples_readme_points_to_runtime_version_source_of_truth() -> None: readme = (ROOT / "examples" / "README.md").read_text() - assert "The pinned runtime version comes from the SDK package version." in readme + assert "The pinned runtime version comes from the SDK package dependency." in readme def test_runtime_distribution_name_is_consistent() -> None: @@ -211,12 +211,31 @@ def test_release_metadata_retries_without_invalid_auth( assert authorizations == ["Bearer invalid-token", None] +def test_source_sdk_package_pins_published_runtime() -> None: + pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text()) + + assert { + "sdk_version": pyproject["project"]["version"], + "dependencies": pyproject["project"]["dependencies"], + } == { + "sdk_version": "0.131.0a4", + "dependencies": [ + "pydantic>=2.12", + "openai-codex-cli-bin==0.131.0a4", + ], + } + + def test_runtime_setup_uses_pep440_package_version_and_codex_release_tags() -> None: runtime_setup = _load_runtime_setup_module() pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text()) assert runtime_setup.PACKAGE_NAME == "openai-codex-cli-bin" assert runtime_setup.pinned_runtime_version() == pyproject["project"]["version"] + assert ( + f"{runtime_setup.PACKAGE_NAME}=={pyproject['project']['version']}" + in pyproject["project"]["dependencies"] + ) assert ( runtime_setup._normalized_package_version("rust-v0.116.0-alpha.1") == "0.116.0a1" diff --git a/sdk/python/uv.lock b/sdk/python/uv.lock index d0e2cf7372..b8e3a8f662 100644 --- a/sdk/python/uv.lock +++ b/sdk/python/uv.lock @@ -3,9 +3,12 @@ revision = 3 requires-python = ">=3.10" [options] -exclude-newer = "2026-04-20T18:19:27.620299Z" +exclude-newer = "2026-05-02T06:28:46.47929Z" exclude-newer-span = "P7D" +[options.exclude-newer-package] +openai-codex-cli-bin = "2026-05-10T00:00:00Z" + [[package]] name = "annotated-types" version = "0.7.0" @@ -279,9 +282,10 @@ wheels = [ [[package]] name = "openai-codex-app-server-sdk" -version = "0.116.0a1" +version = "0.131.0a4" source = { editable = "." } dependencies = [ + { name = "openai-codex-cli-bin" }, { name = "pydantic" }, ] @@ -295,12 +299,26 @@ dev = [ [package.metadata] requires-dist = [ { name = "datamodel-code-generator", marker = "extra == 'dev'", specifier = "==0.31.2" }, + { name = "openai-codex-cli-bin", specifier = "==0.131.0a4" }, { name = "pydantic", specifier = ">=2.12" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.11" }, ] provides-extras = ["dev"] +[[package]] +name = "openai-codex-cli-bin" +version = "0.131.0a4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/9f/f9fc4bb1b2b7a20d4d65143ebb4c4dcd2301a718183b539ecb5b1c0ac3ec/openai_codex_cli_bin-0.131.0a4-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:db0f3cb7dda310641ac04fbaf3f128693a3817ab83ae59b67a3c9c74bd53f8b8", size = 88367585, upload-time = "2026-05-09T06:14:09.453Z" }, + { url = "https://files.pythonhosted.org/packages/dc/39/eb95ed0e8156669e895a192dec760be07dabe891c3c6340f7c6487b9a976/openai_codex_cli_bin-0.131.0a4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6cae5af6edca7f6d3f0bcbbd93cfc8a6dc3e33fb5955af21ae492b6d5d0dcb72", size = 79245567, upload-time = "2026-05-09T06:14:13.581Z" }, + { url = "https://files.pythonhosted.org/packages/0c/92/ade176fa78d746d5ff7a6e371d64740c0d95ab299b0dd58a5404b89b3915/openai_codex_cli_bin-0.131.0a4-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5728f9887baf62d7e72f4f242093b3ff81e26c81d80d346fe1eef7eda6838aa8", size = 77758628, upload-time = "2026-05-09T06:14:18.374Z" }, + { url = "https://files.pythonhosted.org/packages/28/e6/bfe6c65f8e3e5499f71b24c3b6e8d07e4d426543d25e429b9b141b544e5f/openai_codex_cli_bin-0.131.0a4-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d7a47fd3667fbcc216593839c202deffa056e9b3d46c6933e72594d461f4fea0", size = 84535509, upload-time = "2026-05-09T06:14:22.851Z" }, + { url = "https://files.pythonhosted.org/packages/bd/b7/53dc094a691ab6f2ca079e8e865b122843809ac4fad51cac4d59021e599d/openai_codex_cli_bin-0.131.0a4-py3-none-win_amd64.whl", hash = "sha256:c61bcf029672494c4c7fdc8567dbaa659a48bb75641d91c2ade27c1e46803434", size = 88185543, upload-time = "2026-05-09T06:14:27.282Z" }, + { url = "https://files.pythonhosted.org/packages/82/99/e0852ffcf9b4d2794fef83e0c3a267b3c773a776f136e9f7ce19f0c8df42/openai_codex_cli_bin-0.131.0a4-py3-none-win_arm64.whl", hash = "sha256:bbde750186861f102e346ac066f4e9608f515f7b71b16a6e8b7ef1ddc02a97a5", size = 81196380, upload-time = "2026-05-09T06:14:32.103Z" }, +] + [[package]] name = "packaging" version = "26.1"