From c375deaf66618bb4c9cf29166e23dfc41a665826 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 12 Jun 2026 12:10:07 -0400 Subject: [PATCH] Use dependency groups for Python SDK tooling (#27538) ## Summary `just fmt` previously used `uv run --with ruff` to make Ruff available. Because `--with` creates an ephemeral overlay outside the project lockfile, uv periodically re-resolved Ruff (by default every 10 minutes) instead of using the version recorded in `uv.lock`. Move the Python SDK tooling dependencies from the published `dev` extra into `format`, `test`, and composed `dev` dependency groups. The formatter now selects only the locked `format` group, contributor and CI setup explicitly sync the `dev` group, and CI and release commands reuse that environment with `--frozen --no-sync`. The scripts formatter also uses its project's locked Ruff dependency instead of an ephemeral overlay. Validated the Python 3.12 SDK suite (119 passed, 38 skipped) and the repository formatter. --- .github/workflows/python-sdk-release.yml | 4 +-- .github/workflows/sdk.yml | 8 +++--- scripts/format.py | 11 +++----- sdk/python/docs/getting-started.md | 2 +- sdk/python/examples/README.md | 2 +- sdk/python/pyproject.toml | 13 +++++++-- .../test_artifact_workflow_and_binaries.py | 8 ++---- sdk/python/uv.lock | 27 +++++++++++++++---- 8 files changed, 46 insertions(+), 29 deletions(-) diff --git a/.github/workflows/python-sdk-release.yml b/.github/workflows/python-sdk-release.yml index 3ca930daa..2526b37a5 100644 --- a/.github/workflows/python-sdk-release.yml +++ b/.github/workflows/python-sdk-release.yml @@ -191,8 +191,8 @@ jobs: sh -euxc ' python -m venv /tmp/release-tools /tmp/release-tools/bin/python -m pip install build twine uv==0.11.3 - /tmp/release-tools/bin/uv sync --extra dev --frozen - /tmp/release-tools/bin/uv run --extra dev --frozen python scripts/update_sdk_artifacts.py \ + /tmp/release-tools/bin/uv sync --group dev --frozen + /tmp/release-tools/bin/uv run --frozen --no-sync python scripts/update_sdk_artifacts.py \ stage-sdk "${SDK_STAGE_DIR}" \ --sdk-version "${SDK_VERSION}" /tmp/release-tools/bin/python -m build \ diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml index 3cf6d7c8c..5020a9004 100644 --- a/.github/workflows/sdk.yml +++ b/.github/workflows/sdk.yml @@ -35,10 +35,10 @@ jobs: sh -euxc ' python -m venv /tmp/uv /tmp/uv/bin/python -m pip install uv==0.11.3 - /tmp/uv/bin/uv sync --extra dev --frozen - /tmp/uv/bin/uv run --extra dev ruff check --output-format=github . - /tmp/uv/bin/uv run --extra dev ruff format --check . - /tmp/uv/bin/uv run --extra dev pytest + /tmp/uv/bin/uv sync --group dev --frozen + /tmp/uv/bin/uv run --frozen --no-sync ruff check --output-format=github . + /tmp/uv/bin/uv run --frozen --no-sync ruff format --check . + /tmp/uv/bin/uv run --frozen --no-sync pytest ' sdks: diff --git a/scripts/format.py b/scripts/format.py index 0c64d2aa8..69bdb5e36 100644 --- a/scripts/format.py +++ b/scripts/format.py @@ -37,17 +37,15 @@ class FormatterResult: def formatter_groups(*, check: bool) -> tuple[FormatterGroup, ...]: just_args = ["just", "--unstable", "--fmt"] cargo_args = ["cargo", "fmt", "--", "--config", "imports_granularity=Item"] - # Use an unpinned overlay so Ruff is available without syncing project - # dependencies. Each `--project` still retains its local configuration context. + # Each `--project` retains its local dependency and Ruff configuration context. sdk_uv_run_args = [ "uv", "run", "--frozen", "--project", "sdk/python", - "--no-sync", - "--with", - "ruff", + "--only-group", + "format", ] scripts_uv_run_args = [ "uv", @@ -55,9 +53,6 @@ def formatter_groups(*, check: bool) -> tuple[FormatterGroup, ...]: "--frozen", "--project", "scripts", - "--no-sync", - "--with", - "ruff", ] sdk_format_args = [ *sdk_uv_run_args, diff --git a/sdk/python/docs/getting-started.md b/sdk/python/docs/getting-started.md index fb2c88b4c..96d22ec3c 100644 --- a/sdk/python/docs/getting-started.md +++ b/sdk/python/docs/getting-started.md @@ -157,7 +157,7 @@ the repository: ```bash cd sdk/python -uv sync --extra dev +uv sync --group dev source .venv/bin/activate ``` diff --git a/sdk/python/examples/README.md b/sdk/python/examples/README.md index 8efeb75b1..719fb29a4 100644 --- a/sdk/python/examples/README.md +++ b/sdk/python/examples/README.md @@ -31,7 +31,7 @@ Contributors using these checked-in scripts should install development dependencies from `sdk/python`: ```bash -uv sync --extra dev +uv sync --group dev source .venv/bin/activate ``` diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index b70df0cb5..f3bc3a71f 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -24,8 +24,17 @@ Repository = "https://github.com/openai/codex" Issues = "https://github.com/openai/codex/issues" Documentation = "https://github.com/openai/codex/tree/main/sdk/python/docs" -[project.optional-dependencies] -dev = ["pytest>=8.0", "datamodel-code-generator==0.31.2", "ruff>=0.15.8"] +[dependency-groups] +format = ["ruff>=0.15.8"] +test = [ + "pytest>=8.0", + "datamodel-code-generator==0.31.2", + { include-group = "format" }, +] +dev = [ + { include-group = "test" }, + { include-group = "format" }, +] [tool.hatch.build] exclude = [ diff --git a/sdk/python/tests/test_artifact_workflow_and_binaries.py b/sdk/python/tests/test_artifact_workflow_and_binaries.py index 501f1e100..7bedc0cc6 100644 --- a/sdk/python/tests/test_artifact_workflow_and_binaries.py +++ b/sdk/python/tests/test_artifact_workflow_and_binaries.py @@ -145,9 +145,8 @@ def test_root_format_driver_covers_all_formatter_groups() -> None: "--frozen", "--project", "sdk/python", - "--no-sync", - "--with", - "ruff", + "--only-group", + "format", ) scripts_uv_run_args = ( "uv", @@ -155,9 +154,6 @@ def test_root_format_driver_covers_all_formatter_groups() -> None: "--frozen", "--project", "scripts", - "--no-sync", - "--with", - "ruff", ) assert all( command.args[: len(sdk_uv_run_args)] == sdk_uv_run_args diff --git a/sdk/python/uv.lock b/sdk/python/uv.lock index 588c9f4fe..b8a777240 100644 --- a/sdk/python/uv.lock +++ b/sdk/python/uv.lock @@ -289,22 +289,39 @@ dependencies = [ { name = "pydantic" }, ] -[package.optional-dependencies] +[package.dev-dependencies] dev = [ { name = "datamodel-code-generator" }, { name = "pytest" }, { name = "ruff" }, ] +format = [ + { name = "ruff" }, +] +test = [ + { name = "datamodel-code-generator" }, + { name = "pytest" }, + { name = "ruff" }, +] [package.metadata] requires-dist = [ - { name = "datamodel-code-generator", marker = "extra == 'dev'", specifier = "==0.31.2" }, { name = "openai-codex-cli-bin", specifier = "==0.137.0a4" }, { name = "pydantic", specifier = ">=2.12" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.15.8" }, ] -provides-extras = ["dev"] + +[package.metadata.requires-dev] +dev = [ + { name = "datamodel-code-generator", specifier = "==0.31.2" }, + { name = "pytest", specifier = ">=8.0" }, + { name = "ruff", specifier = ">=0.15.8" }, +] +format = [{ name = "ruff", specifier = ">=0.15.8" }] +test = [ + { name = "datamodel-code-generator", specifier = "==0.31.2" }, + { name = "pytest", specifier = ">=8.0" }, + { name = "ruff", specifier = ">=0.15.8" }, +] [[package]] name = "openai-codex-cli-bin"