From f40c9ff43e3d5a5f95df62d9591874e1eec6a01a Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Tue, 1 Sep 2026 00:31:04 +0000 Subject: [PATCH] Promote Python SDK to 2.0.0 stable --- CHANGELOG.md | 7 +++---- README.md | 3 +-- docs/index.md | 4 ++-- pyproject.toml | 10 +++++----- scripts/api_reference_release.py | 18 ++++++++---------- tests/test_api_reference_install.py | 11 +++++++++++ tests/test_release_docs_source.py | 2 +- tests/test_release_metadata.py | 14 +++++++------- 8 files changed, 38 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fa726a..a30eac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -The Python SDK advances to prerelease `2.0.0-rc.44`. PyPI displays the normalized -PEP 440 identity `2.0.0rc44`. This Avro-only SDK release is qualified with Server -`2.0.0-rc.68`; JSON remains HTTP transport and is no longer a workflow payload -codec. +The Python SDK `2.0.0` promotes the qualified release candidate to the stable +2.0 line. This Avro-only SDK release is supported with Server `2.0.0`; JSON +remains HTTP transport and is not a workflow payload codec. Earlier SDK versions remain historical releases and are not alternate supported 2.0 baselines; no prerelease compatibility shim is provided. diff --git a/README.md b/README.md index 3f611c5..04b27b7 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ A Python SDK for the [Durable Workflow server](https://github.com/durable-workflow/server). Speaks the server's language-neutral HTTP/JSON worker protocol — no PHP runtime required. -Status: **Release candidate** — this is the Python SDK release candidate in the -Durable Workflow 2.0 train. Core features include workflows, activities, +Status: **Stable 2.0**. Core features include workflows, activities, schedules, signals, timers, child workflows, continue-as-new, side effects, version markers, worker-applied accepted updates, replay verification, the in-process `WorkflowEnvironment` test harness, and invocable activity carriers. diff --git a/docs/index.md b/docs/index.md index 9ccfe36..f78e910 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,7 +11,7 @@ hide:
-

First-party Python SDK · 2.0 prerelease

+

First-party Python SDK · 2.0 stable

# Durable workflows in Python. @@ -100,7 +100,7 @@ file containing an activity, workflow, worker, and client. ### 1. Start Server Docker keeps this first run local. Resolve the Server image without copying a -prerelease sequence number into the page: +release version into the page: ```bash {{ durable_workflow_server_image_resolver }} diff --git a/pyproject.toml b/pyproject.toml index d565da6..58bc234 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta" [project] name = "durable-workflow" -version = "2.0.0-rc.44" -description = "Release candidate Python SDK for the Durable Workflow 2.0 train" +version = "2.0.0" +description = "Python SDK for the Durable Workflow 2.0 platform" readme = "README.md" requires-python = ">=3.10" license = "MIT" @@ -68,9 +68,9 @@ durable-workflow-replay-conformance = "durable_workflow.replay_conformance:main" durable-workflow-workflow-updates-conformance = "durable_workflow.workflow_updates_conformance:main" [tool.durable-workflow] -product-train = "2.0.0-rc.44" -registry-version = "2.0.0rc44" -supported-server-versions = "2.0.0-rc.68" +product-train = "2.0.0" +registry-version = "2.0.0" +supported-server-versions = "2.0.0" worker-protocol-version = "1.19" control-plane-version = "2" durable-selection = true diff --git a/scripts/api_reference_release.py b/scripts/api_reference_release.py index c0a60c5..96beb9e 100644 --- a/scripts/api_reference_release.py +++ b/scripts/api_reference_release.py @@ -39,6 +39,7 @@ RELEASE_EVIDENCE_SCHEMA = "durable-workflow.python-api-reference.release" QUICKSTART_CONTRACT_SCHEMA = "durable-workflow.docs.v2.quickstart-execution-contract" QUICKSTART_CONTRACT_URL = "https://durable-workflow.com/quickstart-execution-contract.json" +RELEASE_VERSION_PATTERN = r"[0-9]+\.[0-9]+\.[0-9]+(?:-(?:alpha|beta|rc)\.[0-9]+)?" SUPPORTED_PRERELEASE_INSTALL_COMMAND = "curl -fsSL https://durable-workflow.com/install-sdk.sh | sh -s -- python" SUPPORTED_SERVER_IMAGE_RESOLVER_COMMAND = rf'''export DW_SERVER_IMAGE="$( curl -fsSL "${{DURABLE_WORKFLOW_QUICKSTART_CONTRACT_URL:-{QUICKSTART_CONTRACT_URL}}}" | @@ -50,8 +51,8 @@ version = server.get("version") image = server.get("image") reference = server.get("reference") -if not isinstance(version, str) or re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)\.[0-9]+", version) is None: - raise SystemExit("The public quickstart contract has an invalid Server prerelease.") +if not isinstance(version, str) or re.fullmatch(r"{RELEASE_VERSION_PATTERN}", version) is None: + raise SystemExit("The public quickstart contract has an invalid Server release.") if not isinstance(image, str) or reference != f"{{image}}:{{version}}": raise SystemExit("The public quickstart contract has an invalid Server reference.") print(reference)' @@ -116,9 +117,6 @@ def load_release_identity(repo_root: Path) -> ReleaseIdentity: raise ValueError("project.version and tool.durable-workflow.product-train must match") if normalize_registry_version(identity.version) != identity.registry_version: raise ValueError("registry-version must be the PEP 440 form of project.version") - if "-" not in identity.version: - raise ValueError("API-reference release identity must remain a prerelease before the 2.0 stable cutover") - runtime_protocol = declared_runtime_protocol_version( (repo_root / "src" / "durable_workflow" / "client.py").read_text(encoding="utf-8") ) @@ -160,11 +158,11 @@ def load_qualified_onboarding(payload: object) -> QualifiedOnboarding: server_version = server.get("version") server_image = server.get("image") server_reference = server.get("reference") - prerelease = re.compile(r"[0-9]+\.[0-9]+\.[0-9]+-(?:alpha|beta|rc)\.[0-9]+") - if not isinstance(sdk_version, str) or prerelease.fullmatch(sdk_version) is None: - raise ValueError("Public quickstart contract has an invalid Python SDK prerelease") - if not isinstance(server_version, str) or prerelease.fullmatch(server_version) is None: - raise ValueError("Public quickstart contract has an invalid Server prerelease") + release = re.compile(RELEASE_VERSION_PATTERN) + if not isinstance(sdk_version, str) or release.fullmatch(sdk_version) is None: + raise ValueError("Public quickstart contract has an invalid Python SDK release") + if not isinstance(server_version, str) or release.fullmatch(server_version) is None: + raise ValueError("Public quickstart contract has an invalid Server release") if not isinstance(server_image, str) or not server_image: raise ValueError("Public quickstart contract has an invalid Server image") if server_reference != f"{server_image}:{server_version}": diff --git a/tests/test_api_reference_install.py b/tests/test_api_reference_install.py index a3a0010..416e1b5 100644 --- a/tests/test_api_reference_install.py +++ b/tests/test_api_reference_install.py @@ -141,6 +141,17 @@ def test_contract_change_alone_changes_the_qualified_sdk_server_pair() -> None: assert changed.server_reference != current.server_reference +def test_stable_contract_selects_the_stable_sdk_server_pair() -> None: + stable = load_qualified_onboarding(quickstart_contract("2.0.0", "2.0.0")) + + assert stable == QualifiedOnboarding( + sdk_version="2.0.0", + sdk_registry_version="2.0.0", + server_version="2.0.0", + server_reference="durableworkflow/server:2.0.0", + ) + + def test_contract_rejects_a_mismatched_server_reference() -> None: contract = quickstart_contract("2.0.0-rc.101", "2.0.0-rc.201") artifacts = contract["artifacts"] diff --git a/tests/test_release_docs_source.py b/tests/test_release_docs_source.py index 8a8e427..949c91f 100644 --- a/tests/test_release_docs_source.py +++ b/tests/test_release_docs_source.py @@ -5,7 +5,7 @@ REPO_ROOT = Path(__file__).resolve().parents[1] VALIDATOR = REPO_ROOT / "scripts" / "ci" / "validate-release-docs-source.py" -VERSION = "2.0.0-rc.44" +VERSION = "2.0.0" def git(repo: Path, *arguments: str) -> str: diff --git a/tests/test_release_metadata.py b/tests/test_release_metadata.py index b72dd1f..bb09972 100644 --- a/tests/test_release_metadata.py +++ b/tests/test_release_metadata.py @@ -25,11 +25,11 @@ def source_metadata() -> SourceMetadata: return SourceMetadata( commit="a" * 40, name="durable-workflow", - version="2.0.0-rc.44", - registry_version="2.0.0rc44", - server_version="2.0.0-rc.68", + version="2.0.0", + registry_version="2.0.0", + server_version="2.0.0", worker_protocol_version="1.19", - summary="Release candidate Python SDK for the Durable Workflow 2.0 train", + summary="Python SDK for the Durable Workflow 2.0 platform", classifiers=("Programming Language :: Python :: 3",), readme=( "# Durable Workflow\n\n" @@ -45,10 +45,10 @@ def test_worker_release_identity_matches_supported_server_and_protocol() -> None project = manifest["project"] release = manifest["tool"]["durable-workflow"] - assert project["version"] == "2.0.0-rc.44" + assert project["version"] == "2.0.0" assert release["product-train"] == project["version"] - assert release["registry-version"] == "2.0.0rc44" - assert release["supported-server-versions"] == "2.0.0-rc.68" + assert release["registry-version"] == "2.0.0" + assert release["supported-server-versions"] == "2.0.0" assert release["worker-protocol-version"] == PROTOCOL_VERSION == "1.19" assert release["durable-selection"] is True assert release["durable-selection-minimum-worker-protocol-version"] == "1.19"