canvas 0.1.12b0__py3-none-any.whl → 0.1.14__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.12b0.dist-info → canvas-0.1.14.dist-info}/METADATA +43 -2
- canvas-0.1.14.dist-info/RECORD +90 -0
- {canvas-0.1.12b0.dist-info → canvas-0.1.14.dist-info}/WHEEL +1 -1
- canvas_cli/apps/plugin/__init__.py +3 -1
- canvas_cli/apps/plugin/plugin.py +74 -0
- canvas_cli/main.py +5 -3
- canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/my_protocol.py +3 -0
- canvas_generated/messages/effects_pb2.py +28 -0
- canvas_generated/messages/effects_pb2.pyi +147 -0
- canvas_generated/messages/events_pb2.py +31 -0
- {generated → canvas_generated}/messages/events_pb2.pyi +3 -1
- {generated → canvas_generated}/messages/plugins_pb2.py +7 -7
- canvas_generated/services/plugin_runner_pb2.py +28 -0
- {generated → canvas_generated}/services/plugin_runner_pb2.pyi +2 -2
- {generated → canvas_generated}/services/plugin_runner_pb2_grpc.py +14 -14
- canvas_sdk/base.py +45 -0
- canvas_sdk/commands/base.py +61 -41
- canvas_sdk/commands/commands/assess.py +6 -2
- canvas_sdk/commands/commands/diagnose.py +4 -14
- canvas_sdk/commands/commands/goal.py +3 -2
- canvas_sdk/commands/commands/history_present_illness.py +2 -1
- canvas_sdk/commands/commands/medication_statement.py +6 -2
- canvas_sdk/commands/commands/plan.py +2 -1
- canvas_sdk/commands/commands/prescribe.py +24 -11
- canvas_sdk/commands/commands/questionnaire.py +6 -2
- canvas_sdk/commands/commands/reason_for_visit.py +13 -6
- canvas_sdk/commands/commands/stop_medication.py +6 -2
- canvas_sdk/commands/commands/update_goal.py +4 -1
- canvas_sdk/commands/tests/test_utils.py +31 -64
- canvas_sdk/commands/tests/tests.py +116 -65
- canvas_sdk/data/__init__.py +1 -0
- canvas_sdk/data/base.py +22 -0
- canvas_sdk/data/patient.py +6 -0
- canvas_sdk/data/staff.py +6 -0
- canvas_sdk/data/task.py +60 -0
- canvas_sdk/effects/__init__.py +1 -1
- canvas_sdk/effects/banner_alert/__init__.py +2 -0
- canvas_sdk/effects/banner_alert/add_banner_alert.py +49 -0
- canvas_sdk/effects/banner_alert/remove_banner_alert.py +20 -0
- canvas_sdk/effects/base.py +4 -6
- canvas_sdk/events/__init__.py +1 -1
- canvas_sdk/handlers/__init__.py +1 -0
- canvas_sdk/handlers/base.py +16 -0
- canvas_sdk/handlers/cron_task.py +35 -0
- canvas_sdk/protocols/base.py +2 -11
- canvas_sdk/utils/stats.py +27 -0
- logger/__init__.py +2 -0
- logger/logger.py +48 -0
- canvas-0.1.12b0.dist-info/RECORD +0 -78
- canvas_sdk/effects/banner_alert/banner_alert.py +0 -37
- canvas_sdk/effects/banner_alert/constants.py +0 -19
- generated/messages/effects_pb2.py +0 -28
- generated/messages/effects_pb2.pyi +0 -25
- generated/messages/events_pb2.py +0 -31
- generated/services/plugin_runner_pb2.py +0 -28
- {canvas-0.1.12b0.dist-info → canvas-0.1.14.dist-info}/entry_points.txt +0 -0
- {generated → canvas_generated}/messages/effects_pb2_grpc.py +0 -0
- {generated → canvas_generated}/messages/events_pb2_grpc.py +0 -0
- {generated → canvas_generated}/messages/plugins_pb2.pyi +0 -0
- {generated → canvas_generated}/messages/plugins_pb2_grpc.py +0 -0
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"""Client and server classes corresponding to protobuf-defined services."""
|
|
3
3
|
import grpc
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
from
|
|
5
|
+
from canvas_generated.messages import events_pb2 as canvas__generated_dot_messages_dot_events__pb2
|
|
6
|
+
from canvas_generated.messages import plugins_pb2 as canvas__generated_dot_messages_dot_plugins__pb2
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class PluginRunnerStub(object):
|
|
@@ -17,13 +17,13 @@ class PluginRunnerStub(object):
|
|
|
17
17
|
"""
|
|
18
18
|
self.HandleEvent = channel.unary_stream(
|
|
19
19
|
'/canvas.PluginRunner/HandleEvent',
|
|
20
|
-
request_serializer=
|
|
21
|
-
response_deserializer=
|
|
20
|
+
request_serializer=canvas__generated_dot_messages_dot_events__pb2.Event.SerializeToString,
|
|
21
|
+
response_deserializer=canvas__generated_dot_messages_dot_events__pb2.EventResponse.FromString,
|
|
22
22
|
)
|
|
23
23
|
self.ReloadPlugins = channel.unary_stream(
|
|
24
24
|
'/canvas.PluginRunner/ReloadPlugins',
|
|
25
|
-
request_serializer=
|
|
26
|
-
response_deserializer=
|
|
25
|
+
request_serializer=canvas__generated_dot_messages_dot_plugins__pb2.ReloadPluginsRequest.SerializeToString,
|
|
26
|
+
response_deserializer=canvas__generated_dot_messages_dot_plugins__pb2.ReloadPluginsResponse.FromString,
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
|
|
@@ -47,13 +47,13 @@ def add_PluginRunnerServicer_to_server(servicer, server):
|
|
|
47
47
|
rpc_method_handlers = {
|
|
48
48
|
'HandleEvent': grpc.unary_stream_rpc_method_handler(
|
|
49
49
|
servicer.HandleEvent,
|
|
50
|
-
request_deserializer=
|
|
51
|
-
response_serializer=
|
|
50
|
+
request_deserializer=canvas__generated_dot_messages_dot_events__pb2.Event.FromString,
|
|
51
|
+
response_serializer=canvas__generated_dot_messages_dot_events__pb2.EventResponse.SerializeToString,
|
|
52
52
|
),
|
|
53
53
|
'ReloadPlugins': grpc.unary_stream_rpc_method_handler(
|
|
54
54
|
servicer.ReloadPlugins,
|
|
55
|
-
request_deserializer=
|
|
56
|
-
response_serializer=
|
|
55
|
+
request_deserializer=canvas__generated_dot_messages_dot_plugins__pb2.ReloadPluginsRequest.FromString,
|
|
56
|
+
response_serializer=canvas__generated_dot_messages_dot_plugins__pb2.ReloadPluginsResponse.SerializeToString,
|
|
57
57
|
),
|
|
58
58
|
}
|
|
59
59
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
@@ -77,8 +77,8 @@ class PluginRunner(object):
|
|
|
77
77
|
timeout=None,
|
|
78
78
|
metadata=None):
|
|
79
79
|
return grpc.experimental.unary_stream(request, target, '/canvas.PluginRunner/HandleEvent',
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
canvas__generated_dot_messages_dot_events__pb2.Event.SerializeToString,
|
|
81
|
+
canvas__generated_dot_messages_dot_events__pb2.EventResponse.FromString,
|
|
82
82
|
options, channel_credentials,
|
|
83
83
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
84
84
|
|
|
@@ -94,7 +94,7 @@ class PluginRunner(object):
|
|
|
94
94
|
timeout=None,
|
|
95
95
|
metadata=None):
|
|
96
96
|
return grpc.experimental.unary_stream(request, target, '/canvas.PluginRunner/ReloadPlugins',
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
canvas__generated_dot_messages_dot_plugins__pb2.ReloadPluginsRequest.SerializeToString,
|
|
98
|
+
canvas__generated_dot_messages_dot_plugins__pb2.ReloadPluginsResponse.FromString,
|
|
99
99
|
options, channel_credentials,
|
|
100
100
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
canvas_sdk/base.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict
|
|
6
|
+
from pydantic_core import InitErrorDetails, PydanticCustomError, ValidationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Model(BaseModel):
|
|
10
|
+
"""A base model that includes validation methods."""
|
|
11
|
+
|
|
12
|
+
class Meta:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
model_config = ConfigDict(
|
|
16
|
+
strict=True,
|
|
17
|
+
revalidate_instances="always",
|
|
18
|
+
validate_assignment=True,
|
|
19
|
+
json_encoders={
|
|
20
|
+
date: lambda v: v.isoformat(),
|
|
21
|
+
datetime: lambda v: v.isoformat(),
|
|
22
|
+
Enum: lambda v: v.value,
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def _get_effect_method_required_fields(self, method: str) -> tuple[str]:
|
|
27
|
+
return getattr(self.Meta, f"{method}_required_fields", tuple())
|
|
28
|
+
|
|
29
|
+
def _create_error_detail(self, type: str, message: str, value: Any) -> InitErrorDetails:
|
|
30
|
+
return InitErrorDetails({"type": PydanticCustomError(type, message), "input": value})
|
|
31
|
+
|
|
32
|
+
def _get_error_details(self, method: str) -> list[InitErrorDetails]:
|
|
33
|
+
required_fields = self._get_effect_method_required_fields(method)
|
|
34
|
+
return [
|
|
35
|
+
self._create_error_detail(
|
|
36
|
+
"missing", f"Field '{field}' is required to {method.replace('_', ' ')} a command", v
|
|
37
|
+
)
|
|
38
|
+
for field in required_fields
|
|
39
|
+
if (v := getattr(self, field)) is None
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
def _validate_before_effect(self, method: str) -> None:
|
|
43
|
+
self.model_validate(self)
|
|
44
|
+
if error_details := self._get_error_details(method):
|
|
45
|
+
raise ValidationError.from_exception_data(self.__class__.__name__, error_details)
|
canvas_sdk/commands/base.py
CHANGED
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import re
|
|
2
3
|
from enum import EnumType
|
|
3
|
-
from typing import get_args
|
|
4
|
+
from typing import Literal, get_args
|
|
4
5
|
|
|
5
|
-
from
|
|
6
|
-
from
|
|
6
|
+
from canvas_sdk.base import Model
|
|
7
|
+
from canvas_sdk.effects import Effect, EffectType
|
|
7
8
|
|
|
8
|
-
from canvas_sdk.effects import Effect
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class _BaseCommand(BaseModel):
|
|
12
|
-
model_config = ConfigDict(strict=True, validate_assignment=True)
|
|
13
9
|
|
|
10
|
+
class _BaseCommand(Model):
|
|
14
11
|
class Meta:
|
|
15
12
|
key = ""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
originate_required_fields = (
|
|
14
|
+
"user_id",
|
|
15
|
+
"note_uuid",
|
|
16
|
+
)
|
|
17
|
+
edit_required_fields = (
|
|
18
|
+
"user_id",
|
|
19
|
+
"command_uuid",
|
|
20
|
+
)
|
|
21
|
+
delete_required_fields = (
|
|
22
|
+
"user_id",
|
|
23
|
+
"command_uuid",
|
|
24
|
+
)
|
|
25
|
+
commit_required_fields = (
|
|
26
|
+
"user_id",
|
|
27
|
+
"command_uuid",
|
|
28
|
+
)
|
|
29
|
+
enter_in_error_required_fields = (
|
|
30
|
+
"user_id",
|
|
31
|
+
"command_uuid",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def constantized_key(self) -> str:
|
|
35
|
+
return re.sub(r"(?<!^)(?=[A-Z])", "_", self.Meta.key).upper()
|
|
36
|
+
|
|
37
|
+
note_uuid: str | None = None
|
|
19
38
|
command_uuid: str | None = None
|
|
20
|
-
user_id: int
|
|
39
|
+
user_id: int | None = None
|
|
21
40
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
41
|
+
def _get_effect_method_required_fields(
|
|
42
|
+
self, method: Literal["originate", "edit", "delete", "commit", "enter_in_error"]
|
|
43
|
+
) -> tuple[str]:
|
|
44
|
+
base_required_fields: tuple = getattr(
|
|
45
|
+
_BaseCommand.Meta, f"{method}_required_fields", tuple()
|
|
46
|
+
)
|
|
47
|
+
command_required_fields = super()._get_effect_method_required_fields(method)
|
|
48
|
+
return tuple(set(base_required_fields) | set(command_required_fields))
|
|
27
49
|
|
|
28
50
|
@property
|
|
29
51
|
def values(self) -> dict:
|
|
@@ -52,11 +74,12 @@ class _BaseCommand(BaseModel):
|
|
|
52
74
|
@classmethod
|
|
53
75
|
def command_schema(cls) -> dict:
|
|
54
76
|
"""The schema of the command."""
|
|
55
|
-
base_properties = {"
|
|
77
|
+
base_properties = {"note_uuid", "command_uuid", "user_id"}
|
|
56
78
|
schema = cls.model_json_schema()
|
|
79
|
+
required_fields: tuple = getattr(cls.Meta, "originate_required_fields", tuple())
|
|
57
80
|
return {
|
|
58
81
|
definition.get("commands_api_name", name): {
|
|
59
|
-
"required": name in
|
|
82
|
+
"required": name in required_fields,
|
|
60
83
|
"type": cls._get_property_type(name),
|
|
61
84
|
"choices": cls._get_property_choices(name, schema),
|
|
62
85
|
}
|
|
@@ -66,23 +89,23 @@ class _BaseCommand(BaseModel):
|
|
|
66
89
|
|
|
67
90
|
def originate(self) -> Effect:
|
|
68
91
|
"""Originate a new command in the note body."""
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
self._validate_before_effect("originate")
|
|
93
|
+
return Effect(
|
|
94
|
+
type=EffectType.Value(f"ORIGINATE_{self.constantized_key()}_COMMAND"),
|
|
95
|
+
payload=json.dumps(
|
|
96
|
+
{
|
|
97
|
+
"user": self.user_id,
|
|
98
|
+
"note": self.note_uuid,
|
|
99
|
+
"data": self.values,
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
)
|
|
79
103
|
|
|
80
104
|
def edit(self) -> Effect:
|
|
81
105
|
"""Edit the command."""
|
|
82
|
-
|
|
83
|
-
raise AttributeError("Command uuid is required to edit a command")
|
|
106
|
+
self._validate_before_effect("edit")
|
|
84
107
|
return {
|
|
85
|
-
"type": f"EDIT_{self.
|
|
108
|
+
"type": f"EDIT_{self.constantized_key()}_COMMAND",
|
|
86
109
|
"payload": {
|
|
87
110
|
"user": self.user_id,
|
|
88
111
|
"command": self.command_uuid,
|
|
@@ -92,27 +115,24 @@ class _BaseCommand(BaseModel):
|
|
|
92
115
|
|
|
93
116
|
def delete(self) -> Effect:
|
|
94
117
|
"""Delete the command."""
|
|
95
|
-
|
|
96
|
-
raise AttributeError("Command uuid is required to delete a command")
|
|
118
|
+
self._validate_before_effect("delete")
|
|
97
119
|
return {
|
|
98
|
-
"type": f"DELETE_{self.
|
|
120
|
+
"type": f"DELETE_{self.constantized_key()}_COMMAND",
|
|
99
121
|
"payload": {"command": self.command_uuid, "user": self.user_id},
|
|
100
122
|
}
|
|
101
123
|
|
|
102
124
|
def commit(self) -> Effect:
|
|
103
125
|
"""Commit the command."""
|
|
104
|
-
|
|
105
|
-
raise AttributeError("Command uuid is required to commit a command")
|
|
126
|
+
self._validate_before_effect("commit")
|
|
106
127
|
return {
|
|
107
|
-
"type": f"COMMIT_{self.
|
|
128
|
+
"type": f"COMMIT_{self.constantized_key()}_COMMAND",
|
|
108
129
|
"payload": {"command": self.command_uuid, "user": self.user_id},
|
|
109
130
|
}
|
|
110
131
|
|
|
111
132
|
def enter_in_error(self) -> Effect:
|
|
112
133
|
"""Mark the command as entered-in-error."""
|
|
113
|
-
|
|
114
|
-
raise AttributeError("Command uuid is required to enter in error a command")
|
|
134
|
+
self._validate_before_effect("enter_in_error")
|
|
115
135
|
return {
|
|
116
|
-
"type": f"ENTER_IN_ERROR_{self.
|
|
136
|
+
"type": f"ENTER_IN_ERROR_{self.constantized_key()}_COMMAND",
|
|
117
137
|
"payload": {"command": self.command_uuid, "user": self.user_id},
|
|
118
138
|
}
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
-
from canvas_sdk.commands.base import _BaseCommand
|
|
4
3
|
from pydantic import Field
|
|
5
4
|
|
|
5
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
class AssessCommand(_BaseCommand):
|
|
8
9
|
"""A class for managing an Assess command within a specific note."""
|
|
9
10
|
|
|
10
11
|
class Meta:
|
|
11
12
|
key = "assess"
|
|
13
|
+
originate_required_fields = ("condition_id",)
|
|
12
14
|
|
|
13
15
|
class Status(Enum):
|
|
14
16
|
IMPROVED = "improved"
|
|
15
17
|
STABLE = "stable"
|
|
16
18
|
DETERIORATED = "deteriorated"
|
|
17
19
|
|
|
18
|
-
condition_id: str = Field(
|
|
20
|
+
condition_id: str | None = Field(
|
|
21
|
+
default=None, json_schema_extra={"commands_api_name": "condition"}
|
|
22
|
+
)
|
|
19
23
|
background: str | None = None
|
|
20
24
|
status: Status | None = None
|
|
21
25
|
narrative: str | None = None
|
|
@@ -10,8 +10,11 @@ class DiagnoseCommand(_BaseCommand):
|
|
|
10
10
|
|
|
11
11
|
class Meta:
|
|
12
12
|
key = "diagnose"
|
|
13
|
+
originate_required_fields = ("icd10_code",)
|
|
13
14
|
|
|
14
|
-
icd10_code: str = Field(
|
|
15
|
+
icd10_code: str | None = Field(
|
|
16
|
+
default=None, json_schema_extra={"commands_api_name": "diagnose"}
|
|
17
|
+
)
|
|
15
18
|
background: str | None = None
|
|
16
19
|
approximate_date_of_onset: datetime | None = None
|
|
17
20
|
today_assessment: str | None = None
|
|
@@ -29,16 +32,3 @@ class DiagnoseCommand(_BaseCommand):
|
|
|
29
32
|
),
|
|
30
33
|
"today_assessment": self.today_assessment,
|
|
31
34
|
}
|
|
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
|
|
@@ -9,6 +9,7 @@ class GoalCommand(_BaseCommand):
|
|
|
9
9
|
|
|
10
10
|
class Meta:
|
|
11
11
|
key = "goal"
|
|
12
|
+
originate_required_fields = ("goal_statement", "start_date")
|
|
12
13
|
|
|
13
14
|
class Priority(Enum):
|
|
14
15
|
HIGH = "high-priority"
|
|
@@ -26,7 +27,7 @@ class GoalCommand(_BaseCommand):
|
|
|
26
27
|
NO_PROGRESS = "no-progress"
|
|
27
28
|
NOT_ATTAINABLE = "not-attainable"
|
|
28
29
|
|
|
29
|
-
goal_statement: str
|
|
30
|
+
goal_statement: str | None = None
|
|
30
31
|
start_date: datetime | None = None
|
|
31
32
|
due_date: datetime | None = None
|
|
32
33
|
achievement_status: AchievementStatus | None = None
|
|
@@ -39,7 +40,7 @@ class GoalCommand(_BaseCommand):
|
|
|
39
40
|
return {
|
|
40
41
|
"goal_statement": self.goal_statement,
|
|
41
42
|
"start_date": (self.start_date.isoformat() if self.start_date else None),
|
|
42
|
-
"due_date": (self.due_date.isoformat() if self.
|
|
43
|
+
"due_date": (self.due_date.isoformat() if self.due_date else None),
|
|
43
44
|
"achievement_status": (
|
|
44
45
|
self.achievement_status.value if self.achievement_status else None
|
|
45
46
|
),
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
from canvas_sdk.commands.base import _BaseCommand
|
|
2
1
|
from pydantic import Field
|
|
3
2
|
|
|
3
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
class MedicationStatementCommand(_BaseCommand):
|
|
6
7
|
"""A class for managing a MedicationStatement command within a specific note."""
|
|
7
8
|
|
|
8
9
|
class Meta:
|
|
9
10
|
key = "medicationStatement"
|
|
11
|
+
originate_required_fields = ("fdb_code",)
|
|
10
12
|
|
|
11
|
-
fdb_code: str = Field(
|
|
13
|
+
fdb_code: str | None = Field(
|
|
14
|
+
default=None, json_schema_extra={"commands_api_name": "medication"}
|
|
15
|
+
)
|
|
12
16
|
sig: str | None = None
|
|
13
17
|
|
|
14
18
|
@property
|
|
@@ -11,23 +11,34 @@ class PrescribeCommand(_BaseCommand):
|
|
|
11
11
|
|
|
12
12
|
class Meta:
|
|
13
13
|
key = "prescribe"
|
|
14
|
+
originate_required_fields = (
|
|
15
|
+
"fdb_code",
|
|
16
|
+
"sig",
|
|
17
|
+
"quantity_to_dispense",
|
|
18
|
+
"type_to_dispense",
|
|
19
|
+
"refills",
|
|
20
|
+
"substitutions",
|
|
21
|
+
"prescriber_id",
|
|
22
|
+
)
|
|
14
23
|
|
|
15
24
|
class Substitutions(Enum):
|
|
16
25
|
ALLOWED = "allowed"
|
|
17
26
|
NOT_ALLOWED = "not_allowed"
|
|
18
27
|
|
|
19
|
-
fdb_code: str = Field(json_schema_extra={"commands_api_name": "prescribe"})
|
|
28
|
+
fdb_code: str | None = Field(default=None, json_schema_extra={"commands_api_name": "prescribe"})
|
|
20
29
|
icd10_codes: list[str] | None = Field(
|
|
21
|
-
None, json_schema_extra={"
|
|
30
|
+
None, json_schema_extra={"commands_api_name": "indications"}
|
|
22
31
|
)
|
|
23
|
-
sig: str
|
|
32
|
+
sig: str | None = None
|
|
24
33
|
days_supply: int | None = None
|
|
25
|
-
quantity_to_dispense: Decimal
|
|
26
|
-
type_to_dispense: str
|
|
27
|
-
refills: int
|
|
28
|
-
substitutions: Substitutions
|
|
34
|
+
quantity_to_dispense: Decimal | float | int | None = None
|
|
35
|
+
type_to_dispense: str | None = None
|
|
36
|
+
refills: int | None = None
|
|
37
|
+
substitutions: Substitutions | None = None
|
|
29
38
|
pharmacy: str | None = None
|
|
30
|
-
prescriber_id: str = Field(
|
|
39
|
+
prescriber_id: str | None = Field(
|
|
40
|
+
default=None, json_schema_extra={"commands_api_name": "prescriber"}
|
|
41
|
+
)
|
|
31
42
|
note_to_pharmacist: str | None = None
|
|
32
43
|
|
|
33
44
|
@property
|
|
@@ -38,10 +49,12 @@ class PrescribeCommand(_BaseCommand):
|
|
|
38
49
|
"icd10_codes": self.icd10_codes,
|
|
39
50
|
"sig": self.sig,
|
|
40
51
|
"days_supply": self.days_supply,
|
|
41
|
-
"quantity_to_dispense":
|
|
42
|
-
|
|
52
|
+
"quantity_to_dispense": (
|
|
53
|
+
str(Decimal(self.quantity_to_dispense)) if self.quantity_to_dispense else None
|
|
54
|
+
),
|
|
55
|
+
# "type_to_dispense": self.type_to_dispense,
|
|
43
56
|
"refills": self.refills,
|
|
44
|
-
"substitutions": self.substitutions,
|
|
57
|
+
"substitutions": self.substitutions.value if self.substitutions else None,
|
|
45
58
|
"pharmacy": self.pharmacy,
|
|
46
59
|
"prescriber_id": self.prescriber_id,
|
|
47
60
|
"note_to_pharmacist": self.note_to_pharmacist,
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
from canvas_sdk.commands.base import _BaseCommand
|
|
2
1
|
from pydantic import Field
|
|
3
2
|
|
|
3
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
class QuestionnaireCommand(_BaseCommand):
|
|
6
7
|
"""A class for managing a Questionnaire command within a specific note."""
|
|
7
8
|
|
|
8
9
|
class Meta:
|
|
9
10
|
key = "questionnaire"
|
|
11
|
+
originate_required_fields = ("questionnaire_id",)
|
|
10
12
|
|
|
11
|
-
questionnaire_id: str = Field(
|
|
13
|
+
questionnaire_id: str | None = Field(
|
|
14
|
+
default=None, json_schema_extra={"commands_api_name": "questionnaire"}
|
|
15
|
+
)
|
|
12
16
|
result: str | None = None
|
|
13
17
|
|
|
14
18
|
@property
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_core import InitErrorDetails
|
|
3
4
|
|
|
4
5
|
from canvas_sdk.commands.base import _BaseCommand
|
|
5
6
|
from canvas_sdk.commands.constants import Coding
|
|
@@ -16,11 +17,17 @@ class ReasonForVisitCommand(_BaseCommand):
|
|
|
16
17
|
coding: Coding | None = None
|
|
17
18
|
comment: str | None = None
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
def _get_error_details(
|
|
21
|
+
self, method: Literal["originate", "edit", "delete", "commit", "enter_in_error"]
|
|
22
|
+
) -> list[InitErrorDetails]:
|
|
23
|
+
errors = super()._get_error_details(method)
|
|
21
24
|
if self.structured and not self.coding:
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
errors.append(
|
|
26
|
+
self._create_error_detail(
|
|
27
|
+
"value", f"Structured RFV should have a coding.", self.coding
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
return errors
|
|
24
31
|
|
|
25
32
|
@classmethod
|
|
26
33
|
def command_schema(cls) -> dict:
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
from canvas_sdk.commands.base import _BaseCommand
|
|
2
1
|
from pydantic import Field
|
|
3
2
|
|
|
3
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
class StopMedicationCommand(_BaseCommand):
|
|
6
7
|
"""A class for managing a StopMedication command within a specific note."""
|
|
7
8
|
|
|
8
9
|
class Meta:
|
|
9
10
|
key = "stopMedication"
|
|
11
|
+
originate_required_fields = ("medication_id",)
|
|
10
12
|
|
|
11
13
|
# how do we make sure this is a valid medication_id for the patient?
|
|
12
|
-
medication_id: str = Field(
|
|
14
|
+
medication_id: str | None = Field(
|
|
15
|
+
default=None, json_schema_extra={"commands_api_name": "medication"}
|
|
16
|
+
)
|
|
13
17
|
rationale: str | None = None
|
|
14
18
|
|
|
15
19
|
@property
|
|
@@ -11,6 +11,7 @@ class UpdateGoalCommand(_BaseCommand):
|
|
|
11
11
|
|
|
12
12
|
class Meta:
|
|
13
13
|
key = "updateGoal"
|
|
14
|
+
originate_required_fields = ("goal_id",)
|
|
14
15
|
|
|
15
16
|
class AchievementStatus(Enum):
|
|
16
17
|
IN_PROGRESS = "in-progress"
|
|
@@ -28,7 +29,9 @@ class UpdateGoalCommand(_BaseCommand):
|
|
|
28
29
|
MEDIUM = "medium-priority"
|
|
29
30
|
LOW = "low-priority"
|
|
30
31
|
|
|
31
|
-
goal_id: str = Field(
|
|
32
|
+
goal_id: str | None = Field(
|
|
33
|
+
default=None, json_schema_extra={"commands_api_name": "goal_statement"}
|
|
34
|
+
)
|
|
32
35
|
due_date: datetime | None = None
|
|
33
36
|
achievement_status: AchievementStatus | None = None
|
|
34
37
|
priority: Priority | None = None
|