canvas 0.33.0__py3-none-any.whl → 0.34.0__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.
- {canvas-0.33.0.dist-info → canvas-0.34.0.dist-info}/METADATA +2 -1
- canvas-0.34.0.dist-info/RECORD +272 -0
- canvas_sdk/__init__.py +3 -0
- canvas_sdk/commands/__init__.py +1 -1
- canvas_sdk/commands/base.py +3 -0
- canvas_sdk/commands/commands/__init__.py +1 -0
- canvas_sdk/commands/commands/adjust_prescription.py +3 -0
- canvas_sdk/commands/commands/allergy.py +7 -0
- canvas_sdk/commands/commands/assess.py +2 -0
- canvas_sdk/commands/commands/close_goal.py +3 -0
- canvas_sdk/commands/commands/diagnose.py +3 -0
- canvas_sdk/commands/commands/exam.py +3 -0
- canvas_sdk/commands/commands/family_history.py +3 -0
- canvas_sdk/commands/commands/follow_up.py +3 -0
- canvas_sdk/commands/commands/goal.py +3 -0
- canvas_sdk/commands/commands/history_present_illness.py +3 -0
- canvas_sdk/commands/commands/imaging_order.py +3 -0
- canvas_sdk/commands/commands/instruct.py +3 -0
- canvas_sdk/commands/commands/lab_order.py +3 -0
- canvas_sdk/commands/commands/medical_history.py +3 -0
- canvas_sdk/commands/commands/medication_statement.py +2 -0
- canvas_sdk/commands/commands/past_surgical_history.py +3 -0
- canvas_sdk/commands/commands/perform.py +3 -0
- canvas_sdk/commands/commands/plan.py +3 -0
- canvas_sdk/commands/commands/prescribe.py +8 -0
- canvas_sdk/commands/commands/questionnaire/__init__.py +3 -13
- canvas_sdk/commands/commands/questionnaire/question.py +10 -0
- canvas_sdk/commands/commands/reason_for_visit.py +3 -0
- canvas_sdk/commands/commands/refer.py +3 -0
- canvas_sdk/commands/commands/refill.py +3 -0
- canvas_sdk/commands/commands/remove_allergy.py +3 -0
- canvas_sdk/commands/commands/resolve_condition.py +3 -0
- canvas_sdk/commands/commands/review_of_systems.py +3 -0
- canvas_sdk/commands/commands/stop_medication.py +3 -0
- canvas_sdk/commands/commands/structured_assessment.py +3 -0
- canvas_sdk/commands/commands/task.py +7 -0
- canvas_sdk/commands/commands/update_diagnosis.py +3 -0
- canvas_sdk/commands/commands/update_goal.py +3 -0
- canvas_sdk/commands/commands/vitals.py +3 -0
- canvas_sdk/commands/constants.py +8 -0
- canvas_sdk/effects/__init__.py +1 -1
- canvas_sdk/effects/banner_alert/__init__.py +1 -1
- canvas_sdk/effects/banner_alert/add_banner_alert.py +3 -0
- canvas_sdk/effects/banner_alert/remove_banner_alert.py +3 -0
- canvas_sdk/effects/base.py +7 -0
- canvas_sdk/effects/billing_line_item/__init__.py +5 -1
- canvas_sdk/effects/billing_line_item/add_billing_line_item.py +3 -0
- canvas_sdk/effects/billing_line_item/remove_billing_line_item.py +3 -0
- canvas_sdk/effects/billing_line_item/update_billing_line_item.py +3 -0
- canvas_sdk/effects/launch_modal.py +3 -0
- canvas_sdk/effects/patient_chart_summary_configuration.py +3 -0
- canvas_sdk/effects/patient_portal/__init__.py +1 -0
- canvas_sdk/effects/patient_portal/application_configuration.py +3 -0
- canvas_sdk/effects/patient_portal/form_result.py +3 -0
- canvas_sdk/effects/patient_portal_menu_configuration.py +3 -0
- canvas_sdk/effects/patient_profile_configuration.py +5 -1
- canvas_sdk/effects/protocol_card/__init__.py +1 -1
- canvas_sdk/effects/protocol_card/protocol_card.py +6 -0
- canvas_sdk/effects/questionnaire_result.py +3 -0
- canvas_sdk/effects/send_invite.py +3 -0
- canvas_sdk/effects/show_button.py +3 -0
- canvas_sdk/effects/simple_api.py +9 -0
- canvas_sdk/effects/surescripts/__init__.py +2 -2
- canvas_sdk/effects/surescripts/surescripts_messages.py +7 -0
- canvas_sdk/effects/task/__init__.py +6 -1
- canvas_sdk/effects/task/task.py +8 -0
- canvas_sdk/effects/update_user.py +3 -0
- canvas_sdk/effects/widgets/__init__.py +1 -1
- canvas_sdk/effects/widgets/portal_widget.py +3 -0
- canvas_sdk/events/__init__.py +6 -1
- canvas_sdk/events/base.py +3 -0
- canvas_sdk/handlers/__init__.py +1 -1
- canvas_sdk/handlers/action_button.py +6 -0
- canvas_sdk/handlers/application.py +3 -0
- canvas_sdk/handlers/base.py +3 -0
- canvas_sdk/handlers/cron_task.py +3 -0
- canvas_sdk/handlers/simple_api/__init__.py +3 -2
- canvas_sdk/handlers/simple_api/api.py +26 -1
- canvas_sdk/handlers/simple_api/exceptions.py +10 -0
- canvas_sdk/handlers/simple_api/security.py +21 -5
- canvas_sdk/handlers/simple_api/tools.py +9 -0
- canvas_sdk/protocols/__init__.py +1 -1
- canvas_sdk/protocols/base.py +3 -0
- canvas_sdk/protocols/clinical_quality_measure.py +6 -1
- canvas_sdk/protocols/timeframe.py +3 -0
- canvas_sdk/questionnaires/__init__.py +1 -1
- canvas_sdk/questionnaires/utils.py +7 -0
- canvas_sdk/templates/__init__.py +1 -1
- canvas_sdk/templates/utils.py +3 -0
- canvas_sdk/utils/__init__.py +1 -1
- canvas_sdk/utils/http.py +94 -35
- canvas_sdk/utils/plugins.py +4 -0
- canvas_sdk/utils/stats.py +11 -0
- canvas_sdk/v1/__init__.py +1 -0
- canvas_sdk/v1/apps.py +3 -0
- canvas_sdk/v1/data/__init__.py +2 -2
- canvas_sdk/v1/data/allergy_intolerance.py +3 -0
- canvas_sdk/v1/data/appointment.py +7 -0
- canvas_sdk/v1/data/assessment.py +3 -0
- canvas_sdk/v1/data/banner_alert.py +3 -0
- canvas_sdk/v1/data/base.py +3 -0
- canvas_sdk/v1/data/billing.py +7 -0
- canvas_sdk/v1/data/care_team.py +7 -0
- canvas_sdk/v1/data/command.py +3 -0
- canvas_sdk/v1/data/common.py +18 -0
- canvas_sdk/v1/data/condition.py +7 -0
- canvas_sdk/v1/data/coverage.py +14 -0
- canvas_sdk/v1/data/detected_issue.py +3 -0
- canvas_sdk/v1/data/device.py +3 -0
- canvas_sdk/v1/data/imaging.py +7 -0
- canvas_sdk/v1/data/lab.py +16 -0
- canvas_sdk/v1/data/medication.py +3 -0
- canvas_sdk/v1/data/note.py +9 -0
- canvas_sdk/v1/data/observation.py +9 -0
- canvas_sdk/v1/data/organization.py +3 -0
- canvas_sdk/v1/data/patient.py +18 -2
- canvas_sdk/v1/data/practicelocation.py +7 -0
- canvas_sdk/v1/data/protocol_override.py +7 -0
- canvas_sdk/v1/data/questionnaire.py +16 -3
- canvas_sdk/v1/data/reason_for_visit.py +3 -0
- canvas_sdk/v1/data/staff.py +3 -0
- canvas_sdk/v1/data/task.py +12 -0
- canvas_sdk/v1/data/team.py +8 -1
- canvas_sdk/v1/data/user.py +3 -0
- canvas_sdk/v1/models.py +2 -0
- canvas_sdk/value_set/__init__.py +1 -0
- canvas_sdk/value_set/_utilities.py +16 -0
- canvas_sdk/value_set/custom.py +4 -0
- canvas_sdk/value_set/hcc2018.py +3 -0
- canvas_sdk/value_set/v2022/__init__.py +1 -0
- canvas_sdk/value_set/v2022/adverse_event.py +3 -0
- canvas_sdk/value_set/v2022/allergy.py +5 -0
- canvas_sdk/value_set/v2022/assessment.py +5 -0
- canvas_sdk/value_set/v2022/communication.py +5 -0
- canvas_sdk/value_set/v2022/condition.py +5 -0
- canvas_sdk/value_set/v2022/device.py +5 -0
- canvas_sdk/value_set/v2022/diagnostic_study.py +5 -0
- canvas_sdk/value_set/v2022/encounter.py +5 -0
- canvas_sdk/value_set/v2022/immunization.py +5 -0
- canvas_sdk/value_set/v2022/individual_characteristic.py +5 -0
- canvas_sdk/value_set/v2022/intervention.py +5 -0
- canvas_sdk/value_set/v2022/laboratory_test.py +5 -0
- canvas_sdk/value_set/v2022/medication.py +5 -0
- canvas_sdk/value_set/v2022/physical_exam.py +5 -0
- canvas_sdk/value_set/v2022/procedure.py +5 -0
- canvas_sdk/value_set/v2022/symptom.py +3 -0
- canvas_sdk/value_set/value_set.py +9 -0
- canvas_sdk/views/__init__.py +1 -0
- logger/__init__.py +2 -0
- logger/logger.py +3 -0
- plugin_runner/aws_headers.py +1 -1
- plugin_runner/load_all_plugins.py +202 -0
- plugin_runner/plugin_runner.py +21 -24
- plugin_runner/sandbox.py +497 -115
- settings.py +5 -2
- canvas-0.33.0.dist-info/RECORD +0 -366
- canvas_cli/apps/auth/tests.py +0 -155
- canvas_cli/apps/plugin/tests.py +0 -85
- canvas_cli/conftest.py +0 -28
- canvas_cli/tests.py +0 -217
- canvas_cli/utils/context/tests.py +0 -131
- canvas_cli/utils/print/tests.py +0 -69
- canvas_cli/utils/urls/tests.py +0 -12
- canvas_cli/utils/validators/tests.py +0 -37
- canvas_sdk/commands/tests/protocol/__init__.py +0 -0
- canvas_sdk/commands/tests/protocol/tests.py +0 -83
- canvas_sdk/commands/tests/schema/__init__.py +0 -0
- canvas_sdk/commands/tests/schema/tests.py +0 -108
- canvas_sdk/commands/tests/test_base_command.py +0 -81
- canvas_sdk/commands/tests/test_utils.py +0 -375
- canvas_sdk/commands/tests/unit/__init__.py +0 -0
- canvas_sdk/commands/tests/unit/tests.py +0 -278
- canvas_sdk/effects/banner_alert/tests.py +0 -288
- canvas_sdk/effects/protocol_card/tests.py +0 -191
- canvas_sdk/questionnaires/tests/__init__.py +0 -0
- canvas_sdk/questionnaires/tests/test_utils.py +0 -74
- canvas_sdk/templates/tests/__init__.py +0 -0
- canvas_sdk/templates/tests/test_utils.py +0 -43
- canvas_sdk/tests/__init__.py +0 -0
- canvas_sdk/tests/handlers/__init__.py +0 -0
- canvas_sdk/tests/handlers/test_simple_api.py +0 -1167
- canvas_sdk/utils/tests.py +0 -72
- canvas_sdk/value_set/tests/test_value_sets.py +0 -72
- plugin_runner/tests/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/example_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/example_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/example_plugin/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/example_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/example_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/CANVAS_MANIFEST.json +0 -38
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/my_protocol.py +0 -33
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/__init__.py +0 -3
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/base.py +0 -6
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/__init__.py +0 -5
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/base.py +0 -4
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/CANVAS_MANIFEST.json +0 -52
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/protocols/my_protocol.py +0 -39
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/questionnaires/example_questionnaire.yml +0 -61
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/base.py +0 -10
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/base.py +0 -10
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/base.py +0 -3
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/base.py +0 -6
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/base.py +0 -8
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/base.py +0 -3
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_render_template/CANVAS_MANIFEST.json +0 -47
- plugin_runner/tests/fixtures/plugins/test_render_template/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_render_template/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_render_template/protocols/my_protocol.py +0 -43
- plugin_runner/tests/fixtures/plugins/test_render_template/templates/template.html +0 -10
- plugin_runner/tests/fixtures/plugins/test_simple_api/CANVAS_MANIFEST.json +0 -47
- plugin_runner/tests/fixtures/plugins/test_simple_api/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_simple_api/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_simple_api/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_simple_api/protocols/my_protocol.py +0 -43
- plugin_runner/tests/test_application.py +0 -65
- plugin_runner/tests/test_plugin_installer.py +0 -127
- plugin_runner/tests/test_plugin_runner.py +0 -388
- plugin_runner/tests/test_sandbox.py +0 -137
- {canvas-0.33.0.dist-info → canvas-0.34.0.dist-info}/WHEEL +0 -0
- {canvas-0.33.0.dist-info → canvas-0.34.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import uuid
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
from pydantic import ValidationError
|
|
5
|
-
from typer.testing import CliRunner
|
|
6
|
-
|
|
7
|
-
from canvas_sdk.commands import (
|
|
8
|
-
AssessCommand,
|
|
9
|
-
DiagnoseCommand,
|
|
10
|
-
GoalCommand,
|
|
11
|
-
HistoryOfPresentIllnessCommand,
|
|
12
|
-
MedicationStatementCommand,
|
|
13
|
-
PlanCommand,
|
|
14
|
-
PrescribeCommand,
|
|
15
|
-
QuestionnaireCommand,
|
|
16
|
-
ReasonForVisitCommand,
|
|
17
|
-
StopMedicationCommand,
|
|
18
|
-
UpdateGoalCommand,
|
|
19
|
-
)
|
|
20
|
-
from canvas_sdk.commands.base import _BaseCommand
|
|
21
|
-
from canvas_sdk.commands.tests.test_utils import (
|
|
22
|
-
fake,
|
|
23
|
-
get_field_type,
|
|
24
|
-
raises_none_error_for_effect_method,
|
|
25
|
-
raises_wrong_type_error,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
runner = CliRunner()
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@pytest.mark.parametrize(
|
|
32
|
-
"Command,fields_to_test",
|
|
33
|
-
[
|
|
34
|
-
(AssessCommand, ("condition_id", "background", "status", "narrative")),
|
|
35
|
-
(
|
|
36
|
-
DiagnoseCommand,
|
|
37
|
-
("icd10_code", "background", "approximate_date_of_onset", "today_assessment"),
|
|
38
|
-
),
|
|
39
|
-
(
|
|
40
|
-
GoalCommand,
|
|
41
|
-
(
|
|
42
|
-
"goal_statement",
|
|
43
|
-
"start_date",
|
|
44
|
-
"due_date",
|
|
45
|
-
"achievement_status",
|
|
46
|
-
"priority",
|
|
47
|
-
"progress",
|
|
48
|
-
),
|
|
49
|
-
),
|
|
50
|
-
(HistoryOfPresentIllnessCommand, ("narrative",)),
|
|
51
|
-
(MedicationStatementCommand, ("fdb_code", "sig")),
|
|
52
|
-
(PlanCommand, ("narrative", "command_uuid")),
|
|
53
|
-
(
|
|
54
|
-
PrescribeCommand,
|
|
55
|
-
(
|
|
56
|
-
"fdb_code",
|
|
57
|
-
"icd10_codes",
|
|
58
|
-
"sig",
|
|
59
|
-
"days_supply",
|
|
60
|
-
"type_to_dispense",
|
|
61
|
-
"refills",
|
|
62
|
-
"substitutions",
|
|
63
|
-
"pharmacy",
|
|
64
|
-
"prescriber_id",
|
|
65
|
-
"note_to_pharmacist",
|
|
66
|
-
),
|
|
67
|
-
),
|
|
68
|
-
(QuestionnaireCommand, ("questionnaire_id", "result")),
|
|
69
|
-
(ReasonForVisitCommand, ("coding", "comment")),
|
|
70
|
-
(StopMedicationCommand, ("medication_id", "rationale")),
|
|
71
|
-
(
|
|
72
|
-
UpdateGoalCommand,
|
|
73
|
-
(
|
|
74
|
-
"goal_id",
|
|
75
|
-
"due_date",
|
|
76
|
-
"achievement_status",
|
|
77
|
-
"priority",
|
|
78
|
-
"progress",
|
|
79
|
-
),
|
|
80
|
-
),
|
|
81
|
-
],
|
|
82
|
-
)
|
|
83
|
-
def test_command_raises_generic_error_when_kwarg_given_incorrect_type(
|
|
84
|
-
Command: type[_BaseCommand],
|
|
85
|
-
fields_to_test: tuple[str],
|
|
86
|
-
) -> None:
|
|
87
|
-
"""Test that Command raises a generic error when a kwarg is given an incorrect type."""
|
|
88
|
-
for field in fields_to_test:
|
|
89
|
-
raises_wrong_type_error(Command, field)
|
|
90
|
-
|
|
91
|
-
for method in ["originate", "edit", "delete", "commit", "enter_in_error"]:
|
|
92
|
-
raises_none_error_for_effect_method(Command, method)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@pytest.mark.parametrize(
|
|
96
|
-
"Command,err_kwargs,valid_kwargs",
|
|
97
|
-
[
|
|
98
|
-
(
|
|
99
|
-
PlanCommand,
|
|
100
|
-
{"narrative": "yo", "note_uuid": 1},
|
|
101
|
-
{"narrative": "yo", "note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
102
|
-
),
|
|
103
|
-
(
|
|
104
|
-
PlanCommand,
|
|
105
|
-
{"narrative": "yo", "note_uuid": "5", "command_uuid": 5},
|
|
106
|
-
{"narrative": "yo", "note_uuid": "5", "command_uuid": "5"},
|
|
107
|
-
),
|
|
108
|
-
(
|
|
109
|
-
ReasonForVisitCommand,
|
|
110
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000", "structured": True},
|
|
111
|
-
{
|
|
112
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
113
|
-
"structured": False,
|
|
114
|
-
},
|
|
115
|
-
),
|
|
116
|
-
(
|
|
117
|
-
ReasonForVisitCommand,
|
|
118
|
-
{
|
|
119
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
120
|
-
"coding": {"code": "x"},
|
|
121
|
-
},
|
|
122
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
123
|
-
),
|
|
124
|
-
(
|
|
125
|
-
ReasonForVisitCommand,
|
|
126
|
-
{
|
|
127
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
128
|
-
"coding": {"code": 1, "system": "y"},
|
|
129
|
-
},
|
|
130
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
131
|
-
),
|
|
132
|
-
(
|
|
133
|
-
ReasonForVisitCommand,
|
|
134
|
-
{
|
|
135
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
136
|
-
"coding": {"code": None, "system": "y"},
|
|
137
|
-
},
|
|
138
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
139
|
-
),
|
|
140
|
-
(
|
|
141
|
-
ReasonForVisitCommand,
|
|
142
|
-
{
|
|
143
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
144
|
-
"coding": {"system": "y"},
|
|
145
|
-
},
|
|
146
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
147
|
-
),
|
|
148
|
-
(
|
|
149
|
-
ReasonForVisitCommand,
|
|
150
|
-
{
|
|
151
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
152
|
-
"coding": {"code": "x", "system": 1},
|
|
153
|
-
},
|
|
154
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
155
|
-
),
|
|
156
|
-
(
|
|
157
|
-
ReasonForVisitCommand,
|
|
158
|
-
{
|
|
159
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
160
|
-
"coding": {"code": "x", "system": None},
|
|
161
|
-
},
|
|
162
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
163
|
-
),
|
|
164
|
-
(
|
|
165
|
-
ReasonForVisitCommand,
|
|
166
|
-
{
|
|
167
|
-
"note_uuid": "00000000-0000-0000-0000-000000000000",
|
|
168
|
-
"coding": {"code": "x", "system": "y", "display": 1},
|
|
169
|
-
},
|
|
170
|
-
{"note_uuid": "00000000-0000-0000-0000-000000000000"},
|
|
171
|
-
),
|
|
172
|
-
],
|
|
173
|
-
)
|
|
174
|
-
def test_command_raises_specific_error_when_kwarg_given_incorrect_type(
|
|
175
|
-
Command: type[PlanCommand] | type[ReasonForVisitCommand],
|
|
176
|
-
err_kwargs: dict,
|
|
177
|
-
valid_kwargs: dict,
|
|
178
|
-
) -> None:
|
|
179
|
-
"""Test that Command raises a specific error when a kwarg is given an incorrect type."""
|
|
180
|
-
with pytest.raises(ValidationError):
|
|
181
|
-
cmd = Command(**err_kwargs)
|
|
182
|
-
cmd.originate()
|
|
183
|
-
cmd.command_uuid = str(uuid.uuid4())
|
|
184
|
-
cmd.edit()
|
|
185
|
-
|
|
186
|
-
cmd = Command(**valid_kwargs)
|
|
187
|
-
if len(err_kwargs) < len(valid_kwargs):
|
|
188
|
-
return
|
|
189
|
-
key, value = list(err_kwargs.items())[-1]
|
|
190
|
-
with pytest.raises(ValidationError):
|
|
191
|
-
setattr(cmd, key, value)
|
|
192
|
-
cmd.originate()
|
|
193
|
-
cmd.command_uuid = str(uuid.uuid4())
|
|
194
|
-
cmd.edit()
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
@pytest.mark.parametrize(
|
|
198
|
-
"Command,fields_to_test",
|
|
199
|
-
[
|
|
200
|
-
(AssessCommand, ("condition_id", "background", "status", "narrative")),
|
|
201
|
-
(
|
|
202
|
-
DiagnoseCommand,
|
|
203
|
-
("icd10_code", "background", "approximate_date_of_onset", "today_assessment"),
|
|
204
|
-
),
|
|
205
|
-
(
|
|
206
|
-
GoalCommand,
|
|
207
|
-
(
|
|
208
|
-
"goal_statement",
|
|
209
|
-
"start_date",
|
|
210
|
-
"due_date",
|
|
211
|
-
"achievement_status",
|
|
212
|
-
"priority",
|
|
213
|
-
"progress",
|
|
214
|
-
),
|
|
215
|
-
),
|
|
216
|
-
(HistoryOfPresentIllnessCommand, ("narrative",)),
|
|
217
|
-
(MedicationStatementCommand, ("fdb_code", "sig")),
|
|
218
|
-
(PlanCommand, ("narrative", "command_uuid", "note_uuid")),
|
|
219
|
-
(
|
|
220
|
-
PrescribeCommand,
|
|
221
|
-
(
|
|
222
|
-
"fdb_code",
|
|
223
|
-
"icd10_codes",
|
|
224
|
-
"sig",
|
|
225
|
-
"days_supply",
|
|
226
|
-
"quantity_to_dispense",
|
|
227
|
-
"type_to_dispense",
|
|
228
|
-
"refills",
|
|
229
|
-
"substitutions",
|
|
230
|
-
"pharmacy",
|
|
231
|
-
"prescriber_id",
|
|
232
|
-
"note_to_pharmacist",
|
|
233
|
-
),
|
|
234
|
-
),
|
|
235
|
-
(QuestionnaireCommand, ("questionnaire_id", "result")),
|
|
236
|
-
(ReasonForVisitCommand, ("coding", "comment")),
|
|
237
|
-
(StopMedicationCommand, ("medication_id", "rationale")),
|
|
238
|
-
(
|
|
239
|
-
UpdateGoalCommand,
|
|
240
|
-
(
|
|
241
|
-
"goal_id",
|
|
242
|
-
"due_date",
|
|
243
|
-
"achievement_status",
|
|
244
|
-
"priority",
|
|
245
|
-
"progress",
|
|
246
|
-
),
|
|
247
|
-
),
|
|
248
|
-
],
|
|
249
|
-
)
|
|
250
|
-
def test_command_allows_kwarg_with_correct_type(
|
|
251
|
-
Command: type[_BaseCommand],
|
|
252
|
-
fields_to_test: tuple[str],
|
|
253
|
-
) -> None:
|
|
254
|
-
"""Test that Command allows a kwarg with the correct type."""
|
|
255
|
-
schema = Command.model_json_schema()
|
|
256
|
-
|
|
257
|
-
for field in fields_to_test:
|
|
258
|
-
field_type = get_field_type(schema["properties"][field])
|
|
259
|
-
|
|
260
|
-
init_field_value = fake({"type": field_type}, Command)
|
|
261
|
-
init_kwargs = {field: init_field_value}
|
|
262
|
-
cmd = Command(**init_kwargs)
|
|
263
|
-
assert getattr(cmd, field) == init_field_value
|
|
264
|
-
|
|
265
|
-
updated_field_value = fake({"type": field_type}, Command)
|
|
266
|
-
setattr(cmd, field, updated_field_value)
|
|
267
|
-
assert getattr(cmd, field) == updated_field_value
|
|
268
|
-
|
|
269
|
-
for method in ["originate", "edit", "delete", "commit", "enter_in_error"]:
|
|
270
|
-
required_fields = {
|
|
271
|
-
k: v
|
|
272
|
-
for k, v in schema["properties"].items()
|
|
273
|
-
if k in Command()._get_effect_method_required_fields(method)
|
|
274
|
-
}
|
|
275
|
-
base = {field: fake(props, Command) for field, props in required_fields.items()}
|
|
276
|
-
cmd = Command(**base)
|
|
277
|
-
effect = getattr(cmd, method)()
|
|
278
|
-
assert effect is not None
|
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
import shutil
|
|
2
|
-
from collections.abc import Generator
|
|
3
|
-
from contextlib import chdir
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
import pytest
|
|
9
|
-
import requests
|
|
10
|
-
from django.core.exceptions import ImproperlyConfigured
|
|
11
|
-
from pydantic import ValidationError
|
|
12
|
-
from typer.testing import CliRunner
|
|
13
|
-
|
|
14
|
-
import settings
|
|
15
|
-
from canvas_cli.apps.plugin.plugin import _build_package, plugin_url
|
|
16
|
-
from canvas_cli.main import app
|
|
17
|
-
from canvas_sdk.commands.tests.test_utils import MaskedValue, wait_for_log
|
|
18
|
-
from canvas_sdk.effects.banner_alert import AddBannerAlert, RemoveBannerAlert
|
|
19
|
-
|
|
20
|
-
runner = CliRunner()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@pytest.fixture(scope="session")
|
|
24
|
-
def token() -> MaskedValue:
|
|
25
|
-
"""Get a valid token."""
|
|
26
|
-
response = requests.post(
|
|
27
|
-
f"{settings.INTEGRATION_TEST_URL}/auth/token/",
|
|
28
|
-
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|
29
|
-
data={
|
|
30
|
-
"grant_type": "client_credentials",
|
|
31
|
-
"client_id": settings.INTEGRATION_TEST_CLIENT_ID,
|
|
32
|
-
"client_secret": settings.INTEGRATION_TEST_CLIENT_SECRET,
|
|
33
|
-
},
|
|
34
|
-
)
|
|
35
|
-
response.raise_for_status()
|
|
36
|
-
|
|
37
|
-
return MaskedValue(response.json()["access_token"])
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@pytest.fixture(scope="session")
|
|
41
|
-
def first_patient_id(token: MaskedValue) -> dict:
|
|
42
|
-
"""Get the first patient id."""
|
|
43
|
-
headers = {
|
|
44
|
-
"Authorization": f"Bearer {token.value}",
|
|
45
|
-
"Content-Type": "application/json",
|
|
46
|
-
"Accept": "application/json",
|
|
47
|
-
}
|
|
48
|
-
response = requests.get(f"{settings.INTEGRATION_TEST_URL}/api/Patient", headers=headers)
|
|
49
|
-
response.raise_for_status()
|
|
50
|
-
patients = response.json()
|
|
51
|
-
return patients["entry"][0]["resource"]["key"]
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
@pytest.fixture(scope="session")
|
|
55
|
-
def plugin_name() -> str:
|
|
56
|
-
"""Get the plugin name to be used."""
|
|
57
|
-
return f"addbanneralert{datetime.now().timestamp()}".replace(".", "")
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@pytest.fixture(scope="session")
|
|
61
|
-
def write_and_install_protocol_and_clean_up(
|
|
62
|
-
first_patient_id: str, plugin_name: str, token: MaskedValue
|
|
63
|
-
) -> Generator[Any, Any, Any]:
|
|
64
|
-
"""Write the protocol code, install the plugin, and clean up after the test."""
|
|
65
|
-
if not settings.INTEGRATION_TEST_URL:
|
|
66
|
-
raise ImproperlyConfigured("INTEGRATION_TEST_URL is not set")
|
|
67
|
-
|
|
68
|
-
# write the protocol
|
|
69
|
-
with chdir(Path("./custom-plugins")):
|
|
70
|
-
runner.invoke(app, "init", input=plugin_name)
|
|
71
|
-
|
|
72
|
-
protocol_code = f"""
|
|
73
|
-
from canvas_sdk.effects.banner_alert import AddBannerAlert
|
|
74
|
-
from canvas_sdk.events import EventType
|
|
75
|
-
from canvas_sdk.protocols import BaseProtocol
|
|
76
|
-
|
|
77
|
-
class Protocol(BaseProtocol):
|
|
78
|
-
RESPONDS_TO = EventType.Name(EventType.ENCOUNTER_CREATED)
|
|
79
|
-
def compute(self):
|
|
80
|
-
return [
|
|
81
|
-
AddBannerAlert(
|
|
82
|
-
patient_id="{first_patient_id}",
|
|
83
|
-
key="{plugin_name}",
|
|
84
|
-
narrative="this is a test",
|
|
85
|
-
placement=[AddBannerAlert.Placement.CHART],
|
|
86
|
-
intent=AddBannerAlert.Intent.INFO,
|
|
87
|
-
).apply()
|
|
88
|
-
]
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
with open(f"./custom-plugins/{plugin_name}/protocols/my_protocol.py", "w") as protocol:
|
|
92
|
-
protocol.write(protocol_code)
|
|
93
|
-
|
|
94
|
-
with open(_build_package(Path(f"./custom-plugins/{plugin_name}")), "rb") as package:
|
|
95
|
-
message_received_event, thread, ws = wait_for_log(
|
|
96
|
-
settings.INTEGRATION_TEST_URL,
|
|
97
|
-
token.value,
|
|
98
|
-
f"Loading plugin '{plugin_name}",
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
# install the plugin
|
|
102
|
-
response = requests.post(
|
|
103
|
-
plugin_url(settings.INTEGRATION_TEST_URL),
|
|
104
|
-
data={"is_enabled": True},
|
|
105
|
-
files={"package": package},
|
|
106
|
-
headers={"Authorization": f"Bearer {token.value}"},
|
|
107
|
-
)
|
|
108
|
-
response.raise_for_status()
|
|
109
|
-
|
|
110
|
-
message_received_event.wait(timeout=15.0)
|
|
111
|
-
|
|
112
|
-
# unfortunately sometimes the log websocket just doesn't return any
|
|
113
|
-
# messages, so asserting on the state of the timeout here causes failures
|
|
114
|
-
# even though the delay itself will cause the waiting test to pass (because
|
|
115
|
-
# the plugin has been loaded).
|
|
116
|
-
# timeout_not_hit = message_received_event.wait(timeout=15.0)
|
|
117
|
-
# if not timeout_not_hit:
|
|
118
|
-
# ws.close()
|
|
119
|
-
# assert timeout_not_hit, f"plugin loading message timeout hit: Loading plugin '{plugin_name}"
|
|
120
|
-
yield
|
|
121
|
-
|
|
122
|
-
ws.close()
|
|
123
|
-
thread.join()
|
|
124
|
-
|
|
125
|
-
# clean up
|
|
126
|
-
if Path(f"./custom-plugins/{plugin_name}").exists():
|
|
127
|
-
shutil.rmtree(Path(f"./custom-plugins/{plugin_name}"))
|
|
128
|
-
|
|
129
|
-
# disable
|
|
130
|
-
response = requests.patch(
|
|
131
|
-
plugin_url(settings.INTEGRATION_TEST_URL, plugin_name),
|
|
132
|
-
data={"is_enabled": False},
|
|
133
|
-
headers={
|
|
134
|
-
"Authorization": f"Bearer {token.value}",
|
|
135
|
-
},
|
|
136
|
-
)
|
|
137
|
-
response.raise_for_status()
|
|
138
|
-
|
|
139
|
-
# delete
|
|
140
|
-
response = requests.delete(
|
|
141
|
-
plugin_url(settings.INTEGRATION_TEST_URL, plugin_name),
|
|
142
|
-
headers={"Authorization": f"Bearer {token.value}"},
|
|
143
|
-
)
|
|
144
|
-
response.raise_for_status()
|
|
145
|
-
|
|
146
|
-
# confirm no more banner
|
|
147
|
-
response = requests.get(
|
|
148
|
-
f"{settings.INTEGRATION_TEST_URL}/api/BannerAlert/?patient__key={first_patient_id}",
|
|
149
|
-
headers={
|
|
150
|
-
"Authorization": f"Bearer {token.value}",
|
|
151
|
-
},
|
|
152
|
-
)
|
|
153
|
-
response.raise_for_status()
|
|
154
|
-
patient_banners_none = response.json()
|
|
155
|
-
patient_banner = next(
|
|
156
|
-
(b for b in patient_banners_none["results"] if b["key"] == plugin_name), None
|
|
157
|
-
)
|
|
158
|
-
assert patient_banner is None
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
@pytest.mark.integtest
|
|
162
|
-
def test_protocol_that_adds_banner_alert(
|
|
163
|
-
write_and_install_protocol_and_clean_up: None,
|
|
164
|
-
token: MaskedValue,
|
|
165
|
-
plugin_name: str,
|
|
166
|
-
first_patient_id: str,
|
|
167
|
-
) -> None:
|
|
168
|
-
"""Test that the protocol adds a banner alert."""
|
|
169
|
-
# trigger the event
|
|
170
|
-
response = requests.post(
|
|
171
|
-
f"{settings.INTEGRATION_TEST_URL}/api/Note/",
|
|
172
|
-
headers={
|
|
173
|
-
"Authorization": f"Bearer {token.value}",
|
|
174
|
-
"Content-Type": "application/json",
|
|
175
|
-
"Accept": "application/json",
|
|
176
|
-
},
|
|
177
|
-
json={
|
|
178
|
-
"patient": 1,
|
|
179
|
-
"provider": 1,
|
|
180
|
-
"note_type": "office",
|
|
181
|
-
"note_type_version": 1,
|
|
182
|
-
"lastModifiedBySessionKey": "8fee3c03a525cebee1d8a6b8e63dd4dg",
|
|
183
|
-
},
|
|
184
|
-
)
|
|
185
|
-
response.raise_for_status()
|
|
186
|
-
|
|
187
|
-
response = requests.get(
|
|
188
|
-
f"{settings.INTEGRATION_TEST_URL}/api/BannerAlert/?patient__key={first_patient_id}",
|
|
189
|
-
headers={
|
|
190
|
-
"Authorization": f"Bearer {token.value}",
|
|
191
|
-
},
|
|
192
|
-
)
|
|
193
|
-
response.raise_for_status()
|
|
194
|
-
|
|
195
|
-
patient_banners = response.json()
|
|
196
|
-
assert patient_banners["count"] > 0
|
|
197
|
-
|
|
198
|
-
patient_banner = next(b for b in patient_banners["results"] if b["key"] == plugin_name)
|
|
199
|
-
assert patient_banner["pluginName"] == plugin_name
|
|
200
|
-
assert patient_banner["narrative"] == "this is a test"
|
|
201
|
-
assert patient_banner["placement"] == ["chart"]
|
|
202
|
-
assert patient_banner["intent"] == "info"
|
|
203
|
-
assert patient_banner["href"] is None
|
|
204
|
-
assert patient_banner["status"] == "active"
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
@pytest.mark.parametrize(
|
|
208
|
-
"Effect,params,expected_payload",
|
|
209
|
-
[
|
|
210
|
-
(
|
|
211
|
-
AddBannerAlert,
|
|
212
|
-
{
|
|
213
|
-
"patient_id": "uuid",
|
|
214
|
-
"key": "test-key",
|
|
215
|
-
"narrative": "hellooo",
|
|
216
|
-
"placement": [AddBannerAlert.Placement.APPOINTMENT_CARD],
|
|
217
|
-
"intent": AddBannerAlert.Intent.INFO,
|
|
218
|
-
},
|
|
219
|
-
'{"patient": "uuid", "patient_filter": null, "key": "test-key", "data": {"narrative": "hellooo", "placement": ["appointment_card"], "intent": "info", "href": null}}',
|
|
220
|
-
),
|
|
221
|
-
(
|
|
222
|
-
AddBannerAlert,
|
|
223
|
-
{
|
|
224
|
-
"patient_filter": {"active": True},
|
|
225
|
-
"key": "test-key",
|
|
226
|
-
"narrative": "hellooo",
|
|
227
|
-
"placement": [AddBannerAlert.Placement.APPOINTMENT_CARD],
|
|
228
|
-
"intent": AddBannerAlert.Intent.INFO,
|
|
229
|
-
},
|
|
230
|
-
'{"patient": null, "patient_filter": {"active": true}, "key": "test-key", "data": {"narrative": "hellooo", "placement": ["appointment_card"], "intent": "info", "href": null}}',
|
|
231
|
-
),
|
|
232
|
-
(
|
|
233
|
-
RemoveBannerAlert,
|
|
234
|
-
{"patient_id": "uuid", "key": "testeroo"},
|
|
235
|
-
'{"patient": "uuid", "patient_filter": null, "key": "testeroo"}',
|
|
236
|
-
),
|
|
237
|
-
(
|
|
238
|
-
RemoveBannerAlert,
|
|
239
|
-
{"patient_filter": {"active": True}, "key": "testeroo"},
|
|
240
|
-
'{"patient": null, "patient_filter": {"active": true}, "key": "testeroo"}',
|
|
241
|
-
),
|
|
242
|
-
],
|
|
243
|
-
)
|
|
244
|
-
def test_banner_alert_apply_method_succeeds_with_all_required_fields(
|
|
245
|
-
Effect: type[AddBannerAlert] | type[RemoveBannerAlert], params: dict, expected_payload: str
|
|
246
|
-
) -> None:
|
|
247
|
-
"""Test that the apply method succeeds with all required fields."""
|
|
248
|
-
b = Effect()
|
|
249
|
-
for k, v in params.items():
|
|
250
|
-
setattr(b, k, v)
|
|
251
|
-
applied = b.apply()
|
|
252
|
-
assert applied.payload == expected_payload
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
@pytest.mark.parametrize(
|
|
256
|
-
"Effect,expected_err_msgs",
|
|
257
|
-
[
|
|
258
|
-
(
|
|
259
|
-
AddBannerAlert,
|
|
260
|
-
[
|
|
261
|
-
"5 validation errors for AddBannerAlert",
|
|
262
|
-
"Field 'patient_id' or 'patient_filter' is required to apply an AddBannerAlert [type=missing",
|
|
263
|
-
"Field 'key' is required to apply an AddBannerAlert [type=missing",
|
|
264
|
-
"Field 'narrative' is required to apply an AddBannerAlert [type=missing",
|
|
265
|
-
"Field 'placement' is required to apply an AddBannerAlert [type=missing",
|
|
266
|
-
"Field 'intent' is required to apply an AddBannerAlert [type=missing",
|
|
267
|
-
],
|
|
268
|
-
),
|
|
269
|
-
(
|
|
270
|
-
RemoveBannerAlert,
|
|
271
|
-
[
|
|
272
|
-
"2 validation errors for RemoveBannerAlert",
|
|
273
|
-
"Field 'patient_id' or 'patient_filter' is required to apply a RemoveBannerAlert [type=missing",
|
|
274
|
-
"Field 'key' is required to apply a RemoveBannerAlert [type=missing",
|
|
275
|
-
],
|
|
276
|
-
),
|
|
277
|
-
],
|
|
278
|
-
)
|
|
279
|
-
def test_banner_alert_apply_method_raises_error_without_required_fields(
|
|
280
|
-
Effect: type[AddBannerAlert] | type[RemoveBannerAlert], expected_err_msgs: str
|
|
281
|
-
) -> None:
|
|
282
|
-
"""Test that the apply method raises an error when missing required fields."""
|
|
283
|
-
b = Effect()
|
|
284
|
-
with pytest.raises(ValidationError) as e:
|
|
285
|
-
b.apply()
|
|
286
|
-
err_msg = repr(e.value)
|
|
287
|
-
for expected in expected_err_msgs:
|
|
288
|
-
assert expected in err_msg
|