Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dd6d4ec
use 1.17.0.dev (#885)
acroca Jan 16, 2026
9f89746
Trigger ci for new ext tags (#886)
acroca Jan 16, 2026
92f20f5
fix(bug): workflow client missing close function to pass to durable t…
CasperGN Jan 16, 2026
de3eef6
Workflow: remove sleeps from example (#894)
JoshVanL Jan 19, 2026
39d0036
Workflow versioning (#893)
acroca Jan 27, 2026
40b5734
feat(convo): add new fields to conversation api (#902)
sicoyle Feb 6, 2026
8392606
fix: signal when dt reader stream is ready within wf client start cal…
sicoyle Feb 6, 2026
9b2c641
fix(build): capture latest + rereleases for dapr runtime + cli (#906)
sicoyle Feb 9, 2026
1662e5e
chore(deps): bump durabletask-dapr (#905)
CasperGN Feb 9, 2026
9d9d6ec
Update durabletask (#908)
acroca Feb 11, 2026
a91c026
Bump fossas/fossa-action from 1.7.0 to 1.8.0 (#904)
dependabot[bot] Feb 11, 2026
9036527
Use backport github action (#911)
acroca Feb 11, 2026
8ac6070
Add license to the backport action
acroca Feb 11, 2026
4f5709a
Update mypy_protobuf (#910)
acroca Feb 12, 2026
27e164f
fix: Use highest version, not latest (#918)
acroca Feb 13, 2026
cb20efd
Point backport action to a specific commit (#920)
acroca Feb 16, 2026
4e0e38c
Add support to bulk pubsub (#915)
acroca Feb 20, 2026
dbaa95e
Fix tox (#925)
acroca Feb 20, 2026
2325498
add venv (#921)
cicoyle Feb 23, 2026
adbcf32
Added support for python 3.14 and done some pending 3.9 removals (#916)
acroca Feb 24, 2026
fa4a291
chore: Use dapr-bot to create backport PRs, so they can trigger workf…
acroca Feb 24, 2026
a1e0354
fix: Align Workflow Multi App Naming Convention (#932)
matheusandre1 Feb 27, 2026
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
37 changes: 37 additions & 0 deletions .github/workflows/backport.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# Copyright 2026 The Dapr Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Backport
on:
pull_request_target:
types:
- closed
- labeled

jobs:
backport:
name: Backport
runs-on: ubuntu-latest
if: >
github.event.pull_request.merged
&& (
github.event.action == 'closed'
|| (
github.event.action == 'labeled'
&& contains(github.event.label.name, 'backport')
)
)
steps:
- uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e
with:
github_token: ${{ secrets.DAPR_BOT_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/build-push-to-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python_ver: ["3.10", "3.11", "3.12", "3.13"]
python_ver: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python_ver }}
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/build-tag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ on:
- grpc-v*
- flask-v*
- fastapi-v*
- langgraph-v*
- strands-v*
workflow_dispatch:

jobs:
Expand Down Expand Up @@ -41,7 +43,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python_ver: ["3.10", "3.11", "3.12", "3.13"]
python_ver: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python_ver }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python_ver: ["3.10", "3.11", "3.12", "3.13"]
python_ver: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python_ver }}
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/fossa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ on:
- grpc-v*
- flask-v*
- fastapi-v*
- langgraph-v*
- strands-v*
pull_request:
branches:
- main
Expand All @@ -43,12 +45,12 @@ jobs:
uses: actions/checkout@v6

- name: "Run FOSSA Scan"
uses: fossas/fossa-action@v1.7.0 # Use a specific version if locking is preferred
uses: fossas/fossa-action@v1.8.0 # Use a specific version if locking is preferred
with:
api-key: ${{ env.FOSSA_API_KEY }}

- name: "Run FOSSA Test"
uses: fossas/fossa-action@v1.7.0 # Use a specific version if locking is preferred
uses: fossas/fossa-action@v1.8.0 # Use a specific version if locking is preferred
with:
api-key: ${{ env.FOSSA_API_KEY }}
run-tests: true
12 changes: 7 additions & 5 deletions .github/workflows/validate_examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ on:
- grpc-v*
- fastapi-v*
- flask-v*
- langgraph-v*
- strands-v*
pull_request:
branches:
- main
Expand Down Expand Up @@ -46,7 +48,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python_ver: ["3.10", "3.11", "3.12", "3.13"]
python_ver: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- name: Parse repository_dispatch payload
if: github.event_name == 'repository_dispatch'
Expand All @@ -63,14 +65,14 @@ jobs:
repository: ${{ env.CHECKOUT_REPO }}
ref: ${{ env.CHECKOUT_REF }}
- uses: azure/setup-helm@v4
- name: Determine latest Dapr Runtime version
- name: Determine latest Dapr Runtime version (including prerelease)
run: |
helm repo add dapr https://dapr.github.io/helm-charts/ && helm repo update && export RUNTIME_VERSION=$(helm search repo dapr/dapr --devel --versions | awk '/dapr\/dapr/ {print $3; exit}' )
RUNTIME_VERSION=$(curl -s "https://api.github.com/repos/dapr/dapr/releases" | sort -r | grep '"tag_name"' | head -n 1 | cut -d ':' -f2 | tr -d '",v ')
echo "DAPR_RUNTIME_VER=$RUNTIME_VERSION" >> $GITHUB_ENV
echo "Found $RUNTIME_VERSION"
- name: Determine latest Dapr Cli version
- name: Determine latest Dapr Cli version (including prerelease)
run: |
export CLI_VERSION=$(curl "https://api.github.com/repos/dapr/cli/releases/latest" --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' | jq '.tag_name'| tr -d '",v')
CLI_VERSION=$(curl -s "https://api.github.com/repos/dapr/cli/releases" | sort -r | grep '"tag_name"' | head -n 1 | cut -d ':' -f2 | tr -d '",v ')
echo "DAPR_CLI_VER=$CLI_VERSION" >> $GITHUB_ENV
echo "Found $CLI_VERSION"
- name: Set up Python ${{ matrix.python_ver }}
Expand Down
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This includes the following packages:
### Prerequisites

* [Install Dapr standalone mode](https://github.com/dapr/cli#install-dapr-on-your-local-machine-self-hosted)
* [Install Python 3.9+](https://www.python.org/downloads/)
* [Install Python 3.10+](https://www.python.org/downloads/)

### Install Dapr python sdk

Expand Down Expand Up @@ -79,7 +79,14 @@ git clone https://github.com/dapr/python-sdk.git
cd python-sdk
```

2. Install a project in a editable mode
2. Create and activate a virtual environment

```bash
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
```

3. Install a project in editable mode

```bash
pip3 install -e .
Expand All @@ -90,31 +97,31 @@ pip3 install -e ./ext/dapr-ext-langgraph/
pip3 install -e ./ext/dapr-ext-strands/
```

3. Install required packages
4. Install required packages

```bash
pip3 install -r dev-requirements.txt
```

4. Run linter and autofix
5. Run linter and autofix

```bash
tox -e ruff
```

5. Run unit-test
6. Run unit-test

```bash
tox -e py311
```

6. Run type check
7. Run type check

```bash
tox -e type
```

7. Run examples
8. Run examples

```bash
tox -e examples
Expand Down Expand Up @@ -145,12 +152,10 @@ The generated files will be found in `docs/_build`.

```sh
pip3 install -r tools/requirements.txt
export DAPR_BRANCH=release-1.16 # Optional, defaults to master
export DAPR_BRANCH=release-1.17 # Optional, defaults to master
./tools/regen_grpcclient.sh
```

> Note: The `grpcio-tools` version we're using doesn't support Python 3.13.

## Help & Feedback

Need help or have feedback on the SDK? Please open a GitHub issue or come chat with us in the `#python-sdk` channel of our Discord server ([click here to join](https://discord.gg/MySdVxrH)).
Expand Down
93 changes: 93 additions & 0 deletions dapr/aio/clients/grpc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from google.protobuf.any_pb2 import Any as GrpcAny
from google.protobuf.empty_pb2 import Empty as GrpcEmpty
from google.protobuf.message import Message as GrpcMessage
from grpc import StatusCode # type: ignore
from grpc.aio import ( # type: ignore
AioRpcError,
StreamStreamClientInterceptor,
Expand Down Expand Up @@ -69,6 +70,8 @@
)
from dapr.clients.grpc._response import (
BindingResponse,
BulkPublishResponse,
BulkPublishResponseFailedEntry,
BulkStateItem,
BulkStatesResponse,
ConfigurationResponse,
Expand Down Expand Up @@ -484,6 +487,96 @@ async def publish_event(

return DaprResponse(await call.initial_metadata())

async def publish_events(
self,
pubsub_name: str,
topic_name: str,
data: Sequence[Union[bytes, str]],
publish_metadata: Dict[str, str] = {},
data_content_type: Optional[str] = None,
) -> BulkPublishResponse:
"""Bulk publish multiple events to a given topic.
This publishes multiple events to a specified topic and pubsub component.
Each event can be bytes or str. The str data is encoded into bytes with
default charset of utf-8.

The example publishes multiple string events to a topic:

from dapr.aio.clients import DaprClient
async with DaprClient() as d:
resp = await d.publish_events(
pubsub_name='pubsub_1',
topic_name='TOPIC_A',
data=['message1', 'message2', 'message3'],
data_content_type='text/plain',
)
# resp.failed_entries includes any entries that failed to publish.

Args:
pubsub_name (str): the name of the pubsub component
topic_name (str): the topic name to publish to
data (Sequence[Union[bytes, str]]): sequence of events to publish;
each event must be bytes or str
publish_metadata (Dict[str, str], optional): Dapr metadata for the
bulk publish request
data_content_type (str, optional): content type of the event data

Returns:
:class:`BulkPublishResponse` with any failed entries
"""
entries = []
for event in data:
entry_id = str(uuid.uuid4())
if isinstance(event, bytes):
event_data = event
content_type = data_content_type or 'application/octet-stream'
elif isinstance(event, str):
event_data = event.encode('utf-8')
content_type = data_content_type or 'text/plain'
else:
raise ValueError(f'invalid type for event {type(event)}')

entries.append(
api_v1.BulkPublishRequestEntry(
entry_id=entry_id,
event=event_data,
content_type=content_type,
)
)

req = api_v1.BulkPublishRequest(
pubsub_name=pubsub_name,
topic=topic_name,
entries=entries,
metadata=publish_metadata,
)

try:
call = self._stub.BulkPublishEvent(req)
response = await call
except AioRpcError as err:
if err.code() == StatusCode.UNIMPLEMENTED:
try:
call = self._stub.BulkPublishEventAlpha1(req)
response = await call
except AioRpcError as err2:
raise DaprGrpcError(err2) from err2
else:
raise DaprGrpcError(err) from err

failed_entries = [
BulkPublishResponseFailedEntry(
entry_id=entry.entry_id,
error=entry.error,
)
for entry in response.failedEntries
]

return BulkPublishResponse(
failed_entries=failed_entries,
headers=await call.initial_metadata(),
)

async def subscribe(
self,
pubsub_name: str,
Expand Down
10 changes: 2 additions & 8 deletions dapr/clients/grpc/_conversation_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import inspect
import random
import string
import types
from dataclasses import fields, is_dataclass
from enum import Enum
from types import UnionType
from typing import (
Any,
Callable,
Expand All @@ -37,10 +37,6 @@

from dapr.conf import settings

# Make mypy happy. Runtime handle: real class on 3.10+, else None.
# TODO: Python 3.9 is about to be end-of-life, so we can drop this at some point next year (2026)
UnionType: Any = getattr(types, 'UnionType', None)

# duplicated from conversation to avoid circular import
Params = Union[Mapping[str, Any], Sequence[Any], None]

Expand Down Expand Up @@ -857,9 +853,7 @@ def _coerce_literal(value: Any, lit_args: List[Any]) -> Any:

def _is_union(t) -> bool:
origin = get_origin(t)
if origin is Union:
return True
return UnionType is not None and origin is UnionType
return origin is Union or origin is UnionType


def _coerce_and_validate(value: Any, expected_type: Any) -> Any:
Expand Down
Loading
Loading