Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Type Check (pyright)

on:
push:
branches:
- "main"
tags:
- "v*"
- "azuremanaged-v*"
pull_request:
branches:
- "main"

permissions:
contents: read

jobs:
pyright:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python 3.10 (lowest supported)
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install packages and dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e ".[azure-blob-payloads,opentelemetry]"
pip install -e ./durabletask-azuremanaged
pip install pyright

- name: Run pyright (strict, Python 3.10)
run: pyright
51 changes: 42 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,36 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
## v1.5.0

BREAKING CHANGES (type-level only — no runtime impact for typical users)

These changes do not alter runtime behavior for clients or activity/orchestrator
authors, but because the package ships `py.typed`, consumers running strict type
checkers (pyright/mypy) against their own code — or subclassing the public
abstract types — may see new type-check errors and need to update their
overrides:

- `OrchestrationContext.create_timer` now returns the specific `TimerTask` type
(was `CancellableTask`)
([#93](https://github.com/microsoft/durabletask-python/issues/93)).
- `OrchestrationContext.wait_for_external_event` now returns `CancellableTask[Any]`
(was a bare `CancellableTask`).
- `WhenAnyTask` is now generic; `when_any(tasks: Sequence[Task[T]])` returns
`WhenAnyTask[T]` for better static inference of the completing child task
([#94](https://github.com/microsoft/durabletask-python/issues/94)).
`CompositeTask.on_child_completed` now takes `Task[Any]`.
- `TaskHubGrpcWorker.add_activity` / `add_entity` (and the internal registry
methods) now require `Activity[Any, Any]` / `Entity[Any, Any]` instead of the
bare `Activity` / `Entity` aliases.
- `OrchestrationContext.call_entity` / `signal_entity` `input` parameter widened
from `TInput | None` to `Any` (Liskov-safe for callers; subclass overrides
using the old narrower type will be flagged).
- gRPC client interceptors now use the public `grpc.ClientCallDetails` /
`grpc.aio.ClientCallDetails` types instead of private internal namedtuples;
custom interceptor subclasses should retype their override parameters.
- These changes also broadly improve generic type-safety hints throughout the
SDK ([#92](https://github.com/microsoft/durabletask-python/issues/92)).

ADDED

Expand All @@ -14,14 +43,9 @@ ADDED
existing `AsyncTaskHubGrpcClient` async-context-manager support and the
`TaskHubGrpcWorker` pattern. `DurableTaskSchedulerClient` inherits this
behavior automatically. `__exit__` delegates to `close()`, so the
resiliency-aware teardown introduced in v1.5.0 (in-flight recreate
thread join, retired-channel timer cancellation, and SDK-owned channel
cleanup) runs unchanged through the new `with` path.

## v1.5.0

ADDED

resiliency-aware teardown (in-flight recreate thread join, retired-channel
timer cancellation, and SDK-owned channel cleanup) runs unchanged through the
new `with` path.
- Added `ReplaySafeLogger` and `OrchestrationContext.create_replay_safe_logger()`
for suppressing duplicate log messages during orchestrator replay
- Added `GrpcChannelOptions` and `GrpcRetryPolicyOptions` for configuring
Expand All @@ -42,8 +66,17 @@ ADDED
`ListInstanceIds` so local orchestration tests can retrieve history and page
terminal instance IDs by completion window.

CHANGED

- `when_any` now copies its input into a new list (`WhenAnyTask(list(tasks))`).
Previously the task aliased the caller's list, so mutating it after
construction was visible inside the task; that side effect no longer occurs.

FIXED

- Fixed `EntityInstanceId.__lt__` infinite recursion when compared against a
non-`EntityInstanceId` operand. It now returns `NotImplemented`, so mixed-type
comparisons raise `TypeError` cleanly instead of recursing.
- Improved `TaskHubGrpcWorker` recovery from stale or disconnected gRPC streams
so configured hello timeouts apply on fresh connections, received work resets
failure tracking, SDK-owned channels are refreshed and cleaned up safely, and
Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
grpcio-tools
pymarkdownlnt
pyright
13 changes: 11 additions & 2 deletions durabletask-azuremanaged/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

## v1.5.0

- Updates base dependency to durabletask v1.5.0
- Improved type coverage benefits Azure Managed users: `create_timer` now
returns the specific `TimerTask` type and `when_any` is generic so the
completing child task is type-checked through `DurableTaskSchedulerClient`,
`AsyncDurableTaskSchedulerClient`, and `DurableTaskSchedulerWorker` derived
orchestrations.
- gRPC client interceptors in the core SDK now use the public
`grpc.ClientCallDetails` / `grpc.aio.ClientCallDetails` types instead of
private internal namedtuples. Any custom DTS auth interceptor built on the
same pattern as `DTSDefaultClientInterceptorImpl` should retype its
`_intercept_call` override parameter accordingly. This is a type-level change
only and does not alter runtime behavior.
- Added optional `interceptors`, `channel`, and `channel_options` parameters to
`DurableTaskSchedulerClient`, `AsyncDurableTaskSchedulerClient`, and
`DurableTaskSchedulerWorker` to allow combining custom gRPC interceptors with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
from durabletask.internal.grpc_interceptor import (
DefaultAsyncClientInterceptorImpl,
DefaultClientInterceptorImpl,
_AsyncClientCallDetails,
_ClientCallDetails,
)


Expand Down Expand Up @@ -62,7 +60,7 @@ def _upsert_authorization_header(self, token: str) -> None:
self._metadata.append(("authorization", f"Bearer {token}"))

def _intercept_call(
self, client_call_details: _ClientCallDetails) -> grpc.ClientCallDetails:
self, client_call_details: grpc.ClientCallDetails) -> grpc.ClientCallDetails:
"""Internal intercept_call implementation which adds metadata to grpc metadata in the RPC
call details."""
# Refresh the auth token if a credential was provided. The call to
Expand Down Expand Up @@ -114,7 +112,7 @@ def _upsert_authorization_header(self, token: str) -> None:
self._metadata.append(("authorization", f"Bearer {token}"))

async def _intercept_call(
self, client_call_details: _AsyncClientCallDetails) -> grpc.aio.ClientCallDetails:
self, client_call_details: grpc.aio.ClientCallDetails) -> grpc.aio.ClientCallDetails:
"""Internal intercept_call implementation which adds metadata to grpc metadata in the RPC
call details."""
# Refresh the auth token if a credential was provided. The call to
Expand Down
Loading
Loading