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
Copy file name to clipboardExpand all lines: AGENTS.md
+11-13Lines changed: 11 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -61,15 +61,14 @@ Each extension is a **separate PyPI package** with its own `setup.cfg`, `setup.p
61
61
62
62
## Examples (integration test suite)
63
63
64
-
The `examples/` directory serves as both user-facing documentation and the project's integration test suite. Examples are validated in CI using [mechanical-markdown](https://pypi.org/project/mechanical-markdown/), which executes bash code blocks from README files and asserts expected output.
64
+
The `examples/` directory serves as both user-facing documentation and the project's integration test suite. Examples are validated by pytest-based integration tests in `tests/integration/`.
65
65
66
-
**See `examples/AGENTS.md`** for the full guide on example structure, validation, mechanical-markdown STEP blocks, and how to add new examples.
66
+
**See `examples/AGENTS.md`** for the full guide on example structure and how to add new examples.
67
67
68
68
Quick reference:
69
69
```bash
70
-
tox -e examples # Run all examples (needs Dapr runtime)
71
-
tox -e example-component -- state_store # Run a single example
72
-
cd examples && ./validate.sh state_store # Run directly
70
+
tox -e integration # Run all examples (needs Dapr runtime)
71
+
tox -e integration -- test_state_store.py # Run a single example
|`ext/*/setup.cfg`| Extension package metadata and dependencies |
222
-
|`examples/validate.sh`|Entry point for mechanical-markdown example validation|
220
+
|`tests/integration/`|Pytest-based integration tests that validate examples|
223
221
224
222
## Gotchas
225
223
@@ -228,6 +226,6 @@ When completing any task on this project, work through this checklist. Not every
228
226
-**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.
229
227
-**DCO signoff**: PRs will be blocked by the DCO bot if commits lack `Signed-off-by`. Always use `git commit -s`.
230
228
-**Ruff version pinned**: Dev requirements pin `ruff === 0.14.1`. Use this exact version to match CI.
231
-
-**Examples are integration tests**: Changing output format (log messages, print statements) can break example validation. Always check `expected_stdout_lines`in example READMEs when modifying user-visible output.
229
+
-**Examples are integration tests**: Changing output format (log messages, print statements) can break integration tests. Always check expected output in `tests/integration/` when modifying user-visible output.
232
230
-**Background processes in examples**: Examples that start background services (servers, subscribers) must include a cleanup step to stop them, or CI will hang.
233
231
-**Workflow is the most active area**: See `ext/dapr-ext-workflow/AGENTS.md` for workflow-specific architecture and constraints.
Keep conditional nesting to a minimum, and use guard clauses when possible.
7
+
Aim for medium "visual complexity": use intermediate variables to store results of nested/complex function calls, but don't create a new variable for everything.
8
+
Avoid comments unless there is an unusual gotcha, a complex algorithm or anything an experienced code reviewer needs to be aware of. Focus on making better Google-style docstrings instead.
9
+
10
+
The user is not always right. Be skeptical and do not blindly comply if something doesn't make sense.
The `examples/` directory serves as both **user-facing documentation** and the project's **integration test suite**. Each example is a self-contained application validated automatically in CI using [mechanical-markdown](https://pypi.org/project/mechanical-markdown/), which executes bash code blocks embedded in README files and asserts expected output.
3
+
The `examples/` directory serves as both **user-facing documentation** and the project's **integration test suite**. Each example is a self-contained application validated by pytest-based integration tests in `tests/integration/`.
4
4
5
5
## How validation works
6
6
7
-
1.`examples/validate.sh` is the entry point — it `cd`s into an example directory and runs `mm.py -l README.md`
8
-
2.`mm.py` (mechanical-markdown) parses `<!-- STEP -->` HTML comment blocks in the README
9
-
3. Each STEP block wraps a fenced bash code block that gets executed
10
-
4. stdout/stderr is captured and checked against `expected_stdout_lines` / `expected_stderr_lines`
11
-
5. Validation fails if any expected output line is missing
7
+
1. Each example has a corresponding test file in `tests/integration/` (e.g., `test_state_store.py`)
8
+
2. Tests use a `DaprRunner` helper (defined in `conftest.py`) that wraps `dapr run` commands
9
+
3.`DaprRunner.run()` executes a command and captures stdout; `DaprRunner.start()`/`stop()` manage background services
10
+
4. Tests assert that expected output lines appear in the captured output
12
11
13
12
Run examples locally (requires a running Dapr runtime via `dapr init`):
14
13
15
14
```bash
16
15
# All examples
17
-
tox -e examples
16
+
tox -e integration
18
17
19
18
# Single example
20
-
tox -e example-component -- state_store
21
-
22
-
# Or directly
23
-
cd examples && ./validate.sh state_store
19
+
tox -e integration -- test_state_store.py
24
20
```
25
21
26
22
In CI (`validate_examples.yaml`), examples run on all supported Python versions (3.10-3.14) on Ubuntu with a full Dapr runtime including Docker, Redis, and (for LLM examples) Ollama.
@@ -31,7 +27,7 @@ Each example follows this pattern:
5. Register the example in `tox.ini` under `[testenv:examples]` commands:
193
-
```
194
-
./validate.sh your-example-name
195
-
```
196
-
6. Test locally: `cd examples && ./validate.sh your-example-name`
197
-
198
-
## Common README template
199
-
200
-
```markdown
201
-
# Dapr [Building Block] Example
202
-
203
-
This example demonstrates how to use the Dapr [building block] API with the Python SDK.
204
-
205
-
## Pre-requisites
206
-
207
-
- [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started)
208
-
- Python 3.10+
209
-
210
-
## Install Dapr python-SDK
211
-
212
-
\`\`\`bash
213
-
pip3 install dapr dapr-ext-grpc
214
-
\`\`\`
215
-
216
-
## Run the example
217
-
218
-
<!-- STEP
219
-
name: Run example
220
-
expected_stdout_lines:
221
-
- '== APP == Expected output here'
222
-
timeout_seconds: 30
223
-
-->
224
-
225
-
\`\`\`bash
226
-
dapr run --app-id myapp --resources-path ./components/ python3 example.py
227
-
\`\`\`
228
-
229
-
<!-- END_STEP -->
230
-
231
-
## Cleanup
232
-
233
-
<!-- STEP
234
-
name: Cleanup
235
-
-->
236
-
237
-
\`\`\`bash
238
-
dapr stop --app-id myapp
239
-
\`\`\`
240
-
241
-
<!-- END_STEP -->
242
-
```
134
+
4. Write a `README.md` with introduction, pre-requisites, install instructions, and running instructions
135
+
5. Add a corresponding test in `tests/integration/test_<example_name>.py`:
136
+
- Use the `@pytest.mark.example_dir('<example-name>')` marker to set the working directory
137
+
- Use `dapr.run()` for scripts that exit on their own, `dapr.start()`/`dapr.stop()` for long-running services
138
+
- Assert expected output lines appear in the captured output
139
+
6. Test locally: `tox -e integration -- test_<example_name>.py`
243
140
244
141
## Gotchas
245
142
246
-
- **Output format changes break CI**: If you modify print statements or log output in SDK code, check whether any example's `expected_stdout_lines` depend on that output.
247
-
- **Background processes must be cleaned up**: Missing cleanup steps cause CI to hang.
143
+
- **Output format changes break tests**: If you modify print statements or log output in SDK code, check whether any integration test's expected lines depend on that output.
144
+
- **Background processes must be cleaned up**: The `DaprRunner` fixture handles cleanup on teardown, but tests should still call `dapr.stop()` to capture output.
248
145
- **Dapr prefixes output**: Application stdout appears as `== APP == <line>` when run via `dapr run`.
249
146
- **Redis is available in CI**: The CI environment has Redis running on `localhost:6379` — most component YAMLs use this.
250
147
- **Some examples need special setup**: `crypto` generates keys, `configuration` seeds Redis, `conversation` needs LLM config — check individual READMEs.
148
+
- **Infinite-loop example scripts**: Some example scripts (e.g., `invoke-caller.py`) have `while True` loops for demo purposes. Integration tests must either bypass these with HTTP API calls or use `dapr.run(until=...)` for early termination.
0 commit comments