canvas 0.1.3__py3-none-any.whl → 0.1.5__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.1.5.dist-info/METADATA +176 -0
- canvas-0.1.5.dist-info/RECORD +66 -0
- {canvas-0.1.3.dist-info → canvas-0.1.5.dist-info}/WHEEL +1 -1
- canvas-0.1.5.dist-info/entry_points.txt +3 -0
- canvas_cli/apps/__init__.py +0 -0
- canvas_cli/apps/auth/__init__.py +3 -0
- canvas_cli/apps/auth/tests.py +142 -0
- canvas_cli/apps/auth/utils.py +163 -0
- canvas_cli/apps/logs/__init__.py +3 -0
- canvas_cli/apps/logs/logs.py +59 -0
- canvas_cli/apps/plugin/__init__.py +9 -0
- canvas_cli/apps/plugin/plugin.py +286 -0
- canvas_cli/apps/plugin/tests.py +32 -0
- canvas_cli/conftest.py +28 -0
- canvas_cli/main.py +78 -0
- canvas_cli/templates/plugins/default/cookiecutter.json +4 -0
- canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/CANVAS_MANIFEST.json +29 -0
- canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/README.md +12 -0
- canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/__init__.py +0 -0
- canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/my_protocol.py +55 -0
- canvas_cli/tests.py +11 -0
- canvas_cli/utils/__init__.py +0 -0
- canvas_cli/utils/context/__init__.py +3 -0
- canvas_cli/utils/context/context.py +172 -0
- canvas_cli/utils/context/tests.py +130 -0
- canvas_cli/utils/print/__init__.py +3 -0
- canvas_cli/utils/print/print.py +60 -0
- canvas_cli/utils/print/tests.py +70 -0
- canvas_cli/utils/urls/__init__.py +3 -0
- canvas_cli/utils/urls/tests.py +12 -0
- canvas_cli/utils/urls/urls.py +27 -0
- canvas_cli/utils/validators/__init__.py +3 -0
- canvas_cli/utils/validators/manifest_schema.py +80 -0
- canvas_cli/utils/validators/tests.py +36 -0
- canvas_cli/utils/validators/validators.py +40 -0
- canvas_sdk/__init__.py +0 -0
- canvas_sdk/commands/__init__.py +27 -0
- canvas_sdk/commands/base.py +118 -0
- canvas_sdk/commands/commands/assess.py +48 -0
- canvas_sdk/commands/commands/diagnose.py +44 -0
- canvas_sdk/commands/commands/goal.py +48 -0
- canvas_sdk/commands/commands/history_present_illness.py +15 -0
- canvas_sdk/commands/commands/medication_statement.py +28 -0
- canvas_sdk/commands/commands/plan.py +15 -0
- canvas_sdk/commands/commands/prescribe.py +48 -0
- canvas_sdk/commands/commands/questionnaire.py +17 -0
- canvas_sdk/commands/commands/reason_for_visit.py +36 -0
- canvas_sdk/commands/commands/stop_medication.py +18 -0
- canvas_sdk/commands/commands/update_goal.py +48 -0
- canvas_sdk/commands/constants.py +9 -0
- canvas_sdk/commands/tests/test_utils.py +195 -0
- canvas_sdk/commands/tests/tests.py +407 -0
- canvas_sdk/data/__init__.py +0 -0
- canvas_sdk/effects/__init__.py +1 -0
- canvas_sdk/effects/banner_alert/banner_alert.py +37 -0
- canvas_sdk/effects/banner_alert/constants.py +19 -0
- canvas_sdk/effects/base.py +30 -0
- canvas_sdk/events/__init__.py +1 -0
- canvas_sdk/protocols/__init__.py +1 -0
- canvas_sdk/protocols/base.py +12 -0
- canvas_sdk/tests/__init__.py +0 -0
- canvas_sdk/utils/__init__.py +3 -0
- canvas_sdk/utils/http.py +72 -0
- canvas_sdk/utils/tests.py +63 -0
- canvas_sdk/views/__init__.py +0 -0
- canvas/main.py +0 -19
- canvas-0.1.3.dist-info/METADATA +0 -285
- canvas-0.1.3.dist-info/RECORD +0 -6
- canvas-0.1.3.dist-info/entry_points.txt +0 -3
- {canvas → canvas_cli}/__init__.py +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from enum import EnumType
|
|
3
|
+
from typing import get_args
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, model_validator
|
|
6
|
+
from typing_extensions import Self
|
|
7
|
+
|
|
8
|
+
from canvas_sdk.effects import Effect
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _BaseCommand(BaseModel):
|
|
12
|
+
model_config = ConfigDict(strict=True, validate_assignment=True)
|
|
13
|
+
|
|
14
|
+
class Meta:
|
|
15
|
+
key = ""
|
|
16
|
+
|
|
17
|
+
# todo: update int to str as we should use external identifiers
|
|
18
|
+
note_id: int | None = None
|
|
19
|
+
command_uuid: str | None = None
|
|
20
|
+
user_id: int
|
|
21
|
+
|
|
22
|
+
@model_validator(mode="after")
|
|
23
|
+
def _verify_has_note_id_or_command_id(self) -> Self:
|
|
24
|
+
if not self.note_id and not self.command_uuid:
|
|
25
|
+
raise ValueError("Command should have either a note_id or a command_uuid.")
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def values(self) -> dict:
|
|
30
|
+
return {}
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def _get_property_choices(cls, name: str, schema: dict) -> list[dict] | None:
|
|
34
|
+
definition = schema.get("properties", {}).get(name, {})
|
|
35
|
+
if not (choice_ref := next((a.get("$ref") for a in definition.get("anyOf", [])), None)):
|
|
36
|
+
return None
|
|
37
|
+
choice_key = choice_ref.split("#/$defs/")[-1]
|
|
38
|
+
return schema.get("$defs", {}).get(choice_key, {}).get("enum")
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def _get_property_type(cls, name: str) -> type:
|
|
42
|
+
annotation = cls.model_fields[name].annotation
|
|
43
|
+
if annotation_args := get_args(annotation):
|
|
44
|
+
# if its a union, take the first one (which is not None)
|
|
45
|
+
annotation = annotation_args[0]
|
|
46
|
+
|
|
47
|
+
if type(annotation) is EnumType:
|
|
48
|
+
return str
|
|
49
|
+
|
|
50
|
+
return annotation
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def command_schema(cls) -> dict:
|
|
54
|
+
"""The schema of the command."""
|
|
55
|
+
base_properties = {"note_id", "command_uuid", "user_id"}
|
|
56
|
+
schema = cls.model_json_schema()
|
|
57
|
+
return {
|
|
58
|
+
definition.get("commands_api_name", name): {
|
|
59
|
+
"required": name in schema["required"],
|
|
60
|
+
"type": cls._get_property_type(name),
|
|
61
|
+
"choices": cls._get_property_choices(name, schema),
|
|
62
|
+
}
|
|
63
|
+
for name, definition in schema["properties"].items()
|
|
64
|
+
if name not in base_properties
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
def originate(self) -> Effect:
|
|
68
|
+
"""Originate a new command in the note body."""
|
|
69
|
+
if not self.note_id:
|
|
70
|
+
raise AttributeError("Note id is required to originate a command")
|
|
71
|
+
return {
|
|
72
|
+
"type": f"ADD_{self.Meta.key.upper()}_COMMAND",
|
|
73
|
+
"payload": {
|
|
74
|
+
"user": self.user_id,
|
|
75
|
+
"note": self.note_id,
|
|
76
|
+
"data": self.values,
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
def edit(self) -> Effect:
|
|
81
|
+
"""Edit the command."""
|
|
82
|
+
if not self.command_uuid:
|
|
83
|
+
raise AttributeError("Command uuid is required to edit a command")
|
|
84
|
+
return {
|
|
85
|
+
"type": f"EDIT_{self.Meta.key.upper()}_COMMAND",
|
|
86
|
+
"payload": {
|
|
87
|
+
"user": self.user_id,
|
|
88
|
+
"command": self.command_uuid,
|
|
89
|
+
"data": self.values,
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
def delete(self) -> Effect:
|
|
94
|
+
"""Delete the command."""
|
|
95
|
+
if not self.command_uuid:
|
|
96
|
+
raise AttributeError("Command uuid is required to delete a command")
|
|
97
|
+
return {
|
|
98
|
+
"type": f"DELETE_{self.Meta.key.upper()}_COMMAND",
|
|
99
|
+
"payload": {"command": self.command_uuid, "user": self.user_id},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def commit(self) -> Effect:
|
|
103
|
+
"""Commit the command."""
|
|
104
|
+
if not self.command_uuid:
|
|
105
|
+
raise AttributeError("Command uuid is required to commit a command")
|
|
106
|
+
return {
|
|
107
|
+
"type": f"COMMIT_{self.Meta.key.upper()}_COMMAND",
|
|
108
|
+
"payload": {"command": self.command_uuid, "user": self.user_id},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
def enter_in_error(self) -> Effect:
|
|
112
|
+
"""Mark the command as entered-in-error."""
|
|
113
|
+
if not self.command_uuid:
|
|
114
|
+
raise AttributeError("Command uuid is required to enter in error a command")
|
|
115
|
+
return {
|
|
116
|
+
"type": f"ENTER_IN_ERROR_{self.Meta.key.upper()}_COMMAND",
|
|
117
|
+
"payload": {"command": self.command_uuid, "user": self.user_id},
|
|
118
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AssessCommand(_BaseCommand):
|
|
8
|
+
"""A class for managing an Assess command within a specific note."""
|
|
9
|
+
|
|
10
|
+
class Meta:
|
|
11
|
+
key = "assess"
|
|
12
|
+
|
|
13
|
+
class Status(Enum):
|
|
14
|
+
IMPROVED = "improved"
|
|
15
|
+
STABLE = "stable"
|
|
16
|
+
DETERIORATED = "deteriorated"
|
|
17
|
+
|
|
18
|
+
condition_id: str = Field(json_schema_extra={"commands_api_name": "condition"})
|
|
19
|
+
background: str | None = None
|
|
20
|
+
status: Status | None = None
|
|
21
|
+
narrative: str | None = None
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def values(self) -> dict:
|
|
25
|
+
"""The Assess command's field values."""
|
|
26
|
+
return {
|
|
27
|
+
"condition_id": self.condition_id,
|
|
28
|
+
"background": self.background,
|
|
29
|
+
"status": self.status.value if self.status else None,
|
|
30
|
+
"narrative": self.narrative,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# how do we make sure that condition_id is a valid condition for the patient?
|
|
35
|
+
|
|
36
|
+
# idea1:
|
|
37
|
+
# create a class attribute 'pre_validate_condition': bool
|
|
38
|
+
# True: before doing any actions against the home-app instance, will first check
|
|
39
|
+
# if its an active condition for that patient, and it not then logs a message
|
|
40
|
+
# and doesn't do the action. can even create a cache so that we dont always
|
|
41
|
+
# have to keep asking home-app for every patient
|
|
42
|
+
# False: still tries to do it but will run up against whatever home-app barriers
|
|
43
|
+
# we have against actions like that (if those dont already exist, then
|
|
44
|
+
# definitely create them!)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# idea2:
|
|
48
|
+
# validator that checks that condition.patient is the same as note.patient
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DiagnoseCommand(_BaseCommand):
|
|
9
|
+
"""A class for managing a Diagnose command within a specific note."""
|
|
10
|
+
|
|
11
|
+
class Meta:
|
|
12
|
+
key = "diagnose"
|
|
13
|
+
|
|
14
|
+
icd10_code: str = Field(json_schema_extra={"commands_api_name": "diagnose"})
|
|
15
|
+
background: str | None = None
|
|
16
|
+
approximate_date_of_onset: datetime | None = None
|
|
17
|
+
today_assessment: str | None = None
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def values(self) -> dict:
|
|
21
|
+
"""The Diagnose command's field values."""
|
|
22
|
+
return {
|
|
23
|
+
"icd10_code": self.icd10_code,
|
|
24
|
+
"background": self.background,
|
|
25
|
+
"approximate_date_of_onset": (
|
|
26
|
+
self.approximate_date_of_onset.isoformat()
|
|
27
|
+
if self.approximate_date_of_onset
|
|
28
|
+
else None
|
|
29
|
+
),
|
|
30
|
+
"today_assessment": self.today_assessment,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# how do we make sure icd10_code is a valid code?
|
|
35
|
+
|
|
36
|
+
# idea1:
|
|
37
|
+
# create an auto-generated enum class of all possible icd10s, then type the field as that enum
|
|
38
|
+
# will require releasing a new version with the new codes every year, and devs will need to update
|
|
39
|
+
# to make sure they have the latest version to get the right set of codes.
|
|
40
|
+
|
|
41
|
+
# idea2:
|
|
42
|
+
# see if we can get ValueSets to play nicely with pydantic
|
|
43
|
+
|
|
44
|
+
# idea3: runtime warning after pinging ontologies
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class GoalCommand(_BaseCommand):
|
|
8
|
+
"""A class for managing a Goal command within a specific note."""
|
|
9
|
+
|
|
10
|
+
class Meta:
|
|
11
|
+
key = "goal"
|
|
12
|
+
|
|
13
|
+
class Priority(Enum):
|
|
14
|
+
HIGH = "high-priority"
|
|
15
|
+
MEDIUM = "medium-priority"
|
|
16
|
+
LOW = "low-priority"
|
|
17
|
+
|
|
18
|
+
class AchievementStatus(Enum):
|
|
19
|
+
IN_PROGRESS = "in-progress"
|
|
20
|
+
IMPROVING = "improving"
|
|
21
|
+
WORSENING = "worsening"
|
|
22
|
+
NO_CHANGE = "no-change"
|
|
23
|
+
ACHIEVED = "achieved"
|
|
24
|
+
SUSTAINING = "sustaining"
|
|
25
|
+
NOT_ACHIEVED = "not-achieved"
|
|
26
|
+
NO_PROGRESS = "no-progress"
|
|
27
|
+
NOT_ATTAINABLE = "not-attainable"
|
|
28
|
+
|
|
29
|
+
goal_statement: str
|
|
30
|
+
start_date: datetime | None = None
|
|
31
|
+
due_date: datetime | None = None
|
|
32
|
+
achievement_status: AchievementStatus | None = None
|
|
33
|
+
priority: Priority | None = None
|
|
34
|
+
progress: str | None = None
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def values(self) -> dict:
|
|
38
|
+
"""The Goal command's field values."""
|
|
39
|
+
return {
|
|
40
|
+
"goal_statement": self.goal_statement,
|
|
41
|
+
"start_date": (self.start_date.isoformat() if self.start_date else None),
|
|
42
|
+
"due_date": (self.due_date.isoformat() if self.start_date else None),
|
|
43
|
+
"achievement_status": (
|
|
44
|
+
self.achievement_status.value if self.achievement_status else None
|
|
45
|
+
),
|
|
46
|
+
"priority": (self.priority.value if self.priority else None),
|
|
47
|
+
"progress": self.progress,
|
|
48
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class HistoryOfPresentIllnessCommand(_BaseCommand):
|
|
5
|
+
"""A class for managing a HPI command within a specific note."""
|
|
6
|
+
|
|
7
|
+
class Meta:
|
|
8
|
+
key = "hpi"
|
|
9
|
+
|
|
10
|
+
narrative: str
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def values(self) -> dict:
|
|
14
|
+
"""The HPI command's field values."""
|
|
15
|
+
return {"narrative": self.narrative}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MedicationStatementCommand(_BaseCommand):
|
|
6
|
+
"""A class for managing a MedicationStatement command within a specific note."""
|
|
7
|
+
|
|
8
|
+
class Meta:
|
|
9
|
+
key = "medicationStatement"
|
|
10
|
+
|
|
11
|
+
fdb_code: str = Field(json_schema_extra={"commands_api_name": "medication"})
|
|
12
|
+
sig: str | None = None
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def values(self) -> dict:
|
|
16
|
+
"""The MedicationStatement command's field values."""
|
|
17
|
+
return {"fdb_code": self.fdb_code, "sig": self.sig}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# how do we make sure fdb_code is a valid code?
|
|
21
|
+
|
|
22
|
+
# idea1:
|
|
23
|
+
# create an auto-generated enum class of all possible fdbs, then type the field as that enum
|
|
24
|
+
# will require releasing a new version with the new codes every year, and devs will need to update
|
|
25
|
+
# to make sure they have the latest version to get the right set of codes.
|
|
26
|
+
|
|
27
|
+
# idea2:
|
|
28
|
+
# see if we can get ValueSets to play nicely with pydantic
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PlanCommand(_BaseCommand):
|
|
5
|
+
"""A class for managing a Plan command within a specific note."""
|
|
6
|
+
|
|
7
|
+
class Meta:
|
|
8
|
+
key = "plan"
|
|
9
|
+
|
|
10
|
+
narrative: str
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def values(self) -> dict:
|
|
14
|
+
"""The Plan command's field values."""
|
|
15
|
+
return {"narrative": self.narrative}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
6
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PrescribeCommand(_BaseCommand):
|
|
10
|
+
"""A class for managing a Prescribe command within a specific note."""
|
|
11
|
+
|
|
12
|
+
class Meta:
|
|
13
|
+
key = "prescribe"
|
|
14
|
+
|
|
15
|
+
class Substitutions(Enum):
|
|
16
|
+
ALLOWED = "allowed"
|
|
17
|
+
NOT_ALLOWED = "not_allowed"
|
|
18
|
+
|
|
19
|
+
fdb_code: str = Field(json_schema_extra={"commands_api_name": "prescribe"})
|
|
20
|
+
icd10_codes: list[str] | None = Field(
|
|
21
|
+
None, json_schema_extra={"commandsd_api_name": "indications"}
|
|
22
|
+
)
|
|
23
|
+
sig: str
|
|
24
|
+
days_supply: int | None = None
|
|
25
|
+
quantity_to_dispense: Decimal
|
|
26
|
+
type_to_dispense: str
|
|
27
|
+
refills: int
|
|
28
|
+
substitutions: Substitutions = Substitutions.ALLOWED # type: ignore
|
|
29
|
+
pharmacy: str | None = None
|
|
30
|
+
prescriber_id: str = Field(json_schema_extra={"commands_api_name": "prescriber"})
|
|
31
|
+
note_to_pharmacist: str | None = None
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def values(self) -> dict:
|
|
35
|
+
"""The Prescribe command's field values."""
|
|
36
|
+
return {
|
|
37
|
+
"fdb_code": self.fdb_code,
|
|
38
|
+
"icd10_codes": self.icd10_codes,
|
|
39
|
+
"sig": self.sig,
|
|
40
|
+
"days_supply": self.days_supply,
|
|
41
|
+
"quantity_to_dispense": self.quantity_to_dispense,
|
|
42
|
+
"type_to_dispense": self.type_to_dispense,
|
|
43
|
+
"refills": self.refills,
|
|
44
|
+
"substitutions": self.substitutions,
|
|
45
|
+
"pharmacy": self.pharmacy,
|
|
46
|
+
"prescriber_id": self.prescriber_id,
|
|
47
|
+
"note_to_pharmacist": self.note_to_pharmacist,
|
|
48
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class QuestionnaireCommand(_BaseCommand):
|
|
6
|
+
"""A class for managing a Questionnaire command within a specific note."""
|
|
7
|
+
|
|
8
|
+
class Meta:
|
|
9
|
+
key = "questionnaire"
|
|
10
|
+
|
|
11
|
+
questionnaire_id: str = Field(json_schema_extra={"commands_api_name": "questionnaire"})
|
|
12
|
+
result: str | None = None
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def values(self) -> dict:
|
|
16
|
+
"""The Questionnaire command's field values."""
|
|
17
|
+
return {"questionnaire_id": self.questionnaire_id, "result": self.result}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from pydantic import model_validator
|
|
2
|
+
from typing_extensions import Self
|
|
3
|
+
|
|
4
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
5
|
+
from canvas_sdk.commands.constants import Coding
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ReasonForVisitCommand(_BaseCommand):
|
|
9
|
+
"""A class for managing a ReasonForVisit command within a specific note."""
|
|
10
|
+
|
|
11
|
+
class Meta:
|
|
12
|
+
key = "reasonForVisit"
|
|
13
|
+
|
|
14
|
+
structured: bool = False
|
|
15
|
+
# how do we make sure that coding is a valid rfv coding from their home-app?
|
|
16
|
+
coding: Coding | None = None
|
|
17
|
+
comment: str | None = None
|
|
18
|
+
|
|
19
|
+
@model_validator(mode="after")
|
|
20
|
+
def _verify_structured_has_a_coding(self) -> Self:
|
|
21
|
+
if self.structured and not self.coding:
|
|
22
|
+
raise ValueError("Structured RFV should have a coding.")
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def command_schema(cls) -> dict:
|
|
27
|
+
"""The schema of the command."""
|
|
28
|
+
command_schema = super().command_schema()
|
|
29
|
+
# the commands api does not include the 'structured' field in the fields response
|
|
30
|
+
command_schema.pop("structured")
|
|
31
|
+
return command_schema
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def values(self) -> dict:
|
|
35
|
+
"""The ReasonForVisit command's field values."""
|
|
36
|
+
return {"structured": self.structured, "coding": self.coding, "comment": self.comment}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class StopMedicationCommand(_BaseCommand):
|
|
6
|
+
"""A class for managing a StopMedication command within a specific note."""
|
|
7
|
+
|
|
8
|
+
class Meta:
|
|
9
|
+
key = "stopMedication"
|
|
10
|
+
|
|
11
|
+
# how do we make sure this is a valid medication_id for the patient?
|
|
12
|
+
medication_id: str = Field(json_schema_extra={"commands_api_name": "medication"})
|
|
13
|
+
rationale: str | None = None
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def values(self) -> dict:
|
|
17
|
+
"""The StopMedication command's field values."""
|
|
18
|
+
return {"medication_id": self.medication_id, "rationale": self.rationale}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
6
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UpdateGoalCommand(_BaseCommand):
|
|
10
|
+
"""A class for managing an UpdateGoal command within a specific note."""
|
|
11
|
+
|
|
12
|
+
class Meta:
|
|
13
|
+
key = "updateGoal"
|
|
14
|
+
|
|
15
|
+
class AchievementStatus(Enum):
|
|
16
|
+
IN_PROGRESS = "in-progress"
|
|
17
|
+
IMPROVING = "improving"
|
|
18
|
+
WORSENING = "worsening"
|
|
19
|
+
NO_CHANGE = "no-change"
|
|
20
|
+
ACHIEVED = "achieved"
|
|
21
|
+
SUSTAINING = "sustaining"
|
|
22
|
+
NOT_ACHIEVED = "not-achieved"
|
|
23
|
+
NO_PROGRESS = "no-progress"
|
|
24
|
+
NOT_ATTAINABLE = "not-attainable"
|
|
25
|
+
|
|
26
|
+
class Priority(Enum):
|
|
27
|
+
HIGH = "high-priority"
|
|
28
|
+
MEDIUM = "medium-priority"
|
|
29
|
+
LOW = "low-priority"
|
|
30
|
+
|
|
31
|
+
goal_id: str = Field(json_schema_extra={"commands_api_name": "goal_statement"})
|
|
32
|
+
due_date: datetime | None = None
|
|
33
|
+
achievement_status: AchievementStatus | None = None
|
|
34
|
+
priority: Priority | None = None
|
|
35
|
+
progress: str | None = None
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def values(self) -> dict:
|
|
39
|
+
"""The UpdateGoal command's field values."""
|
|
40
|
+
return {
|
|
41
|
+
"goal_id": self.goal_id,
|
|
42
|
+
"due_date": (self.due_date.isoformat() if self.due_date else None),
|
|
43
|
+
"achievement_status": (
|
|
44
|
+
self.achievement_status.value if self.achievement_status else None
|
|
45
|
+
),
|
|
46
|
+
"priority": (self.priority.value if self.priority else None),
|
|
47
|
+
"progress": self.progress,
|
|
48
|
+
}
|