canvas 0.33.0__py3-none-any.whl → 0.33.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of canvas might be problematic. Click here for more details.

Files changed (254) hide show
  1. {canvas-0.33.0.dist-info → canvas-0.33.1.dist-info}/METADATA +2 -1
  2. canvas-0.33.1.dist-info/RECORD +272 -0
  3. canvas_sdk/__init__.py +3 -0
  4. canvas_sdk/commands/__init__.py +1 -1
  5. canvas_sdk/commands/base.py +3 -0
  6. canvas_sdk/commands/commands/__init__.py +1 -0
  7. canvas_sdk/commands/commands/adjust_prescription.py +3 -0
  8. canvas_sdk/commands/commands/allergy.py +7 -0
  9. canvas_sdk/commands/commands/assess.py +2 -0
  10. canvas_sdk/commands/commands/close_goal.py +3 -0
  11. canvas_sdk/commands/commands/diagnose.py +3 -0
  12. canvas_sdk/commands/commands/exam.py +3 -0
  13. canvas_sdk/commands/commands/family_history.py +3 -0
  14. canvas_sdk/commands/commands/follow_up.py +3 -0
  15. canvas_sdk/commands/commands/goal.py +3 -0
  16. canvas_sdk/commands/commands/history_present_illness.py +3 -0
  17. canvas_sdk/commands/commands/imaging_order.py +3 -0
  18. canvas_sdk/commands/commands/instruct.py +3 -0
  19. canvas_sdk/commands/commands/lab_order.py +3 -0
  20. canvas_sdk/commands/commands/medical_history.py +3 -0
  21. canvas_sdk/commands/commands/medication_statement.py +2 -0
  22. canvas_sdk/commands/commands/past_surgical_history.py +3 -0
  23. canvas_sdk/commands/commands/perform.py +3 -0
  24. canvas_sdk/commands/commands/plan.py +3 -0
  25. canvas_sdk/commands/commands/prescribe.py +8 -0
  26. canvas_sdk/commands/commands/questionnaire/__init__.py +3 -13
  27. canvas_sdk/commands/commands/questionnaire/question.py +10 -0
  28. canvas_sdk/commands/commands/reason_for_visit.py +3 -0
  29. canvas_sdk/commands/commands/refer.py +3 -0
  30. canvas_sdk/commands/commands/refill.py +3 -0
  31. canvas_sdk/commands/commands/remove_allergy.py +3 -0
  32. canvas_sdk/commands/commands/resolve_condition.py +3 -0
  33. canvas_sdk/commands/commands/review_of_systems.py +3 -0
  34. canvas_sdk/commands/commands/stop_medication.py +3 -0
  35. canvas_sdk/commands/commands/structured_assessment.py +3 -0
  36. canvas_sdk/commands/commands/task.py +7 -0
  37. canvas_sdk/commands/commands/update_diagnosis.py +3 -0
  38. canvas_sdk/commands/commands/update_goal.py +3 -0
  39. canvas_sdk/commands/commands/vitals.py +3 -0
  40. canvas_sdk/commands/constants.py +8 -0
  41. canvas_sdk/effects/__init__.py +1 -1
  42. canvas_sdk/effects/banner_alert/__init__.py +1 -1
  43. canvas_sdk/effects/banner_alert/add_banner_alert.py +3 -0
  44. canvas_sdk/effects/banner_alert/remove_banner_alert.py +3 -0
  45. canvas_sdk/effects/base.py +7 -0
  46. canvas_sdk/effects/billing_line_item/__init__.py +5 -1
  47. canvas_sdk/effects/billing_line_item/add_billing_line_item.py +3 -0
  48. canvas_sdk/effects/billing_line_item/remove_billing_line_item.py +3 -0
  49. canvas_sdk/effects/billing_line_item/update_billing_line_item.py +3 -0
  50. canvas_sdk/effects/launch_modal.py +3 -0
  51. canvas_sdk/effects/patient_chart_summary_configuration.py +3 -0
  52. canvas_sdk/effects/patient_portal/__init__.py +1 -0
  53. canvas_sdk/effects/patient_portal/application_configuration.py +3 -0
  54. canvas_sdk/effects/patient_portal/form_result.py +3 -0
  55. canvas_sdk/effects/patient_portal_menu_configuration.py +3 -0
  56. canvas_sdk/effects/patient_profile_configuration.py +5 -1
  57. canvas_sdk/effects/protocol_card/__init__.py +1 -1
  58. canvas_sdk/effects/protocol_card/protocol_card.py +6 -0
  59. canvas_sdk/effects/questionnaire_result.py +3 -0
  60. canvas_sdk/effects/send_invite.py +3 -0
  61. canvas_sdk/effects/show_button.py +3 -0
  62. canvas_sdk/effects/simple_api.py +9 -0
  63. canvas_sdk/effects/surescripts/__init__.py +2 -2
  64. canvas_sdk/effects/surescripts/surescripts_messages.py +7 -0
  65. canvas_sdk/effects/task/__init__.py +6 -1
  66. canvas_sdk/effects/task/task.py +8 -0
  67. canvas_sdk/effects/update_user.py +3 -0
  68. canvas_sdk/effects/widgets/__init__.py +1 -1
  69. canvas_sdk/effects/widgets/portal_widget.py +3 -0
  70. canvas_sdk/events/__init__.py +6 -1
  71. canvas_sdk/events/base.py +3 -0
  72. canvas_sdk/handlers/__init__.py +1 -1
  73. canvas_sdk/handlers/action_button.py +6 -0
  74. canvas_sdk/handlers/application.py +3 -0
  75. canvas_sdk/handlers/base.py +3 -0
  76. canvas_sdk/handlers/cron_task.py +3 -0
  77. canvas_sdk/handlers/simple_api/__init__.py +3 -2
  78. canvas_sdk/handlers/simple_api/api.py +26 -1
  79. canvas_sdk/handlers/simple_api/exceptions.py +10 -0
  80. canvas_sdk/handlers/simple_api/security.py +21 -5
  81. canvas_sdk/handlers/simple_api/tools.py +9 -0
  82. canvas_sdk/protocols/__init__.py +1 -1
  83. canvas_sdk/protocols/base.py +3 -0
  84. canvas_sdk/protocols/clinical_quality_measure.py +6 -1
  85. canvas_sdk/protocols/timeframe.py +3 -0
  86. canvas_sdk/questionnaires/__init__.py +1 -1
  87. canvas_sdk/questionnaires/utils.py +7 -0
  88. canvas_sdk/templates/__init__.py +1 -1
  89. canvas_sdk/templates/utils.py +3 -0
  90. canvas_sdk/utils/__init__.py +1 -1
  91. canvas_sdk/utils/http.py +69 -35
  92. canvas_sdk/utils/plugins.py +4 -0
  93. canvas_sdk/utils/stats.py +11 -0
  94. canvas_sdk/v1/__init__.py +1 -0
  95. canvas_sdk/v1/apps.py +3 -0
  96. canvas_sdk/v1/data/__init__.py +2 -2
  97. canvas_sdk/v1/data/allergy_intolerance.py +3 -0
  98. canvas_sdk/v1/data/appointment.py +7 -0
  99. canvas_sdk/v1/data/assessment.py +3 -0
  100. canvas_sdk/v1/data/banner_alert.py +3 -0
  101. canvas_sdk/v1/data/base.py +3 -0
  102. canvas_sdk/v1/data/billing.py +7 -0
  103. canvas_sdk/v1/data/care_team.py +7 -0
  104. canvas_sdk/v1/data/command.py +3 -0
  105. canvas_sdk/v1/data/common.py +18 -0
  106. canvas_sdk/v1/data/condition.py +7 -0
  107. canvas_sdk/v1/data/coverage.py +14 -0
  108. canvas_sdk/v1/data/detected_issue.py +3 -0
  109. canvas_sdk/v1/data/device.py +3 -0
  110. canvas_sdk/v1/data/imaging.py +7 -0
  111. canvas_sdk/v1/data/lab.py +16 -0
  112. canvas_sdk/v1/data/medication.py +3 -0
  113. canvas_sdk/v1/data/note.py +9 -0
  114. canvas_sdk/v1/data/observation.py +9 -0
  115. canvas_sdk/v1/data/organization.py +3 -0
  116. canvas_sdk/v1/data/patient.py +18 -2
  117. canvas_sdk/v1/data/practicelocation.py +7 -0
  118. canvas_sdk/v1/data/protocol_override.py +7 -0
  119. canvas_sdk/v1/data/questionnaire.py +16 -3
  120. canvas_sdk/v1/data/reason_for_visit.py +3 -0
  121. canvas_sdk/v1/data/staff.py +3 -0
  122. canvas_sdk/v1/data/task.py +12 -0
  123. canvas_sdk/v1/data/team.py +8 -1
  124. canvas_sdk/v1/data/user.py +3 -0
  125. canvas_sdk/v1/models.py +2 -0
  126. canvas_sdk/value_set/__init__.py +1 -0
  127. canvas_sdk/value_set/_utilities.py +16 -0
  128. canvas_sdk/value_set/custom.py +4 -0
  129. canvas_sdk/value_set/hcc2018.py +3 -0
  130. canvas_sdk/value_set/v2022/__init__.py +1 -0
  131. canvas_sdk/value_set/v2022/adverse_event.py +3 -0
  132. canvas_sdk/value_set/v2022/allergy.py +5 -0
  133. canvas_sdk/value_set/v2022/assessment.py +5 -0
  134. canvas_sdk/value_set/v2022/communication.py +5 -0
  135. canvas_sdk/value_set/v2022/condition.py +5 -0
  136. canvas_sdk/value_set/v2022/device.py +5 -0
  137. canvas_sdk/value_set/v2022/diagnostic_study.py +5 -0
  138. canvas_sdk/value_set/v2022/encounter.py +5 -0
  139. canvas_sdk/value_set/v2022/immunization.py +5 -0
  140. canvas_sdk/value_set/v2022/individual_characteristic.py +5 -0
  141. canvas_sdk/value_set/v2022/intervention.py +5 -0
  142. canvas_sdk/value_set/v2022/laboratory_test.py +5 -0
  143. canvas_sdk/value_set/v2022/medication.py +5 -0
  144. canvas_sdk/value_set/v2022/physical_exam.py +5 -0
  145. canvas_sdk/value_set/v2022/procedure.py +5 -0
  146. canvas_sdk/value_set/v2022/symptom.py +3 -0
  147. canvas_sdk/value_set/value_set.py +9 -0
  148. canvas_sdk/views/__init__.py +1 -0
  149. logger/__init__.py +2 -0
  150. logger/logger.py +3 -0
  151. plugin_runner/aws_headers.py +1 -1
  152. plugin_runner/load_all_plugins.py +202 -0
  153. plugin_runner/plugin_runner.py +21 -24
  154. plugin_runner/sandbox.py +497 -115
  155. settings.py +5 -2
  156. canvas-0.33.0.dist-info/RECORD +0 -366
  157. canvas_cli/apps/auth/tests.py +0 -155
  158. canvas_cli/apps/plugin/tests.py +0 -85
  159. canvas_cli/conftest.py +0 -28
  160. canvas_cli/tests.py +0 -217
  161. canvas_cli/utils/context/tests.py +0 -131
  162. canvas_cli/utils/print/tests.py +0 -69
  163. canvas_cli/utils/urls/tests.py +0 -12
  164. canvas_cli/utils/validators/tests.py +0 -37
  165. canvas_sdk/commands/tests/protocol/__init__.py +0 -0
  166. canvas_sdk/commands/tests/protocol/tests.py +0 -83
  167. canvas_sdk/commands/tests/schema/__init__.py +0 -0
  168. canvas_sdk/commands/tests/schema/tests.py +0 -108
  169. canvas_sdk/commands/tests/test_base_command.py +0 -81
  170. canvas_sdk/commands/tests/test_utils.py +0 -375
  171. canvas_sdk/commands/tests/unit/__init__.py +0 -0
  172. canvas_sdk/commands/tests/unit/tests.py +0 -278
  173. canvas_sdk/effects/banner_alert/tests.py +0 -288
  174. canvas_sdk/effects/protocol_card/tests.py +0 -191
  175. canvas_sdk/questionnaires/tests/__init__.py +0 -0
  176. canvas_sdk/questionnaires/tests/test_utils.py +0 -74
  177. canvas_sdk/templates/tests/__init__.py +0 -0
  178. canvas_sdk/templates/tests/test_utils.py +0 -43
  179. canvas_sdk/tests/__init__.py +0 -0
  180. canvas_sdk/tests/handlers/__init__.py +0 -0
  181. canvas_sdk/tests/handlers/test_simple_api.py +0 -1167
  182. canvas_sdk/utils/tests.py +0 -72
  183. canvas_sdk/value_set/tests/test_value_sets.py +0 -72
  184. plugin_runner/tests/__init__.py +0 -0
  185. plugin_runner/tests/fixtures/plugins/example_plugin/CANVAS_MANIFEST.json +0 -29
  186. plugin_runner/tests/fixtures/plugins/example_plugin/README.md +0 -12
  187. plugin_runner/tests/fixtures/plugins/example_plugin/__init__.py +0 -0
  188. plugin_runner/tests/fixtures/plugins/example_plugin/protocols/__init__.py +0 -0
  189. plugin_runner/tests/fixtures/plugins/example_plugin/protocols/my_protocol.py +0 -18
  190. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/CANVAS_MANIFEST.json +0 -38
  191. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/README.md +0 -11
  192. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/__init__.py +0 -0
  193. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/my_protocol.py +0 -33
  194. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/__init__.py +0 -3
  195. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/base.py +0 -6
  196. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/__init__.py +0 -5
  197. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/base.py +0 -4
  198. plugin_runner/tests/fixtures/plugins/test_load_questionnaire/CANVAS_MANIFEST.json +0 -52
  199. plugin_runner/tests/fixtures/plugins/test_load_questionnaire/README.md +0 -11
  200. plugin_runner/tests/fixtures/plugins/test_load_questionnaire/protocols/__init__.py +0 -0
  201. plugin_runner/tests/fixtures/plugins/test_load_questionnaire/protocols/my_protocol.py +0 -39
  202. plugin_runner/tests/fixtures/plugins/test_load_questionnaire/questionnaires/example_questionnaire.yml +0 -61
  203. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/CANVAS_MANIFEST.json +0 -29
  204. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/README.md +0 -12
  205. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/__init__.py +0 -0
  206. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/base.py +0 -10
  207. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/__init__.py +0 -0
  208. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/my_protocol.py +0 -18
  209. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/CANVAS_MANIFEST.json +0 -29
  210. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/README.md +0 -12
  211. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/__init__.py +0 -0
  212. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/base.py +0 -10
  213. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/__init__.py +0 -0
  214. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/my_protocol.py +0 -18
  215. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/CANVAS_MANIFEST.json +0 -29
  216. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/README.md +0 -12
  217. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/__init__.py +0 -0
  218. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/base.py +0 -3
  219. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/__init__.py +0 -0
  220. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/my_protocol.py +0 -18
  221. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/CANVAS_MANIFEST.json +0 -29
  222. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/README.md +0 -12
  223. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/__init__.py +0 -0
  224. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/base.py +0 -6
  225. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/__init__.py +0 -0
  226. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/my_protocol.py +0 -18
  227. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/CANVAS_MANIFEST.json +0 -29
  228. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/README.md +0 -12
  229. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/__init__.py +0 -0
  230. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/base.py +0 -8
  231. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/__init__.py +0 -0
  232. plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/my_protocol.py +0 -18
  233. plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/CANVAS_MANIFEST.json +0 -29
  234. plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/README.md +0 -12
  235. plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/__init__.py +0 -0
  236. plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/base.py +0 -3
  237. plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/__init__.py +0 -0
  238. plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/my_protocol.py +0 -18
  239. plugin_runner/tests/fixtures/plugins/test_render_template/CANVAS_MANIFEST.json +0 -47
  240. plugin_runner/tests/fixtures/plugins/test_render_template/README.md +0 -11
  241. plugin_runner/tests/fixtures/plugins/test_render_template/protocols/__init__.py +0 -0
  242. plugin_runner/tests/fixtures/plugins/test_render_template/protocols/my_protocol.py +0 -43
  243. plugin_runner/tests/fixtures/plugins/test_render_template/templates/template.html +0 -10
  244. plugin_runner/tests/fixtures/plugins/test_simple_api/CANVAS_MANIFEST.json +0 -47
  245. plugin_runner/tests/fixtures/plugins/test_simple_api/README.md +0 -11
  246. plugin_runner/tests/fixtures/plugins/test_simple_api/__init__.py +0 -0
  247. plugin_runner/tests/fixtures/plugins/test_simple_api/protocols/__init__.py +0 -0
  248. plugin_runner/tests/fixtures/plugins/test_simple_api/protocols/my_protocol.py +0 -43
  249. plugin_runner/tests/test_application.py +0 -65
  250. plugin_runner/tests/test_plugin_installer.py +0 -127
  251. plugin_runner/tests/test_plugin_runner.py +0 -388
  252. plugin_runner/tests/test_sandbox.py +0 -137
  253. {canvas-0.33.0.dist-info → canvas-0.33.1.dist-info}/WHEEL +0 -0
  254. {canvas-0.33.0.dist-info → canvas-0.33.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,16 @@
1
+ from inspect import isclass
2
+ from typing import Any
3
+
4
+ from canvas_sdk.value_set.value_set import ValueSet
5
+
6
+
7
+ def get_overrides(dictionary: dict[str, Any]) -> tuple:
8
+ """
9
+ Return the keys that are ValueSets.
10
+ """
11
+ return tuple(
12
+ key for key, value in dictionary.items() if isclass(value) and issubclass(value, ValueSet)
13
+ )
14
+
15
+
16
+ __exports__ = ()
@@ -1,3 +1,4 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
1
2
  from canvas_sdk.value_set.value_set import ValueSet
2
3
 
3
4
 
@@ -1055,3 +1056,6 @@ class DiabetesOtherClassConditionSuspect(ValueSet):
1055
1056
  "L98498",
1056
1057
  "L98499",
1057
1058
  }
1059
+
1060
+
1061
+ __exports__ = get_overrides(locals().copy())
@@ -55367,3 +55367,6 @@ class HCCConditions(ValueSet):
55367
55367
  if icd10 in HCCConditions.LABELS:
55368
55368
  return cast(float, HCCConditions.LABELS[icd10]["CommunityRAF"])
55369
55369
  return 0
55370
+
55371
+
55372
+ __exports__ = ("HCCConditions",)
@@ -0,0 +1 @@
1
+ __exports__ = ()
@@ -31,3 +31,6 @@ class StatinAllergen(ValueSet):
31
31
  SNOMEDCT = {
32
32
  "372912004", # Substance with 3-hydroxy-3-methylglutaryl-coenzyme A reductase inhibitor mechanism of action (substance)
33
33
  }
34
+
35
+
36
+ __exports__ = ("StatinAllergen",)
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -230,3 +232,6 @@ class StatinAllergen(ValueSet):
230
232
  SNOMEDCT = {
231
233
  "372912004", # Substance with 3-hydroxy-3-methylglutaryl-coenzyme A reductase inhibitor mechanism of action (substance)
232
234
  }
235
+
236
+
237
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -213,3 +215,6 @@ class HistoryOfHipFractureInParent(ValueSet):
213
215
  "445121000124105", # Family history of paternal hip fracture (situation)
214
216
  "445501000124107", # Family history of hip fracture in parent (situation)
215
217
  }
218
+
219
+
220
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -323,3 +325,6 @@ class ConsultantReport(ValueSet):
323
325
  "371531000", # Report of clinical encounter (record artifact)
324
326
  "371545006", # Confirmatory consultation report (record artifact)
325
327
  }
328
+
329
+
330
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -40652,3 +40654,6 @@ class UrinaryRetention(ValueSet):
40652
40654
  "267064002", # Retention of urine (disorder)
40653
40655
  "12245681000119103", # Postprocedural retention of urine (disorder)
40654
40656
  }
40657
+
40658
+
40659
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -172,3 +174,6 @@ class CardiacPacer(ValueSet):
172
174
  "360128001", # Intravenous triggered cardiac pacemaker system (physical object)
173
175
  "424921004", # Permanent cardiac pacemaker, device (physical object)
174
176
  }
177
+
178
+
179
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -4965,3 +4967,6 @@ class DexaDualEnergyXrayAbsorptiometry_BoneDensityForUrologyCare(ValueSet):
4965
4967
  "38265-5", # DXA Radius and Ulna [T-score] Bone density
4966
4968
  "38268-9", # DXA Skeletal system Views for bone density
4967
4969
  }
4970
+
4971
+
4972
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -2562,3 +2564,6 @@ class HospitalServicesForUrologyCare(ValueSet):
2562
2564
  "99283", # Emergency department visit for the evaluation and management of a patient, which requires these 3 key components: An expanded problem focused history; An expanded problem focused examination; and Medical decision making of moderate complexity. Counseling and/or coordination of care with other physicians, other qualified health care professionals, or agencies are provided consistent with the nature of the problem(s) and the patient's and/or family's needs. Usually, the presenting problem(s) are of moderate severity.
2563
2565
  "99284", # Emergency department visit for the evaluation and management of a patient, which requires these 3 key components: A detailed history; A detailed examination; and Medical decision making of moderate complexity. Counseling and/or coordination of care with other physicians, other qualified health care professionals, or agencies are provided consistent with the nature of the problem(s) and the patient's and/or family's needs. Usually, the presenting problem(s) are of high severity, and require urgent evaluation by the physician, or other qualified health care professionals but do not pose an immediate significant threat to life or physiologic function.
2564
2566
  }
2567
+
2568
+
2569
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -339,3 +341,6 @@ class PneumococcalPolysaccharide23Vaccine(ValueSet):
339
341
  "33", # pneumococcal polysaccharide vaccine, 23 valent
340
342
  "109", # pneumococcal vaccine, unspecified formulation
341
343
  }
344
+
345
+
346
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -311,3 +313,6 @@ class White(ValueSet):
311
313
  CDCREC = {
312
314
  "2106-3", # White
313
315
  }
316
+
317
+
318
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -1330,3 +1332,6 @@ class ReferralsWhereWeightAssessmentMayOccur(ValueSet):
1330
1332
  "408289007", # Refer to weight management program (procedure)
1331
1333
  "416790000", # Referral for home physical therapy (procedure)
1332
1334
  }
1335
+
1336
+
1337
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -1248,3 +1250,6 @@ class HumanImmunodeficiencyVirusHivLaboratoryTestCodesAbAndAg(ValueSet):
1248
1250
  "9669-3", # HIV 1 p66 Ab [Presence] in Serum by Immunoblot
1249
1251
  "9821-0", # HIV 1 p24 Ag [Presence] in Serum
1250
1252
  }
1253
+
1254
+
1255
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -5128,3 +5130,6 @@ class MedicationsForBelowNormalBmi(ValueSet):
5128
5130
  "860221", # megestrol acetate 40 MG Oral Tablet
5129
5131
  "860225", # megestrol acetate 40 MG/ML Oral Suspension
5130
5132
  }
5133
+
5134
+
5135
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -199,3 +201,6 @@ class BmiRatio(ValueSet):
199
201
  LOINC = {
200
202
  "39156-5", # Body mass index (BMI) [Ratio]
201
203
  }
204
+
205
+
206
+ __exports__ = get_overrides(locals().copy())
@@ -1,3 +1,5 @@
1
+ from canvas_sdk.value_set._utilities import get_overrides
2
+
1
3
  from ..value_set import ValueSet
2
4
 
3
5
 
@@ -4037,3 +4039,6 @@ class FluorideVarnishApplicationForChildren(ValueSet):
4037
4039
  "234723000", # Topical application of fluoride - tooth (procedure)
4038
4040
  "313042009", # Application of dental fluoride varnish (procedure)
4039
4041
  }
4042
+
4043
+
4044
+ __exports__ = get_overrides(locals().copy())
@@ -174,3 +174,6 @@ class FrailtySymptom(ValueSet):
174
174
  "16018431000119109", # Paresis of right lower limb (finding)
175
175
  "16419651000119103", # Dependence on biphasic positive airway pressure ventilation due to central sleep apnea syndrome (finding)
176
176
  }
177
+
178
+
179
+ __exports__ = ("FrailtySymptom",)
@@ -110,3 +110,12 @@ class ValueSet(CodeConstantsURLMappingMixin, metaclass=ValueSystems):
110
110
  for system in cls.CODE_SYSTEM_MAPPING
111
111
  if hasattr(cls, system)
112
112
  }
113
+
114
+
115
+ __exports__ = (
116
+ "CodeConstants",
117
+ "CodeConstantsURLMappingMixin",
118
+ "CombinedValueSet",
119
+ "ValueSystems",
120
+ "ValueSet",
121
+ )
@@ -0,0 +1 @@
1
+ __exports__ = ()
logger/__init__.py CHANGED
@@ -1,3 +1,5 @@
1
1
  from logger.logger import PluginLogger
2
2
 
3
3
  log = PluginLogger()
4
+
5
+ __exports__ = ("log",)
logger/logger.py CHANGED
@@ -70,3 +70,6 @@ class PluginLogger:
70
70
  def critical(self, message: Any) -> None:
71
71
  """Logs a critical message."""
72
72
  self.logger.critical(message)
73
+
74
+
75
+ __exports__ = ()
@@ -20,7 +20,7 @@ def aws_sig_v4_headers(
20
20
  ) -> dict[str, str]:
21
21
  """Constructs signed headers for use in requests made to AWS."""
22
22
  algorithm = "AWS4-HMAC-SHA256"
23
- now = datetime.datetime.utcnow()
23
+ now = datetime.datetime.now(datetime.UTC)
24
24
  amzdate = now.strftime("%Y%m%dT%H%M%SZ")
25
25
  datestamp = now.strftime("%Y%m%d")
26
26
  payload_hash = hashlib.sha256(payload).hexdigest()
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env uv run
2
+
3
+ import json
4
+ import logging
5
+ import re
6
+ import sys
7
+ import traceback
8
+ from collections import defaultdict
9
+ from contextlib import redirect_stderr, redirect_stdout
10
+ from glob import glob
11
+ from io import StringIO
12
+ from pathlib import Path
13
+ from textwrap import indent
14
+
15
+ import httpretty
16
+
17
+ from canvas_generated.messages.events_pb2 import PLUGIN_CREATED
18
+ from canvas_generated.messages.events_pb2 import Event as EventRequest
19
+ from canvas_sdk.events.base import Event
20
+ from canvas_sdk.protocols.base import BaseProtocol
21
+ from canvas_sdk.utils import stats
22
+ from plugin_runner.plugin_runner import LOADED_PLUGINS, load_or_reload_plugin
23
+
24
+ stats.STATS_ENABLED = False
25
+
26
+ ORIGINAL_PATH = sys.path.copy()
27
+
28
+
29
+ def enable_httpretty() -> None:
30
+ """
31
+ Prevent any HTTP requests from being made.
32
+ """
33
+ httpretty.enable(verbose=True, allow_net_connect=False)
34
+
35
+ for method in [
36
+ httpretty.GET,
37
+ httpretty.PUT,
38
+ httpretty.POST,
39
+ httpretty.DELETE,
40
+ httpretty.HEAD,
41
+ httpretty.PATCH,
42
+ httpretty.OPTIONS,
43
+ httpretty.CONNECT,
44
+ ]:
45
+ httpretty.register_uri(method, re.compile(r".*"), body="{}")
46
+
47
+
48
+ def disable_httpretty() -> None:
49
+ """
50
+ Allow normal HTTP activity.
51
+ """
52
+ httpretty.disable()
53
+ httpretty.reset()
54
+
55
+
56
+ def main() -> None:
57
+ """
58
+ Iterate through all of our plugins to verify they work with this version of the SDK.
59
+ """
60
+ if len(sys.argv) < 2:
61
+ print("You must specify a base path.")
62
+ sys.exit(1)
63
+
64
+ base_path = sys.argv[1]
65
+
66
+ for folder in glob(f"{base_path}/**/*"):
67
+ path = Path(folder)
68
+
69
+ if "{{" in folder:
70
+ print(f"Ignoring templated path: {folder}")
71
+ continue
72
+
73
+ if not path.is_dir():
74
+ continue
75
+
76
+ if not (path / "CANVAS_MANIFEST.json").exists():
77
+ print(f"Missing CANVAS_MANIFEST.json in {folder}")
78
+ continue
79
+
80
+ sys.path = ORIGINAL_PATH.copy()
81
+
82
+ # this makes plugin imports work and mirrors what the plugin_runner does
83
+ sys.path.append((Path(".") / path.parent).as_posix())
84
+
85
+ print(path)
86
+
87
+ output = StringIO()
88
+
89
+ plugin_runner_logger = logging.getLogger("plugin_runner_logger")
90
+ old_handlers = plugin_runner_logger.handlers.copy()
91
+ plugin_runner_logger.handlers = [logging.StreamHandler(output)]
92
+
93
+ with redirect_stdout(output), redirect_stderr(output):
94
+ success = load_or_reload_plugin(path)
95
+
96
+ output_string = output.getvalue()
97
+
98
+ if not success:
99
+ print()
100
+ print(indent(output_string, prefix=" ").rstrip())
101
+ print()
102
+
103
+ plugin_runner_logger.handlers = old_handlers
104
+
105
+ enable_httpretty()
106
+
107
+ for key, plugin in LOADED_PLUGINS.items():
108
+ Klass: type[BaseProtocol] = plugin["class"]
109
+
110
+ if not hasattr(Klass, "compute") or not callable(Klass.compute):
111
+ print(f"Skipping {key} due to no compute method")
112
+
113
+ event_request = EventRequest(
114
+ type=PLUGIN_CREATED,
115
+ context=json.dumps(
116
+ {
117
+ "key": "test",
118
+ "fields": {
119
+ "coding": {"value": "test"},
120
+ "goal_statement": {"value": "test"},
121
+ "questionnaire": {"text": "test"},
122
+ "medication": {"extra": {"coding": "test"}},
123
+ "ordering_provider": {"value": "test"},
124
+ "text": "test",
125
+ },
126
+ "method": "GET",
127
+ "note_id": 5,
128
+ "note": {
129
+ "uuid": "b2bd0672-ab36-4eca-b105-884f976ae810",
130
+ "id": "b2bd0672-ab36-4eca-b105-884f976ae810",
131
+ },
132
+ "path": "https://test",
133
+ "patient_id": 5,
134
+ "patient": {"id": 5},
135
+ "results": [],
136
+ "search_term": "test",
137
+ "state": "LKD",
138
+ }
139
+ ),
140
+ target="b2bd0672-ab36-4eca-b105-884f976ae810",
141
+ target_type="Patient",
142
+ )
143
+ event = Event(event_request=event_request)
144
+
145
+ try:
146
+ klass = Klass(
147
+ event=event,
148
+ secrets=defaultdict(lambda: "test", {"sentinel": True}),
149
+ environment=defaultdict(lambda: "test", {"sentinel": True}),
150
+ )
151
+ except TypeError as e:
152
+ print(f"Failed to instantiate {key}:", e)
153
+ continue
154
+
155
+ plugin_runner_logger = logging.getLogger("plugin_runner_logger")
156
+ old_handlers = plugin_runner_logger.handlers.copy()
157
+ plugin_runner_logger.handlers = [logging.StreamHandler(output)]
158
+
159
+ output = StringIO()
160
+
161
+ error: Exception | None = None
162
+
163
+ try:
164
+ with redirect_stdout(output), redirect_stderr(output):
165
+ result = klass.compute()
166
+ except TypeError as e:
167
+ error = e
168
+ except KeyError as e:
169
+ error = e
170
+ except Exception as e:
171
+ error = e
172
+
173
+ plugin_runner_logger.handlers = old_handlers
174
+
175
+ result_count = len(result)
176
+ request_count = len(httpretty.latest_requests())
177
+
178
+ print(f"{key}: {result_count}/{request_count}")
179
+
180
+ if error:
181
+ print()
182
+
183
+ # abbreviate these, they come from not being able to access the database
184
+ if "fake_getaddrinfo" in str(error):
185
+ print(indent(str(error), prefix=" ").rstrip())
186
+ else:
187
+ print(indent("".join(traceback.format_exception(error)), prefix=" ").rstrip())
188
+
189
+ print()
190
+
191
+ output_string = output.getvalue()
192
+
193
+ if output_string:
194
+ print()
195
+ print(indent(output_string, prefix=" ").rstrip())
196
+ print()
197
+
198
+ disable_httpretty()
199
+
200
+
201
+ if __name__ == "__main__":
202
+ main()
@@ -33,7 +33,7 @@ from canvas_sdk.utils.stats import get_duration_ms, statsd_client
33
33
  from logger import log
34
34
  from plugin_runner.authentication import token_for_plugin
35
35
  from plugin_runner.installation import install_plugins
36
- from plugin_runner.sandbox import Sandbox
36
+ from plugin_runner.sandbox import Sandbox, sandbox_from_module
37
37
  from settings import (
38
38
  CHANNEL_NAME,
39
39
  CUSTOMER_IDENTIFIER,
@@ -320,6 +320,12 @@ async def synchronize_plugins(run_once: bool = False) -> None:
320
320
  while True:
321
321
  message = await pubsub.get_message(ignore_subscribe_messages=True, timeout=5.0)
322
322
 
323
+ await pubsub.check_health()
324
+
325
+ if not pubsub.connection.is_connected: # type: ignore
326
+ log.info("synchronize_plugins: reconnecting to Redis")
327
+ await pubsub.connection.connect() # type: ignore
328
+
323
329
  if message is None:
324
330
  continue
325
331
 
@@ -350,12 +356,6 @@ async def synchronize_plugins(run_once: bool = False) -> None:
350
356
  log.error(f"synchronize_plugins: load_plugins failed: {e}")
351
357
  sentry_sdk.capture_exception(e)
352
358
 
353
- await pubsub.check_health()
354
-
355
- if not pubsub.connection.is_connected: # type: ignore
356
- log.info("synchronize_plugins: reconnecting to Redis")
357
- await pubsub.connection.connect() # type: ignore
358
-
359
359
  if run_once:
360
360
  break
361
361
 
@@ -437,18 +437,6 @@ def find_modules(base_path: pathlib.Path, prefix: str | None = None) -> list[str
437
437
  return modules
438
438
 
439
439
 
440
- def sandbox_from_module(base_path: pathlib.Path, module_name: str) -> Any:
441
- """Sandbox the code execution."""
442
- module_path = base_path / str(module_name.replace(".", "/") + ".py")
443
-
444
- if not module_path.exists():
445
- raise ModuleNotFoundError(f'Could not load module "{module_name}"')
446
-
447
- sandbox = Sandbox(module_path, namespace=module_name)
448
-
449
- return sandbox.execute()
450
-
451
-
452
440
  async def publish_message(message: dict) -> None:
453
441
  """Publish a message to the pubsub channel."""
454
442
  log.info(f'Publishing message to pubsub channel "{CHANNEL_NAME}"')
@@ -465,7 +453,7 @@ def get_client() -> tuple[redis.Redis, redis.client.PubSub]:
465
453
  return client, pubsub
466
454
 
467
455
 
468
- def load_or_reload_plugin(path: pathlib.Path) -> None:
456
+ def load_or_reload_plugin(path: pathlib.Path) -> bool:
469
457
  """Given a path, load or reload a plugin."""
470
458
  log.info(f'Loading plugin at "{path}"')
471
459
 
@@ -481,11 +469,11 @@ def load_or_reload_plugin(path: pathlib.Path) -> None:
481
469
  log.error(f'Unable to load plugin "{name}": {e}')
482
470
  sentry_sdk.capture_exception(e)
483
471
 
484
- return
472
+ return False
485
473
 
486
474
  secrets_file = path / SECRETS_FILE_NAME
487
-
488
475
  secrets_json = {}
476
+
489
477
  if secrets_file.exists():
490
478
  try:
491
479
  secrets_json = json.load(secrets_file.open())
@@ -502,7 +490,9 @@ def load_or_reload_plugin(path: pathlib.Path) -> None:
502
490
  log.error(f'Unable to load plugin "{name}": {str(e)}')
503
491
  sentry_sdk.capture_exception(e)
504
492
 
505
- return
493
+ return False
494
+
495
+ any_failed = False
506
496
 
507
497
  for handler in handlers:
508
498
  # TODO add class colon validation to existing schema validation
@@ -514,10 +504,13 @@ def load_or_reload_plugin(path: pathlib.Path) -> None:
514
504
  log.error(f'Unable to parse class for plugin "{name}": "{handler["class"]}"')
515
505
  sentry_sdk.capture_exception(e)
516
506
 
507
+ any_failed = True
508
+
517
509
  continue
518
510
 
519
511
  try:
520
- result = sandbox_from_module(path.parent, handler_module)
512
+ sandbox = sandbox_from_module(path.parent, handler_module)
513
+ result = sandbox.execute()
521
514
 
522
515
  if name_and_class in LOADED_PLUGINS:
523
516
  log.info(f"Reloading plugin '{name_and_class}'")
@@ -545,6 +538,10 @@ def load_or_reload_plugin(path: pathlib.Path) -> None:
545
538
 
546
539
  sentry_sdk.capture_exception(e)
547
540
 
541
+ any_failed = True
542
+
543
+ return not any_failed
544
+
548
545
 
549
546
  def refresh_event_type_map() -> None:
550
547
  """Ensure the event subscriptions are up to date."""