canvas 0.2.10__py3-none-any.whl → 0.3.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.

Files changed (46) hide show
  1. {canvas-0.2.10.dist-info → canvas-0.3.0.dist-info}/METADATA +3 -3
  2. {canvas-0.2.10.dist-info → canvas-0.3.0.dist-info}/RECORD +46 -44
  3. canvas_cli/apps/plugin/plugin.py +56 -23
  4. canvas_cli/utils/validators/validators.py +1 -1
  5. canvas_generated/messages/effects_pb2.py +5 -5
  6. canvas_generated/messages/effects_pb2.pyi +4 -2
  7. canvas_generated/messages/events_pb2.py +3 -3
  8. canvas_generated/messages/events_pb2.pyi +62 -0
  9. canvas_generated/messages/plugins_pb2.py +1 -1
  10. canvas_generated/services/plugin_runner_pb2.py +1 -1
  11. canvas_sdk/base.py +2 -2
  12. canvas_sdk/commands/__init__.py +3 -1
  13. canvas_sdk/commands/base.py +2 -2
  14. canvas_sdk/commands/commands/allergy.py +2 -0
  15. canvas_sdk/commands/commands/close_goal.py +3 -0
  16. canvas_sdk/commands/commands/prescribe.py +1 -3
  17. canvas_sdk/commands/commands/refill.py +1 -0
  18. canvas_sdk/commands/commands/task.py +1 -1
  19. canvas_sdk/commands/commands/vitals.py +15 -12
  20. canvas_sdk/commands/tests/schema/tests.py +1 -1
  21. canvas_sdk/commands/tests/test_utils.py +4 -2
  22. canvas_sdk/data/base.py +5 -1
  23. canvas_sdk/data/client.py +1 -1
  24. canvas_sdk/data/patient.py +2 -0
  25. canvas_sdk/data/staff.py +2 -0
  26. canvas_sdk/data/task.py +7 -0
  27. canvas_sdk/effects/protocol_card/protocol_card.py +2 -0
  28. canvas_sdk/effects/protocol_card/tests.py +5 -2
  29. canvas_sdk/protocols/__init__.py +1 -0
  30. canvas_sdk/protocols/clinical_quality_measure.py +1 -0
  31. canvas_sdk/utils/http.py +19 -18
  32. canvas_sdk/utils/stats.py +2 -1
  33. canvas_sdk/v1/data/allergy_intolerance.py +2 -3
  34. canvas_sdk/v1/data/base.py +55 -9
  35. canvas_sdk/v1/data/lab.py +8 -0
  36. canvas_sdk/v1/data/patient.py +3 -0
  37. canvas_sdk/v1/data/questionnaire.py +204 -0
  38. canvas_sdk/v1/data/user.py +2 -0
  39. canvas_sdk/value_set/v2022/condition.py +2 -2
  40. canvas_sdk/value_set/v2022/encounter.py +1 -1
  41. canvas_sdk/value_set/value_set.py +20 -5
  42. logger/__init__.py +1 -0
  43. logger/logger.py +17 -6
  44. settings.py +43 -0
  45. {canvas-0.2.10.dist-info → canvas-0.3.0.dist-info}/WHEEL +0 -0
  46. {canvas-0.2.10.dist-info → canvas-0.3.0.dist-info}/entry_points.txt +0 -0
canvas_sdk/v1/data/lab.py CHANGED
@@ -6,6 +6,8 @@ from canvas_sdk.v1.data.user import CanvasUser
6
6
 
7
7
 
8
8
  class LabReport(models.Model):
9
+ """A class representing a lab report."""
10
+
9
11
  class Meta:
10
12
  managed = False
11
13
  app_label = "canvas_sdk"
@@ -38,6 +40,8 @@ class LabReport(models.Model):
38
40
 
39
41
 
40
42
  class LabReview(models.Model):
43
+ """A class representing a lab review."""
44
+
41
45
  class Meta:
42
46
  managed = False
43
47
  app_label = "canvas_sdk"
@@ -61,6 +65,8 @@ class LabReview(models.Model):
61
65
 
62
66
 
63
67
  class LabValue(models.Model):
68
+ """A class representing a lab value."""
69
+
64
70
  class Meta:
65
71
  managed = False
66
72
  app_label = "canvas_sdk"
@@ -82,6 +88,8 @@ class LabValue(models.Model):
82
88
 
83
89
 
84
90
  class LabValueCoding(models.Model):
91
+ """A class representing a lab value coding."""
92
+
85
93
  class Meta:
86
94
  managed = False
87
95
  app_label = "canvas_sdk"
@@ -4,6 +4,8 @@ from django.db import models
4
4
 
5
5
 
6
6
  class Patient(models.Model):
7
+ """A class representing a patient."""
8
+
7
9
  class Meta:
8
10
  managed = False
9
11
  app_label = "canvas_sdk"
@@ -46,4 +48,5 @@ class Patient(models.Model):
46
48
 
47
49
  @classmethod
48
50
  def find(cls, id: str) -> Self:
51
+ """Find a patient by id."""
49
52
  return cls.objects.get(id=id)
@@ -0,0 +1,204 @@
1
+ from collections.abc import Container
2
+
3
+ from django.db import models
4
+ from django.db.models import Q
5
+
6
+ from canvas_sdk.v1.data import Patient
7
+ from canvas_sdk.v1.data.base import (
8
+ CommittableModelManager,
9
+ ValueSetLookupByNameQuerySet,
10
+ )
11
+ from canvas_sdk.v1.data.user import CanvasUser
12
+
13
+
14
+ class ResponseOptionSet(models.Model):
15
+ """ResponseOptionSet."""
16
+
17
+ class Meta:
18
+ managed = False
19
+ app_label = "canvas_sdk"
20
+ db_table = "canvas_sdk_data_api_responseoptionset_001"
21
+
22
+ dbid = models.BigIntegerField(primary_key=True)
23
+ created = models.DateTimeField()
24
+ modified = models.DateTimeField()
25
+ status = models.CharField()
26
+ name = models.CharField()
27
+ code_system = models.CharField()
28
+ code = models.CharField()
29
+ type = models.CharField()
30
+ use_in_shx = models.BooleanField()
31
+
32
+
33
+ class ResponseOption(models.Model):
34
+ """ResponseOption."""
35
+
36
+ class Meta:
37
+ managed = False
38
+ app_label = "canvas_sdk"
39
+ db_table = "canvas_sdk_data_api_responseoption_001"
40
+
41
+ dbid = models.BigIntegerField(primary_key=True)
42
+ created = models.DateTimeField()
43
+ modified = models.DateTimeField()
44
+ status = models.CharField()
45
+ name = models.CharField()
46
+ code = models.CharField()
47
+ code_description = models.CharField()
48
+ value = models.CharField()
49
+ response_option_set = models.ForeignKey(
50
+ ResponseOptionSet, on_delete=models.DO_NOTHING, related_name="options"
51
+ )
52
+ ordering = models.IntegerField()
53
+
54
+
55
+ class Question(models.Model):
56
+ """Question."""
57
+
58
+ class Meta:
59
+ managed = False
60
+ app_label = "canvas_sdk"
61
+ db_table = "canvas_sdk_data_api_question_001"
62
+
63
+ id = models.UUIDField()
64
+ dbid = models.BigIntegerField(primary_key=True)
65
+ created = models.DateTimeField()
66
+ modified = models.DateTimeField()
67
+ status = models.CharField()
68
+ name = models.CharField()
69
+ response_option_set = models.ForeignKey(
70
+ ResponseOptionSet, on_delete=models.DO_NOTHING, related_name="questions"
71
+ )
72
+ acknowledge_only = models.BooleanField()
73
+ show_prologue = models.BooleanField()
74
+ code_system = models.CharField()
75
+ code = models.CharField()
76
+
77
+
78
+ class QuestionnaireValueSetLookupQuerySet(ValueSetLookupByNameQuerySet):
79
+ """QuerySet class for Questionaire ValueSet lookups."""
80
+
81
+ @staticmethod
82
+ def q_object(system: str, codes: Container[str]) -> Q:
83
+ """The code system and code values for a Questionnaire are just attributes on the model."""
84
+ return Q(code_system=system, code__in=codes)
85
+
86
+
87
+ class Questionnaire(models.Model):
88
+ """Questionnaire."""
89
+
90
+ class Meta:
91
+ managed = False
92
+ app_label = "canvas_sdk"
93
+ db_table = "canvas_sdk_data_api_questionnaire_001"
94
+
95
+ objects = models.Manager.from_queryset(QuestionnaireValueSetLookupQuerySet)()
96
+
97
+ id = models.UUIDField()
98
+ dbid = models.BigIntegerField(primary_key=True)
99
+ created = models.DateTimeField()
100
+ modified = models.DateTimeField()
101
+ status = models.CharField()
102
+ name = models.CharField()
103
+ expected_completion_time = models.FloatField()
104
+ can_originate_in_charting = models.BooleanField()
105
+ use_case_in_charting = models.CharField()
106
+ scoring_function_name = models.TextField()
107
+ scoring_code_system = models.CharField()
108
+ scoring_code = models.CharField()
109
+ code_system = models.CharField()
110
+ code = models.CharField()
111
+ search_tags = models.CharField()
112
+ questions = models.ManyToManyField(Question, through="QuestionnaireQuestionMap")
113
+ use_in_shx = models.BooleanField()
114
+ carry_forward = models.TextField()
115
+
116
+
117
+ class QuestionnaireQuestionMap(models.Model):
118
+ """QuestionnaireQuestionMap."""
119
+
120
+ class Meta:
121
+ managed = False
122
+ app_label = "canvas_sdk"
123
+ db_table = "canvas_sdk_data_api_questionnairequestionmap_001"
124
+
125
+ dbid = models.BigIntegerField(primary_key=True)
126
+ created = models.DateTimeField()
127
+ modified = models.DateTimeField()
128
+ status = models.CharField()
129
+ questionnaire = models.ForeignKey(Questionnaire, on_delete=models.DO_NOTHING)
130
+ question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
131
+
132
+
133
+ class Interview(models.Model):
134
+ """Interview."""
135
+
136
+ class Meta:
137
+ managed = False
138
+ app_label = "canvas_sdk"
139
+ db_table = "canvas_sdk_data_api_interview_001"
140
+
141
+ objects = CommittableModelManager()
142
+
143
+ id = models.UUIDField()
144
+ dbid = models.BigIntegerField(primary_key=True)
145
+ deleted = models.BooleanField()
146
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
147
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
148
+ status = models.CharField()
149
+ name = models.CharField()
150
+ language_id = models.BigIntegerField()
151
+ use_case_in_charting = models.CharField()
152
+ patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING, related_name="interviews")
153
+ note_id = models.BigIntegerField()
154
+ appointment_id = models.BigIntegerField()
155
+ questionnaires = models.ManyToManyField(Questionnaire, through="InterviewQuestionnaireMap")
156
+ progress_status = models.CharField()
157
+ created = models.DateTimeField()
158
+ modified = models.DateTimeField()
159
+
160
+
161
+ class InterviewQuestionnaireMap(models.Model):
162
+ """InterviewQuestionnaireMap."""
163
+
164
+ class Meta:
165
+ managed = False
166
+ app_label = "canvas_sdk"
167
+ db_table = "canvas_sdk_data_api_interviewquestionnairemap_001"
168
+
169
+ dbid = models.BigIntegerField(primary_key=True)
170
+ created = models.DateTimeField()
171
+ modified = models.DateTimeField()
172
+ status = models.CharField()
173
+ interview = models.ForeignKey(Interview, on_delete=models.DO_NOTHING)
174
+ questionnaire = models.ForeignKey(Questionnaire, on_delete=models.CASCADE)
175
+
176
+
177
+ class InterviewQuestionResponse(models.Model):
178
+ """InterviewQuestionResponse."""
179
+
180
+ class Meta:
181
+ managed = False
182
+ app_label = "canvas_sdk"
183
+ db_table = "canvas_sdk_data_api_interviewquestionresponse_001"
184
+
185
+ dbid = models.BigIntegerField(primary_key=True)
186
+ created = models.DateTimeField()
187
+ modified = models.DateTimeField()
188
+ status = models.CharField()
189
+ interview = models.ForeignKey(
190
+ Interview, on_delete=models.DO_NOTHING, related_name="interview_responses"
191
+ )
192
+ questionnaire = models.ForeignKey(
193
+ Questionnaire, on_delete=models.DO_NOTHING, related_name="interview_responses"
194
+ )
195
+ question = models.ForeignKey(
196
+ Question, on_delete=models.DO_NOTHING, related_name="interview_responses"
197
+ )
198
+ response_option = models.ForeignKey(
199
+ ResponseOption, on_delete=models.DO_NOTHING, related_name="interview_responses"
200
+ )
201
+ response_option_value = models.TextField()
202
+ questionnaire_state = models.TextField()
203
+ interview_state = models.TextField()
204
+ comment = models.CharField()
@@ -2,6 +2,8 @@ from django.db import models
2
2
 
3
3
 
4
4
  class CanvasUser(models.Model):
5
+ """A class representing a Canvas User."""
6
+
5
7
  class Meta:
6
8
  managed = False
7
9
  app_label = "canvas_sdk"
@@ -8101,7 +8101,7 @@ class KidneyFailure(ValueSet):
8101
8101
 
8102
8102
  class Proteinuria(ValueSet):
8103
8103
  """
8104
- **Clinical Focus:** The purpose of this value set is to represent concepts for a diagnosis of proteinuria
8104
+ **Clinical Focus:** The purpose of this value set is to represent concepts for a diagnosis of proteinuria.
8105
8105
 
8106
8106
  **Data Element Scope:** This value set may use a model element related to Diagnosis.
8107
8107
 
@@ -33137,7 +33137,7 @@ class StableAndUnstableAngina(ValueSet):
33137
33137
 
33138
33138
  class StatinAssociatedMuscleSymptoms(ValueSet):
33139
33139
  """
33140
- **Clinical Focus:**
33140
+ **Clinical Focus:** The purpose of this value set is to represent diagnoses of muscle-related symptoms associated with statin use.
33141
33141
 
33142
33142
  **Data Element Scope:**
33143
33143
 
@@ -1557,7 +1557,7 @@ class AudiologyVisit(ValueSet):
1557
1557
 
1558
1558
  class MedicalDisabilityExam(ValueSet):
1559
1559
  """
1560
- **Clinical Focus:** The purpose of this value set is to represent concepts for encounters for work related or medical disability examinations
1560
+ **Clinical Focus:** The purpose of this value set is to represent concepts for encounters for work related or medical disability examinations.
1561
1561
 
1562
1562
  **Data Element Scope:** This value set may use a model element related to Encounter.
1563
1563
 
@@ -1,8 +1,10 @@
1
1
  from collections import defaultdict
2
- from typing import Dict, Union
2
+ from typing import Dict, Union, cast
3
3
 
4
4
 
5
5
  class CodeConstants:
6
+ """A class representing different code systems and their URLs."""
7
+
6
8
  CPT = "CPT"
7
9
  HCPCSLEVELII = "HCPCSLEVELII"
8
10
  CVX = "CVX"
@@ -32,6 +34,8 @@ class CodeConstants:
32
34
 
33
35
 
34
36
  class CodeConstantsURLMapping:
37
+ """A class that maps code systems to their URLs."""
38
+
35
39
  CODE_SYSTEM_MAPPING = {
36
40
  CodeConstants.CPT: CodeConstants.URL_CPT,
37
41
  CodeConstants.HCPCSLEVELII: CodeConstants.URL_HCPCSLEVELII,
@@ -50,6 +54,8 @@ class CodeConstantsURLMapping:
50
54
 
51
55
 
52
56
  class CombinedValueSet(CodeConstantsURLMapping):
57
+ """A class representing a combination of two value sets."""
58
+
53
59
  def __init__(
54
60
  self,
55
61
  value_set_1: Union["ValueSet", "CombinedValueSet"],
@@ -59,7 +65,8 @@ class CombinedValueSet(CodeConstantsURLMapping):
59
65
  self.value_set_2 = value_set_2
60
66
 
61
67
  @property
62
- def values(self):
68
+ def values(self) -> Dict[str, set]:
69
+ """A property that returns the combined values from both value sets."""
63
70
  values: Dict[str, set] = defaultdict(set)
64
71
 
65
72
  for vs in [self.value_set_1, self.value_set_2]:
@@ -71,21 +78,29 @@ class CombinedValueSet(CodeConstantsURLMapping):
71
78
  return values
72
79
 
73
80
  def __or__(self, value_set: Union["ValueSet", "CombinedValueSet"]) -> "CombinedValueSet":
81
+ """Implements the `|` (or) operator to combine value sets."""
74
82
  return CombinedValueSet(self, value_set)
75
83
 
76
84
 
77
85
  class ValueSystems(type):
86
+ """A metaclass for defining a ValueSet."""
87
+
78
88
  @property
79
89
  def values(cls) -> dict[str, set]:
90
+ """A property that returns a dictionary of code systems and their associated values."""
80
91
  return {
81
92
  system: getattr(cls, system)
82
- for system in cls.CODE_SYSTEM_MAPPING.keys()
93
+ for system in cast(ValueSet, cls).CODE_SYSTEM_MAPPING.keys()
83
94
  if hasattr(cls, system)
84
95
  }
85
96
 
86
- def __or__(self, value_set: Union["ValueSet", "CombinedValueSet"]) -> CombinedValueSet:
87
- return CombinedValueSet(self, value_set)
97
+ def __or__(self, value_set: Union["ValueSet", "CombinedValueSet"]) -> CombinedValueSet: # type: ignore[override]
98
+ """Implements the `|` (or) operator."""
99
+ return CombinedValueSet(cast(ValueSet, self), value_set)
88
100
 
89
101
 
90
102
  class ValueSet(CodeConstantsURLMapping, metaclass=ValueSystems):
103
+ """The Base class for a ValueSet."""
104
+
105
+ values: dict[str, set]
91
106
  pass
logger/__init__.py CHANGED
@@ -1,2 +1,3 @@
1
1
  from logger.logger import PluginLogger
2
+
2
3
  log = PluginLogger()
logger/logger.py CHANGED
@@ -1,20 +1,26 @@
1
1
  import logging
2
2
  import os
3
+ from typing import Any
3
4
 
4
5
  from pubsub.pubsub import Publisher
5
6
 
6
7
 
7
8
  class PubSubLogHandler(logging.Handler):
9
+ """Custom logging handler that publishes logs to a pub/sub channel."""
10
+
8
11
  def __init__(self) -> None:
9
12
  self.publisher = Publisher()
10
13
  logging.Handler.__init__(self=self)
11
14
 
12
- def emit(self, record) -> None:
15
+ def emit(self, record: Any) -> None:
16
+ """Publishes the log message to the pub/sub channel."""
13
17
  message = self.format(record)
14
18
  self.publisher.publish(message)
15
19
 
16
20
 
17
21
  class PluginLogger:
22
+ """A custom logger for plugins."""
23
+
18
24
  def __init__(self) -> None:
19
25
  self.logger = logging.getLogger("plugin_runner_logger")
20
26
  self.logger.setLevel(logging.INFO)
@@ -32,17 +38,22 @@ class PluginLogger:
32
38
  pubsub_handler.setFormatter(formatter)
33
39
  self.logger.addHandler(pubsub_handler)
34
40
 
35
- def debug(self, message) -> None:
41
+ def debug(self, message: Any) -> None:
42
+ """Logs a debug message."""
36
43
  self.logger.debug(message)
37
44
 
38
- def info(self, message) -> None:
45
+ def info(self, message: Any) -> None:
46
+ """Logs an info message."""
39
47
  self.logger.info(message)
40
48
 
41
- def warning(self, message) -> None:
49
+ def warning(self, message: Any) -> None:
50
+ """Logs a warning message."""
42
51
  self.logger.warning(message)
43
52
 
44
- def error(self, message) -> None:
53
+ def error(self, message: Any) -> None:
54
+ """Logs an error message."""
45
55
  self.logger.error(message)
46
56
 
47
- def critical(self, message) -> None:
57
+ def critical(self, message: Any) -> None:
58
+ """Logs a critical message."""
48
59
  self.logger.critical(message)
settings.py ADDED
@@ -0,0 +1,43 @@
1
+ import os
2
+
3
+ from dotenv import load_dotenv
4
+
5
+ from canvas_sdk.utils.db import get_database_dict_from_url
6
+
7
+ load_dotenv()
8
+
9
+ INTEGRATION_TEST_URL = os.getenv("INTEGRATION_TEST_URL")
10
+ INTEGRATION_TEST_CLIENT_ID = os.getenv("INTEGRATION_TEST_CLIENT_ID")
11
+ INTEGRATION_TEST_CLIENT_SECRET = os.getenv("INTEGRATION_TEST_CLIENT_SECRET")
12
+
13
+ GRAPHQL_ENDPOINT = os.getenv("GRAPHQL_ENDPOINT", "http://localhost:8000/plugins-graphql")
14
+
15
+ INSTALLED_APPS = ["canvas_sdk"]
16
+
17
+ SECRET_KEY = os.getenv(
18
+ "SECRET_KEY",
19
+ "This value is the key to securing signed data – it is vital you keep this secure, or attackers could use it to generate their own signed values.",
20
+ )
21
+
22
+ # Use BigAutoField for Default Primary Key field type
23
+ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
24
+
25
+ CANVAS_SDK_DB_NAME = os.getenv("CANVAS_SDK_DB_NAME", "home-app")
26
+ CANVAS_SDK_DB_USERNAME = os.getenv("CANVAS_SDK_DB_USERNAME", "app")
27
+ CANVAS_SDK_DB_PASSWORD = os.getenv("CANVAS_SDK_DB_PASSWORD", "app")
28
+ CANVAS_SDK_DB_HOST = os.getenv("CANVAS_SDK_DB_HOST", "home-app-db")
29
+ CANVAS_SDK_DB_PORT = os.getenv("CANVAS_SDK_DB_PORT", "5432")
30
+
31
+ if os.getenv("DATABASE_URL"):
32
+ database_dict = get_database_dict_from_url()
33
+ else:
34
+ database_dict = {
35
+ "ENGINE": "django.db.backends.postgresql",
36
+ "NAME": CANVAS_SDK_DB_NAME,
37
+ "USER": CANVAS_SDK_DB_USERNAME,
38
+ "PASSWORD": CANVAS_SDK_DB_PASSWORD,
39
+ "HOST": CANVAS_SDK_DB_HOST,
40
+ "PORT": CANVAS_SDK_DB_PORT,
41
+ }
42
+
43
+ DATABASES = {"default": database_dict}