Examples index¶
Learning path · step 5 of 8 — Curated task index. Prev: Python tutorial. Next: API reference.
examples/{cli,client}/is the source of truth for what's on disk; this page is the curated headline view.
One copy of each example, running against DHIS2 v41, v42, v43, and v44 alike. An example that exists for a single major lives under that major's subdirectory — examples/client/v43/ for the v43 schema divergences (v44 runs these too, since 2.44 ships the same features), examples/client/v41/ for the v41 wire quirks; see Schema diff: v41 -> v42 -> v43 for what they demonstrate.
Each entry below: file path → what it demonstrates → which concept doc explains it. This page is curated — it covers the headline examples per topic; not every single file shows up here. ls examples/{cli,client}/ is the source of truth, and each surface directory has a README of its own.
Examples come in two surfaces here; the MCP examples live in the dhis2w-mcp repository and the FHIR examples in the dhis2w-fhir repository:
- CLI (
examples/cli/*.sh) — bash invocations of thed2wTyper CLI. Run withbash examples/cli/<name>.shwith the venv onPATH(viasource .venv/bin/activateoruv run -- bash ...). - Client (
examples/client/*.py) — Python library usage. Run withuv run python examples/client/<name>.py.
Every example reads the active DHIS2 profile from .dhis2/profiles.toml / ~/.config/dhis2/profiles.toml / DHIS2_PROFILE env (see profiles). Assume a seeded local stack (make dhis2-run) unless stated otherwise.
CLI examples¶
| Example | What it demonstrates | Related docs |
|---|---|---|
metadata_round_trip.sh |
Cookbook — export → jq transform → diff → dry-run → import → live verify → revert | CLI tutorial / metadata plugin |
whoami.sh |
Simplest invocation — d2w system whoami + d2w system info |
system |
profile_list_verify.sh |
d2w profile list / verify / show |
profiles |
profile_oidc_config.sh |
Populate an OAuth2 profile by discovering DHIS2's OIDC endpoints | auth |
profile_oidc_login.sh |
Full OIDC login flow — profile add → login → verify → whoami | auth |
profile_session.sh |
Bind a profile to an existing browser login via --auth session + DHIS2_SESSION_COOKIE (plus optional DHIS2_SESSION_XSRF for CSRF-enforcing writes) |
auth |
metadata_list.sh |
d2w metadata list — field presets, filters, order, --all |
metadata plugin |
metadata_get.sh |
d2w metadata get <resource> <uid> — one object, narrowed by --fields |
metadata plugin |
metadata_patch.sh |
RFC 6902 JSON Patch — inline --set / --remove and file-based |
metadata plugin |
metadata_export.sh |
d2w metadata export — a narrow slice and the full catalog |
metadata plugin |
metadata_import.sh |
d2w metadata import — dry run, the commit, and --strategy DELETE |
metadata plugin |
metadata_export_filter.sh |
Per-resource filters + dangling-reference warning on export | metadata plugin |
metadata_diff.sh |
d2w metadata diff — bundle-vs-bundle or bundle-vs-live |
metadata plugin |
metadata_search.sh |
Cross-resource UID / code / name search via d2w metadata search <query> |
metadata plugin |
attribute_values.sh |
Cross-resource AttributeValue workflows via d2w metadata attributes |
metadata plugin |
options.sh |
OptionSet + Option workflows — d2w metadata option-sets get / find / sync |
metadata plugin |
legend_sets.sh |
d2w metadata legend-sets — create / get / clone / delete + the seeded LsDoseBand1 coverage dashboards |
legend sets API |
organisation_units.sh |
d2w metadata organisation-units + groups + group-sets + levels — tree walk, per-level rename, group + dimension round-trip |
organisation units API |
data_elements.sh |
d2w metadata data-elements + groups + group-sets — DE create, rename, legend-set attach, group + dimension round-trip |
data elements API |
indicators.sh |
d2w metadata indicators + groups + group-sets — numerator/denominator expression pre-flight, create, group + dimension round-trip |
indicators API |
program_indicators.sh |
d2w metadata program-indicators + groups — program-scoped expression validation + group membership (pair, no group-set) |
program indicators API |
category_options.sh |
d2w metadata category-options + groups + group-sets — validity-window creation + group + dimension round-trip |
category options API |
data_sets.sh |
d2w metadata data-sets + sections — DataSet create, DE attach (with per-set CC override), ordered Section round-trip |
data sets API |
validation_rules.sh |
d2w metadata validation-rules + their groups — the authoring flip side of maintenance validation run |
validation rules + predictors API |
predictors.sh |
d2w metadata predictors + their groups — the authoring flip side of maintenance predictors run |
validation rules + predictors API |
tracker_schema.sh |
d2w metadata tracked-entity-attributes + tracked-entity-types — create a unique-generated TEA + a Person TET and wire them together |
tracker schema API |
tracker_programs.sh |
d2w metadata programs — tracker + event Program authoring with PTEA enrollment form + OU scoping |
tracker schema API |
tracker_program_stages.sh |
d2w metadata program-stages — stage authoring with ordered PSDE list + reorder + per-DE compulsory flag |
tracker schema API |
messaging.sh |
d2w messaging send / get / reply / set-priority / assign / delete — ticket-workflow round-trip |
messaging plugin |
program_rules.sh |
d2w metadata program-rules — vars, validate-expression, where-de-is-used |
metadata plugin |
sql_views.sh |
d2w metadata list sqlViews / get / execute / refresh / adhoc across the VIEW / QUERY / MATERIALIZED_VIEW shapes |
SQL views API |
aggregate_data_values.sh |
Aggregate data values — read / write a single value / bulk file push | aggregate |
tracker_reads.sh |
Tracked entities by type, enrollments, events, bulk import | tracker |
tracker_register_and_followup.sh |
Canonical tracker-program clinic intake — register, log an event, query outstanding enrollments | tracker |
tracker_event_program.sh |
Event-only WITHOUT_REGISTRATION program — standalone events with no enrollment | tracker |
analytics_query.sh |
Aggregated analytics queries + resource-table refresh | analytics |
analytics_outlier_tracked_entities.sh |
Outlier detection + tracked-entity analytics | analytics |
user_administration.sh |
d2w user — list / get / invite / reinvite / reset-password |
user plugin |
user_groups.sh |
d2w user group admin workflows |
user groups + roles |
user_roles.sh |
d2w user role admin workflows |
user groups + roles |
schema.sh |
d2w schema <type> — describe a generated type's fields (offline; reflects the active version tree) |
CLI reference |
route_register_and_run.sh |
d2w route lifecycle across every upstream auth type |
auth schemes |
customize_login.sh |
Brand the DHIS2 login page + top menu | customize plugin |
doctor.sh |
d2w doctor — probe every DHIS2_ISSUES.md gotcha + metadata-health check |
doctor plugin |
maintenance.sh |
d2w maintenance — background tasks, cache, cleanup, integrity |
maintenance plugin |
files.sh |
d2w files — documents (URL + binary round-trip) + fileResource (MESSAGE_ATTACHMENT round-trip) |
files plugin |
visualizations.sh |
d2w metadata visualizations + d2w metadata dashboards — flag-driven viz create, clone, dashboard compose |
visualizations guide |
maps.sh |
d2w metadata maps — thematic choropleth authoring via REST |
maps API |
apps.sh |
d2w apps list / hub-list / hub-url / update --dry-run / update --all / reload over /api/apps + /api/appHub |
apps API |
dev_codegen.sh |
d2w dev codegen — regenerate the typed client from a live instance |
codegen |
profile_pat.sh |
d2w profile pat create — provision a PAT as admin |
auth |
dev_sample.sh |
d2w dev sample ... — inject fixtures + verify end-to-end |
manual testing |
dev_uid.sh |
d2w dev uid — mint 11-char DHIS2 UIDs client-side, offline |
CLI reference |
Client examples (Python library)¶
| Example | What it demonstrates | Related docs |
|---|---|---|
bulk_patch_from_csv.py |
Cookbook — apply a CSV of patches concurrently via asyncio.gather + JsonPatchOpAdapter |
metadata plugin |
profile_drift_check.py |
Cookbook — diff metadata between two profiles, exit non-zero on drift (CI template) | metadata plugin |
retry_policy.py |
Cookbook — RetryPolicy for transient 5xx / connection errors on batch workflows |
client library tutorial |
task_await.py |
Cookbook — client.tasks.await_completion blocks on analytics refresh / metadata import / etc. |
client library tutorial |
concurrent_bulk.py |
Cookbook — fan-out patterns (naive gather → bounded semaphore → tuned pool + retries) with live timings | client architecture |
integrity_issues_stream.py |
Cookbook — client.maintenance.iter_integrity_issues streams tagged issues, severity histogram, early-break scan |
maintenance plugin |
system_cache.py |
Cookbook — client.system cache: info() primed on connect, default_category_combo_uid(), per-key setting(), invalidate + refetch |
system API |
files_documents.py |
Cookbook — client.files documents + fileResource round-trip; external URL docs, binary two-step upload, MESSAGE_ATTACHMENT round-trip |
files plugin |
bulk_delete.py |
Cookbook — client.metadata.delete_bulk / delete_bulk_multi for one-call teardown via /api/metadata?importStrategy=DELETE |
metadata accessor |
metadata_patch_bulk.py |
Cookbook — client.metadata.patch_bulk fans out RFC 6902 patches across many UIDs with per-UID failure capture |
metadata accessor |
bulk_save.py |
Cookbook — client.resources.<res>.save_bulk(items) writes a typed list of one resource in one call |
metadata accessor |
metadata_dry_run.py |
Cookbook — client.metadata.dry_run(...) as the pre-commit gate, and the refusal read back off the Dhis2ApiError |
metadata accessor |
stream_data_values.py |
Cookbook — client.data_values.stream four ways: bytes, sync generator, Path (CSV), 1000-row file with timing |
data values streaming |
stream_analytics.py |
Cookbook — client.analytics.stream_to for JSON / CSV / rawData exports to disk with per-format timing |
analytics streaming |
data_values_export.py |
Cookbook — client.data_values.export as a typed DataValueSet, then client.stream of the same export to a Path, a BytesIO, and a chunk callable |
data values |
data_values_import_atomic.py |
Cookbook — the same partly invalid payload imported under atomic_mode="ALL" and "OBJECT", reading the summary from a 200 or a 409 alike |
data values |
complete_data_set_registrations_read.py |
Cookbook — client.complete_data_set_registrations.export lists which forms are reported complete below the root over a date range |
aggregate |
tracker_reads.py |
Cookbook — client.tracker.tracked_entities / enrollments / events page through one program's records with typed row parsing |
tracker reads |
analytics_event_query.py |
Cookbook — client.analytics.event_query / enrollment_query line lists for the seeded Child Programme |
analytics streaming |
analytics_tables_poll_once.py |
Cookbook — client.maintenance.run_analytics_tables followed with client.tasks.poll_once, one poll per tick with a carried cursor |
tasks module |
messaging_with_attachment.py |
Cookbook — client.messaging.send + MESSAGE_ATTACHMENT fileResource pairing; full inbox lifecycle (list, reply, mark-read, delete) |
messaging plugin |
validation_rules.py |
Cookbook — client.validation workflow: expression validation, run analysis, list persisted results |
validation API |
predictors.py |
Cookbook — client.predictors.run_all over a date range with import-count envelope |
validation API |
whoami.py |
Minimal — default profile → call /api/me |
client library tutorial |
library_only_auth.py |
Library-only auth for PyPI consumers without dhis2w-core |
auth |
profile_resolver.py |
Use a DHIS2 profile from Python via dhis2w-core.open_client |
profiles |
profile_crud.py |
Profile CRUD — in-memory Profile(...) + on-disk add/rename/set-default/remove through the profile-plugin service |
profiles |
oidc_login.py |
OAuth 2.1 authorization-code + PKCE flow; auto-dispatches to Playwright when DHIS2_USERNAME+DHIS2_PASSWORD are set |
auth |
list_data_elements.py |
Generated typed resource accessors | metadata CRUD |
enum_round_trip.py |
Generated StrEnums — type-safe access to DHIS2 CONSTANT values | typed schemas |
dashboard_item_users.py |
DashboardItem.user -> users (rename + reshape) |
schema diff v41 -> v42 -> v43 / versioning |
tracked_entity_attribute_favorites.py |
TrackedEntityAttribute.favorite -> favorites + 6 new search fields |
schema diff v41 -> v42 -> v43 |
program_set_labels.py |
v43-only — client.programs.set_labels overrides enrollmentsLabel / eventsLabel / programStagesLabel |
schema diff v41 -> v42 -> v43 |
program_set_change_log.py |
v43-only — toggle Program.enableChangeLog (server-side enrollment + event audit) |
schema diff v41 -> v42 -> v43 |
program_set_enrollment_category_combo.py |
v43-only — set the alt enrollmentCategoryCombo reference applied at enrollment time |
schema diff v41 -> v42 -> v43 |
event_visualization_fix_headers.py |
EventChart / EventReport / EventVisualization add fixColumnHeaders / fixRowHeaders / hideEmptyColumns |
schema diff v41 -> v42 -> v43 |
map_basemaps.py |
Map.basemaps v43-only addition + new Basemap model |
schema diff v41 -> v42 -> v43 |
section_user_removed.py |
Section.user removed in v43 (also Section.favorite) |
schema diff v41 -> v42 -> v43 |
removed_resources.py |
pushAnalysis / externalFileResource / dataInputPeriods removed in v43 |
schema diff v41 -> v42 -> v43 |
metadata_filter_order_paging.py |
Full query DSL — filters, rootJunction, order, server-side paging | metadata plugin |
metadata_patch.py |
RFC 6902 JSON Patch — generated accessor + service + adapter paths | metadata plugin |
metadata_export.py |
service.export_metadata — a typed MetadataBundle, walked and narrowed by per-resource filters |
metadata plugin |
metadata_diff.py |
service.diff_bundles + diff_bundle_against_instance |
metadata plugin |
metadata_bulk_import.py |
service.import_metadata — a typed bundle pushed, dry run then committed |
metadata plugin |
metadata_search.py |
Cross-resource UID / code / name search via client.metadata.search |
metadata plugin |
metadata_usage.py |
Reverse-reference lookup "what points at this UID?" via client.metadata.usage |
metadata plugin |
attribute_values.py |
AttributeValuesAccessor across every resource with an attributeValues field |
metadata plugin |
options_integration.py |
Every method on OptionSetsAccessor — list / get / find / sync |
metadata plugin |
legend_sets.py |
client.legend_sets.create_from_spec + VisualizationSpec(legend_set=...) — colour bands attached to a throw-away viz |
legend sets API |
organisation_units.py |
client.organisation_units + groups + group-sets + levels — descendants walk, rename-by-level, membership + dimension round-trip |
organisation units API |
data_elements.py |
client.data_elements + groups + group-sets — keyword-arg create, rename, per-item membership, dimension |
data elements API |
indicators.py |
client.indicators.validate_expression pre-flight + numerator/denominator create + group + dimension round-trip |
indicators API |
program_indicators.py |
client.program_indicators + groups — program-scoped expression validation + EVENT/ENROLLMENT create + group round-trip (pair, no group-set) |
program indicators API |
category_options.py |
client.category_options validity-window helper + groups + group-sets round-trip |
category options API |
data_sets.py |
client.data_sets + client.sections — DataSet create, DE attach, ordered Section round-trip |
data sets API |
validation_rules.py |
client.validation_rules + its groups — CRUD round-trip + group membership |
validation rules + predictors API |
predictors.py |
client.predictors + its groups — CRUD round-trip + group membership |
validation rules + predictors API |
tracker_schema.py |
client.tracked_entity_attributes + client.tracked_entity_types — TEA + TET round-trip with the TETA linkage helpers |
tracker schema API |
tracker_programs.py |
client.programs — tracker Program with PTEA + OU linkage, using the TET + TEA from step 1 |
tracker schema API |
program_rules.py |
Every method on ProgramRulesAccessor — get, vars, validate, where-DE-used |
metadata plugin |
sql_views.py |
SqlViewsAccessor list / get / execute / refresh / adhoc across the three view shapes |
SQL views API |
sql_view_runner.py |
Three ways to use SqlViewRunner — by UID, ad-hoc query, named bindings |
SQL views API |
indicator_crud.py |
Create a typed Indicator with a formula, use it, clean up | metadata CRUD |
data_set_crud.py |
Full CRUD lifecycle for a data set | metadata CRUD |
org_unit_crud.py |
Full CRUD lifecycle for an organisation unit | metadata CRUD |
geojson_org_units.py |
Pull org units as GeoJSON (validated via geojson-pydantic) | metadata CRUD |
push_data_value.py |
Write one aggregate data value against the seeded dataset | aggregate |
tracker_lifecycle.py |
Create a tracked entity with an enrollment + event | tracker |
tracker_clinic_intake.py |
Canonical tracker-program intake via client.tracker.register / add_event / outstanding |
tracker |
tracker_event_program.py |
WITHOUT_REGISTRATION event-only program — one-shot events via add_event without an enrollment |
tracker |
analytics_query.py |
Aggregated analytics + resource-table refresh | analytics |
analytics_events_enrollments.py |
Event + enrollment analytics queries | analytics |
analytics_outlier_tracked_entities.py |
Outlier detection + tracked-entity analytics | analytics |
task_polling.py |
Watch an analytics-refresh job to completion | maintenance plugin |
doctor.py |
Programmatic probe results for CI / monitoring | doctor plugin |
user_administration.py |
User administration via the Python client | user plugin |
user_groups.py |
User groups via the Python client | user groups + roles |
user_roles.py |
User roles via the Python client | user groups + roles |
sharing.py |
Typed sharing helpers — read + replace on any object | sharing |
customize_login.py |
Brand a DHIS2 instance programmatically | customize plugin |
error_handling.py |
Dhis2ApiError, WebMessage conflicts, AuthenticationError |
errors |
bootstrap_zero_to_data.py |
End-to-end — zero org unit to a data value in one script | client library tutorial |
viz_create_basic.py |
Simplest visualization spec → create → verify axes | visualizations guide |
viz_multiline_by_province.py |
Multi-line time-series with analytics-probe sanity check | visualizations guide |
viz_pivot_table.py |
PIVOT_TABLE — organisation units down the side, periods across the top | visualizations guide |
viz_single_value.py |
SINGLE_VALUE — the KPI tile, and why its grid collapses to one cell | visualizations guide |
viz_clone_and_modify.py |
Clone an existing chart, verify independence | visualizations guide |
dashboard_compose.py |
Assemble a dashboard from scratch with typed DashboardSlots |
visualizations guide |
map_create_choropleth.py |
Build a thematic choropleth from a typed MapSpec + MapLayerSpec |
maps API |
apps.py |
client.apps.list_apps / hub_list / get_hub_url — library surface for the apps plugin |
apps API |
MCP examples¶
The MCP examples live with the MCP server in the dhis2w-mcp plugin pack: its examples/ tree carries one script per MCP plugin group, each calling the tools through an in-process FastMCP client, and its documentation site explains the tools they call.
FHIR examples¶
The FHIR examples live with the FHIR toolchain in the dhis2w-fhir plugin pack: its examples/ tree carries the d2w fhir scripts, the library examples, the evaluation engine examples, and nine complete example guides, and its documentation site is the guide series they sit under.
External plugin example¶
examples/plugin-external/ — a minimal runnable external plugin (own pyproject.toml, entry-point registration, CLI + MCP hooks). See external plugins for the contract.
Running the whole set¶
make verify-examples runs every example on this page against the active profile and prints a per-surface PASS / FAIL / TIMEOUT / SKIP table. Two things decide what a batch pass actually executes:
- Skipped by default. An example that needs Chromium, a human-clicked login, or public-internet egress carries a stated reason in
SKIP_BY_DEFAULTininfra/scripts/verify_examples.py.--include-browseropts the UI-driven set back in. - Skipped when the environment is missing. An example that reads a real secret or endpoint out of the environment - a personal access token, a caller's own DHIS2 credentials - runs when every variable it names is set and skips naming the missing ones otherwise. An unprovisioned machine is a fact about the machine, not a defect in the example, and
make verify-examplessourcesinfra/home/credentials/.env.authfirst so a seeded checkout provides them all.
make refresh-and-verify is the full cycle: rebuild the seeded stack, seed the tokens, refresh the analytics tables the analytics examples read, then run the suite.
How example coverage maps to features¶
- Every top-level CLI domain has at least one example. See CLI reference for the full command tree.
- Every plugin with a service layer has both a CLI and client example. Pairs are intentional — the CLI shows the user-facing path, the client shows what library callers do.
- Every MCP plugin group has representative examples in the
dhis2w-mcprepository.
When adding a new plugin / command / MCP tool: update this file alongside the feature PR so the catalogue stays in sync.