Add patient_sex_banner extension - #424
Conversation
Covers the Licensing & legal section of the Open Source Plugin Publishing Checklist.
Updated README to improve clarity and added image.
|
cerberus review |
|
Can you fix that? Add appropriate tests |
Drop PLUGIN_CREATED / PLUGIN_UPDATED from RESPONDS_TO so the protocol only ever reconciles the single patient on a PATIENT_CREATED / PATIENT_UPDATED event, instead of running Patient.objects.all() and emitting one effect per patient on every install/update. Add pytest coverage for the add / remove / missing-patient paths.
Add BackfillBanners, a CronTask that reconciles the sex banner across the active-patient panel in bounded pages (PAGE_SIZE=500) after install, then goes dormant — restoring existing-patient coverage without the all-at-once scan that lifecycle events caused. Extract the shared banner-building logic into banner.py so the event handler and the backfill stay in sync, and register the cron in CANVAS_MANIFEST.json. Add pytest coverage for the backfill (sweep / advance / dormant paths) and the shared helper; update the README to describe the paged backfill.
|
cerberus review |
| ] | ||
|
|
||
| def compute(self) -> list[Effect]: | ||
| try: |
There was a problem hiding this comment.
🟡 Nit — Use of deprecated self.target API
The code uses self.target to access the patient ID, but this property is deprecated in SDK 0.11.0 and will be removed in 1.0.0. Replace with self.event.target.id to use the non-deprecated API.
Why cerberus flagged this
The context digest explicitly confirms: self.target is a deprecated property (deprecated_in="0.11.0", removed in 1.0.0) returning self.event.target.id. The PR's my_protocol.py:25 uses Patient.objects.get(id=self.target), which is functionally correct today but relies on a deprecated API that will be removed in a future SDK version. This is not a runtime-breaking bug now, not a security issue, not data corruption — it's a forward-compatibility/style concern. That aligns with REVIEW.md's nit bucket (not one of the "Always check" Important categories). The claim is well-grounded in the provided definitions and doesn't overstate severity.
There was a problem hiding this comment.
Fixed in 9fb20c7 — replaced the deprecated self.target with self.event.target.id, the supported accessor for the event's patient key since SDK 0.11.0. Updated the handler test's fixture to match; 14 pytests still green.
self.target is deprecated in SDK 0.11.0 and slated for removal in 1.0.0; self.event.target.id is the supported accessor for the event's patient key.
🧵 Jessica Herbert cc @JessicaHerbert
What it does
Adds
patient_sex_banner, a reference plugin that puts a banner alert on a patient's chart whenever their sex at birth is recorded as something other than Female or Male (e.g. Other, Unknown, or unset):The banner is placed on the chart timeline, chart, and patient profile. When the sex at birth is corrected to Female or Male, the banner is removed automatically.
Protocol(event handler) responds toPATIENT_CREATED/PATIENT_UPDATEDand reconciles that one patient's banner viaPatient.objects.get(id=self.target).BackfillBanners(cron task) backfills existing patients after install: it sweeps the active-patient panel in bounded pages (PAGE_SIZE=500, cursor ondbid), adds the banner to anyone whose sex at birth isn't M/F, then goes dormant. This covers pre-existing patients without the all-at-once, instance-wide scan that plugin-lifecycle events would cause.Shared banner-building logic lives in
banner.pyso the two paths always build the same banner.Who it's for
Practices that electronically prescribe controlled substances (EPCS) and may register patients whose sex at birth is something other than M/F — the mismatch is surfaced on the chart before prescribing, rather than surfacing as a failed transmission at the pharmacy.
Layout
No secrets or settings. Banner text, placements, and intent are fixed in code.
Open Source Plugin Publishing Checklist
name/descriptionpopulated; README has all six required sections + a screenshot.LICENSE(MIT) andlicense = "MIT"inpyproject.toml; manifestlicensealso set toMIT.Tests
14 pytests, all green (Canvas SDK mocked in
conftest.py, so the suite runs without a live instance):tests/test_banner.py— the shared add/remove/reconcile helpers.tests/protocols/test_my_protocol.py— event handler reconciles only the event patient (neverobjects.all()), and returns no effects for a stale/deleted patient.tests/protocols/test_backfill.py— cron sweeps from zero, advances the cursor on a full page, goes dormant on a partial/empty page, and no-ops (without querying) once dormant.Review fix
Addressed the Cerberus finding: removed
PLUGIN_CREATED/PLUGIN_UPDATEDfromRESPONDS_TO. The handler previously ranPatient.objects.all()on plugin lifecycle events, emitting one effect per patient across the whole instance on every install/update. Existing-patient coverage is now provided by the paged, dormant-when-doneBackfillBannerscron instead.Generated by the Investigator