This file provides context for AI agents working on the Dapr Python SDK. The project is the official Python SDK for Dapr (Distributed Application Runtime), enabling Python developers to build distributed applications using Dapr building blocks.
Repository: https://github.com/dapr/python-sdk License: Apache 2.0
Deeper documentation lives alongside the code. This root file gives you the big picture and tells you where to look. Each extension and the examples directory has its own
AGENTS.mdwith detailed architecture, APIs, and patterns.
dapr/ # Core SDK package (single PyPI dist: `pip install dapr`)
├── actor/ # Actor framework (virtual actor model)
├── aio/ # Async I/O modules
├── clients/ # Dapr clients (gRPC and HTTP)
├── common/ # Shared utilities
├── conf/ # Configuration (settings, environment)
├── proto/ # Auto-generated gRPC protobuf stubs (DO NOT EDIT)
├── serializers/ # JSON and pluggable serializers
├── version/ # Version metadata
└── ext/ # Extensions, installable as extras to the base package
├── fastapi/ # FastAPI integration ← see dapr/ext/fastapi/AGENTS.md (`pip install dapr[fastapi]`)
├── flask/ # Flask integration ← see dapr/ext/flask/AGENTS.md (`pip install dapr[flask]`)
├── grpc/ # gRPC App extension ← see dapr/ext/grpc/AGENTS.md (`pip install dapr[grpc]`)
├── langgraph/ # LangGraph checkpointer ← see dapr/ext/langgraph/AGENTS.md (`pip install dapr[langgraph]`)
├── strands/ # Strands agent sessions ← see dapr/ext/strands/AGENTS.md (`pip install dapr[strands]`)
└── workflow/ # Workflow authoring ← see dapr/ext/workflow/AGENTS.md (`pip install dapr[workflow]`)
flask_dapr/ # Deprecation shim: re-exports dapr.ext.flask with FutureWarning
tests/ # Unit tests (mirrors dapr/ package structure)
├── ext/ # Extension tests, one subdir per extension
├── examples/ # Output-based tests that run examples and check stdout
├── integration/ # Programmatic SDK tests using DaprClient directly
examples/ # User-facing example applications ← see examples/AGENTS.md
docs/ # Sphinx documentation source
tools/ # Build and release scripts
- Namespace packages:
dapr.extis an implicit PEP 420 namespace package. See the Gotchas section below before adding anything at that path. - Client architecture:
DaprGrpcClient(primary, high-performance) and HTTP-based clients. Both implement shared interfaces. - Actor model:
Actorbase class,ActorInterfacewith@actormethoddecorator,ActorProxy/ActorProxyFactoryfor client-side references,ActorRuntimefor server-side hosting. - Serialization: Pluggable via
Serializerbase class.DefaultJSONSerializeris the default. - Proto files: Auto-generated from Dapr proto definitions. Never edit files under
dapr/proto/directly.
Extensions are bundled into the core dapr wheel and exposed as installable extras. Each one lives under dapr/ext/<name>/ with its own AGENTS.md.
| Extra | Import path | Purpose | Active development |
|---|---|---|---|
dapr[workflow] |
dapr.ext.workflow |
Durable workflow orchestration (durabletask vendored internally) | High, major focus area |
dapr[grpc] |
dapr.ext.grpc |
gRPC server for Dapr callbacks (methods, pub/sub, bindings, jobs) | Moderate |
dapr[fastapi] |
dapr.ext.fastapi |
FastAPI integration for pub/sub and actors | Moderate |
dapr[flask] |
dapr.ext.flask |
Flask integration for pub/sub and actors (legacy flask_dapr import path is a deprecated shim) |
Low |
dapr[langgraph] |
dapr.ext.langgraph |
LangGraph checkpoint persistence to Dapr state store | Moderate |
dapr[strands] |
dapr.ext.strands |
Strands agent session management via Dapr state store | New |
The previously-separate distributions (dapr-ext-*, flask-dapr) are no longer published. dapr/__init__.py emits a FutureWarning if it detects a legacy install at import time; see RELEASE.md for the migration recipe.
The examples/ directory contains user-facing example applications. These are validated by two test suites:
tests/examples/— Output-based tests that run examples viadapr runand check stdout for expected strings. Uses aDaprRunnerhelper to manage process lifecycle. Seeexamples/AGENTS.md.tests/integration/— Programmatic SDK tests that callDaprClientmethods directly and assert on return values, gRPC status codes, and SDK types. More reliable than output-based tests since they don't depend on print statement formatting. Seetests/integration/AGENTS.md.
Quick reference:
uv run pytest tests/examples/ # Run output-based example tests
uv run pytest tests/examples/test_state_store.py # Run a single example test
uv run pytest tests/integration/ # Run programmatic SDK tests
uv run pytest tests/integration/test_invoke.py # Run a single integration test- Minimum: Python 3.10
- Tested: 3.10, 3.11, 3.12, 3.13, 3.14
- Target version for tooling:
py310(ruff, mypy)
Install all packages in editable mode with dev dependencies:
uv sync --all-packages --group devTests use Python's built-in unittest framework with coverage. The vendored durabletask tests use pytest.
# All unit tests. pytest is required: `unittest discover` silently skips the
# pytest-style tests under tests/ext/flask and tests/ext/workflow/durabletask.
uv run pytest -m "not e2e" ./tests --ignore=tests/integration --ignore=tests/examples
# Single extension (unittest discover works for these — no pytest-style tests):
uv run python -m unittest discover -v ./tests/ext/workflow
uv run python -m unittest discover -v ./tests/ext/grpc
uv run python -m unittest discover -v ./tests/ext/fastapi
uv run python -m unittest discover -v ./tests/ext/langgraph
uv run python -m unittest discover -v ./tests/ext/strands
# pytest-style suites:
uv run pytest -m "not e2e" ./tests/ext/workflow/durabletask/
uv run pytest ./tests/ext/flask/test_shim_deprecation.py
# Run linting and formatting
uv run ruff check --fix && uv run ruff format
# Run type checking
uv run mypy
# Run output-based example tests (requires Dapr runtime)
uv run pytest tests/examples/
# Run programmatic integration tests (requires Dapr runtime)
uv run pytest tests/integration/Formatter/Linter: Ruff (v0.14.1)
Key rules:
- Line length: 100 characters (E501 is currently ignored, but respect the 100-char target)
- Quote style: Single quotes
- Import sorting: isort-compatible (ruff
Irules) - Target: Python 3.10
- Excluded from linting:
.github/,dapr/proto/
Run formatting and lint fixes:
uv run ruff check --fix && uv run ruff formatType checking: MyPy
uv run mypyMyPy checks the dapr and flask_dapr packages (covering all bundled extensions under dapr.ext.*). Proto stubs (dapr.proto.*) have errors ignored, and unstubbed third-party libs (langgraph.*, langchain.*, strands.*, strands_agents.*, grpc.aio) are marked ignore_missing_imports. Configuration in pyproject.toml under [tool.mypy].
- DCO required: Every commit must include a
Signed-off-byline. Usegit commit -sto add it automatically. - CI checks: Linting (ruff), unit tests (Python 3.10-3.14), type checking (mypy), and DCO verification run on all PRs.
- Branch targets: PRs go to
mainorrelease-*branches. - Tag-based releases: A single
v*tag triggers PyPI publishing for all packages (core SDK and all extensions).
When completing any task on this project, work through this checklist. Not every item applies to every change — use judgment — but always consider each one.
- Read the relevant existing source files before making changes
- Understand the existing patterns in the area you're modifying (naming, error handling, async vs sync)
- Check if there's both a sync and async variant that needs updating (see
dapr/aio/and extensionaio/subdirectories) - Read the relevant extension's
AGENTS.mdfor architecture and gotchas specific to that area
- Follow existing code style: single quotes, 100-char lines, Python 3.10+ syntax
- Do not edit files under
dapr/proto/— these are auto-generated - Do not add
__init__.pyfiles to namespace package roots in extensions
- Add or update unit tests under
tests/(core SDK) ortests/ext/<name>/(extensions) - Tests are predominantly
unittest.TestCase; follow the existing patterns in the relevant directory. A few pytest-style tests exist for fixture-dependent scenarios (e.g.pytest.warnsfor theflask_daprshim). - Verify tests pass:
uv run pytest -m "not e2e" ./tests --ignore=tests/integration --ignore=tests/examples(must use pytest;unittest discoversilently skips pytest-style tests)
- Run
uv run ruff check --fix && uv run ruff formatand fix any remaining issues - Run
uv run mypyif you changed files covered by mypy (thedaprandflask_daprpackages, which includes all bundled extensions underdapr.ext.*)
- If you added a new user-facing feature or building block, add or update an example in
examples/ - Add a corresponding pytest test in
tests/examples/(output-based) and/ortests/integration/(programmatic) - If you changed output format of existing functionality, update expected output in
tests/examples/ - See
examples/AGENTS.mdfor full details on writing examples
- Update docstrings if you changed a public API's signature or behavior
- Update the relevant example README if the usage pattern changed
- Run
uv run ruff check --fix && uv run ruff format— linting must be clean - Run
uv run pytest -m "not e2e" ./tests --ignore=tests/integration --ignore=tests/examples— all unit tests must pass - If you touched examples:
uv run pytest tests/examples/test_<example-name>.pyto validate locally - Commits must be signed off for DCO:
git commit -s
| File | Purpose |
|---|---|
pyproject.toml |
Package metadata, extras, dependencies, ruff, mypy, and uv workspace config |
uv.lock |
Locked dependency versions (reproducible installs) |
dapr/__init__.py |
Imports _detect_legacy_extension_dists to warn about legacy dapr-ext-* / flask-dapr installs that collide with the bundled extension files |
dapr/version/version.py |
SDK version string |
tests/examples/ |
Output-based tests that validate examples by checking stdout |
tests/integration/ |
Programmatic SDK tests using DaprClient directly |
- Namespace packages:
dapr.extis a PEP 420 implicit namespace package. Do not createdapr/ext/__init__.py; that would block any future externally-publisheddapr.ext.*distribution from coexisting with the core wheel on install. - Proto files: Never manually edit anything under
dapr/proto/. These are generated. - Bundled extensions: live under
dapr/ext/<name>/, opted in via extras (dapr[fastapi], etc.). The legacydapr-ext-*andflask-daprdistributions are no longer published; legacy installs must be uninstalled before upgrading orimport daprwill emit aFutureWarning. - DCO signoff: PRs will be blocked by the DCO bot if commits lack
Signed-off-by. Always usegit commit -s. - Ruff version pinned:
pyproject.tomlpinsruff==0.14.1in[dependency-groups].dev. Useuv sync --all-packages --group devto get the exact version. - Examples are tested by output matching: Changing output format (log messages, print statements) can break
tests/examples/. Always check expected output there when modifying user-visible output. - Background processes in examples: Examples that start background services (servers, subscribers) must include a cleanup step to stop them, or CI will hang.
- Workflow is the most active area: See
dapr/ext/workflow/AGENTS.mdfor workflow-specific architecture and constraints.