You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ext/ # Extension packages (each is a separate PyPI package)
28
-
├── dapr-ext-workflow/ # Workflow authoring ← see ext/dapr-ext-workflow/AGENTS.md
29
-
├── dapr-ext-grpc/ # gRPC App extension ← see ext/dapr-ext-grpc/AGENTS.md
30
-
├── dapr-ext-fastapi/ # FastAPI integration ← see ext/dapr-ext-fastapi/AGENTS.md
31
-
├── dapr-ext-langgraph/ # LangGraph checkpointer ← see ext/dapr-ext-langgraph/AGENTS.md
32
-
├── dapr-ext-strands/ # Strands agent sessions ← see ext/dapr-ext-strands/AGENTS.md
33
-
└── flask_dapr/ # Flask integration ← see ext/flask_dapr/AGENTS.md
34
+
flask_dapr/ # Deprecation shim: re-exports dapr.ext.flask with FutureWarning
34
35
35
36
tests/ # Unit tests (mirrors dapr/ package structure)
36
-
├── examples/ # Output-based tests that run examples and check stdout
37
-
├── integration/ # Programmatic SDK tests using DaprClient directly
37
+
├── ext/ # Extension tests, one subdir per extension
38
+
├── examples/ # Output-based tests that run examples and check stdout
39
+
├── integration/ # Programmatic SDK tests using DaprClient directly
38
40
examples/ # User-facing example applications ← see examples/AGENTS.md
39
41
docs/ # Sphinx documentation source
40
42
tools/ # Build and release scripts
41
43
```
42
44
43
45
## Key architectural patterns
44
46
45
-
-**Namespace packages**: The `dapr` namespace is shared across the core SDK and extensions via `find_namespace_packages`. Extensions live in `ext/` but install into the `dapr.ext.*` namespace. Do not add `__init__.py` to namespace package roots in extensions.
47
+
-**Namespace packages**: `dapr.ext`is an implicit PEP 420 namespace package. See the Gotchas section below before adding anything at that path.
46
48
-**Client architecture**: `DaprGrpcClient` (primary, high-performance) and HTTP-based clients. Both implement shared interfaces.
47
49
-**Actor model**: `Actor` base class, `ActorInterface` with `@actormethod` decorator, `ActorProxy`/`ActorProxyFactory` for client-side references, `ActorRuntime` for server-side hosting.
48
50
-**Serialization**: Pluggable via `Serializer` base class. `DefaultJSONSerializer` is the default.
49
51
-**Proto files**: Auto-generated from Dapr proto definitions. Never edit files under `dapr/proto/` directly.
50
52
51
53
## Extension overview
52
54
53
-
Each extension is a **separate PyPI package** with its own `pyproject.toml`, `setup.py`, `tests/`, and`AGENTS.md`.
55
+
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`.
54
56
55
-
| Extension | Package | Purpose | Active development |
|`dapr[workflow]`|`dapr.ext.workflow`| Durable workflow orchestration (durabletask vendored internally) |**High**, major focus area |
60
+
|`dapr[grpc]`|`dapr.ext.grpc`| gRPC server for Dapr callbacks (methods, pub/sub, bindings, jobs) | Moderate |
61
+
|`dapr[fastapi]`|`dapr.ext.fastapi`| FastAPI integration for pub/sub and actors | Moderate |
62
+
|`dapr[flask]`|`dapr.ext.flask`| Flask integration for pub/sub and actors (legacy `flask_dapr` import path is a deprecated shim) | Low |
63
+
|`dapr[langgraph]`|`dapr.ext.langgraph`| LangGraph checkpoint persistence to Dapr state store | Moderate |
64
+
|`dapr[strands]`|`dapr.ext.strands`| Strands agent session management via Dapr state store | New |
65
+
66
+
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.
63
67
64
68
## Examples and testing
65
69
@@ -95,17 +99,20 @@ uv sync --all-packages --group dev
95
99
Tests use Python's built-in `unittest` framework with `coverage`. The vendored durabletask tests use `pytest`.
96
100
97
101
```bash
98
-
# Run all unit tests
99
-
uv run python -m unittest discover -v ./tests
100
-
101
-
# Extension tests (run each separately)
102
-
uv run python -m unittest discover -v ./ext/dapr-ext-workflow/tests
103
-
uv run pytest -m "not e2e" ./ext/dapr-ext-workflow/tests/durabletask/
104
-
uv run python -m unittest discover -v ./ext/dapr-ext-grpc/tests
105
-
uv run python -m unittest discover -v ./ext/dapr-ext-fastapi/tests
106
-
uv run python -m unittest discover -v ./ext/dapr-ext-langgraph/tests
107
-
uv run python -m unittest discover -v ./ext/dapr-ext-strands/tests
108
-
uv run python -m unittest discover -v ./ext/flask_dapr/tests
102
+
# All unit tests. pytest is required: `unittest discover` silently skips the
103
+
# pytest-style tests under tests/ext/flask and tests/ext/workflow/durabletask.
104
+
uv run pytest -m "not e2e" ./tests --ignore=tests/integration --ignore=tests/examples
105
+
106
+
# Single extension (unittest discover works for these — no pytest-style tests):
107
+
uv run python -m unittest discover -v ./tests/ext/workflow
108
+
uv run python -m unittest discover -v ./tests/ext/grpc
109
+
uv run python -m unittest discover -v ./tests/ext/fastapi
110
+
uv run python -m unittest discover -v ./tests/ext/langgraph
111
+
uv run python -m unittest discover -v ./tests/ext/strands
112
+
113
+
# pytest-style suites:
114
+
uv run pytest -m "not e2e" ./tests/ext/workflow/durabletask/
115
+
uv run pytest ./tests/ext/flask/test_shim_deprecation.py
109
116
110
117
# Run linting and formatting
111
118
uv run ruff check --fix && uv run ruff format
@@ -143,7 +150,7 @@ uv run ruff check --fix && uv run ruff format
143
150
uv run mypy
144
151
```
145
152
146
-
MyPy is configured to check: `dapr/actor/`, `dapr/aio/`, `dapr/clients/`, `dapr/conf/`, `dapr/serializers/`, `ext/dapr-ext-grpc/`, `ext/dapr-ext-fastapi/`, `ext/flask_dapr/`, and `examples/demo_actor/`. Proto stubs (`dapr.proto.*`) have errors ignored. Configuration lives in `pyproject.toml` under `[tool.mypy]`.
153
+
MyPy 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]`.
147
154
148
155
## Commit and PR conventions
149
156
@@ -171,14 +178,14 @@ When completing any task on this project, work through this checklist. Not every
171
178
172
179
### Unit tests
173
180
174
-
-[ ] Add or update unit tests under `tests/` (core SDK) or `ext/*/tests/` (extensions)
175
-
-[ ] Tests use `unittest` — follow the existing test patterns in the relevant directory
176
-
-[ ] Verify tests pass: `python -m unittest discover -v ./tests` (or the relevant test directory)
181
+
-[ ] Add or update unit tests under `tests/` (core SDK) or `tests/ext/<name>/` (extensions)
182
+
-[ ] 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.warns` for the `flask_dapr` shim).
-[ ] Run `uv run ruff check --fix && uv run ruff format` and fix any remaining issues
181
-
-[ ] Run `uv run mypy` if you changed files covered by mypy (actor, aio, clients, conf, serializers, ext-grpc, ext-fastapi, flask_dapr)
188
+
-[ ] Run `uv run mypy` if you changed files covered by mypy (the `dapr` and `flask_dapr` packages, which includes all bundled extensions under `dapr.ext.*`)
182
189
183
190
### Examples (integration tests)
184
191
@@ -195,29 +202,28 @@ When completing any task on this project, work through this checklist. Not every
195
202
### Final verification
196
203
197
204
-[ ] Run `uv run ruff check --fix && uv run ruff format` — linting must be clean
198
-
-[ ] Run `uv run python -m unittest discover -v ./tests` — all unit tests must pass
205
+
-[ ] Run `uv run pytest -m "not e2e" ./tests --ignore=tests/integration --ignore=tests/examples` — all unit tests must pass
199
206
-[ ] If you touched examples: `uv run pytest tests/examples/test_<example-name>.py` to validate locally
200
207
-[ ] Commits must be signed off for DCO: `git commit -s`
|`setup.py`| PyPI publish helper (handles dev version suffixing) |
209
-
|`ext/*/pyproject.toml`| Extension package metadata and dependencies |
215
+
|`dapr/__init__.py`| Imports `_detect_legacy_extension_dists` to warn about legacy `dapr-ext-*` / `flask-dapr` installs that collide with the bundled extension files |
210
216
|`dapr/version/version.py`| SDK version string |
211
217
|`tests/examples/`| Output-based tests that validate examples by checking stdout |
212
218
|`tests/integration/`| Programmatic SDK tests using DaprClient directly |
213
219
214
220
## Gotchas
215
221
216
-
-**Namespace packages**: Do not add `__init__.py` to the top-level`dapr/` directory in extensions — it will break namespace package resolution.
222
+
-**Namespace packages**: `dapr.ext` is a PEP 420 implicit namespace package. Do **not** create `dapr/ext/__init__.py`; that would block any future externally-published`dapr.ext.*` distribution from coexisting with the core wheel on install.
217
223
-**Proto files**: Never manually edit anything under `dapr/proto/`. These are generated.
218
-
-**Extension independence**: Each extension is a separate PyPI package. Core SDK changes should not break extensions; extension changes should not require core SDK changes unless intentional.
224
+
-**Bundled extensions**: live under `dapr/ext/<name>/`, opted in via extras (`dapr[fastapi]`, etc.). The legacy `dapr-ext-*` and `flask-dapr` distributions are no longer published; legacy installs must be uninstalled before upgrading or `import dapr` will emit a `FutureWarning`.
219
225
-**DCO signoff**: PRs will be blocked by the DCO bot if commits lack `Signed-off-by`. Always use `git commit -s`.
220
226
-**Ruff version pinned**: `pyproject.toml` pins `ruff==0.14.1` in `[dependency-groups].dev`. Use `uv sync --all-packages --group dev` to get the exact version.
221
227
-**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.
222
228
-**Background processes in examples**: Examples that start background services (servers, subscribers) must include a cleanup step to stop them, or CI will hang.
223
-
-**Workflow is the most active area**: See `ext/dapr-ext-workflow/AGENTS.md` for workflow-specific architecture and constraints.
229
+
-**Workflow is the most active area**: See `dapr/ext/workflow/AGENTS.md` for workflow-specific architecture and constraints.
0 commit comments