canvas 0.14.0__py3-none-any.whl → 0.15.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 (68) hide show
  1. {canvas-0.14.0.dist-info → canvas-0.15.0.dist-info}/METADATA +1 -1
  2. {canvas-0.14.0.dist-info → canvas-0.15.0.dist-info}/RECORD +67 -46
  3. canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/my_protocol.py +1 -1
  4. canvas_generated/messages/effects_pb2.py +2 -2
  5. canvas_generated/messages/effects_pb2.pyi +4 -0
  6. canvas_generated/messages/events_pb2.py +2 -2
  7. canvas_generated/messages/events_pb2.pyi +8 -0
  8. canvas_sdk/commands/tests/protocol/tests.py +3 -1
  9. canvas_sdk/commands/tests/test_utils.py +76 -18
  10. canvas_sdk/effects/banner_alert/tests.py +41 -20
  11. canvas_sdk/events/base.py +1 -3
  12. canvas_sdk/handlers/action_button.py +5 -2
  13. canvas_sdk/handlers/application.py +1 -1
  14. canvas_sdk/handlers/cron_task.py +1 -1
  15. canvas_sdk/protocols/clinical_quality_measure.py +1 -1
  16. canvas_sdk/v1/apps.py +7 -0
  17. canvas_sdk/v1/data/__init__.py +75 -4
  18. canvas_sdk/v1/data/allergy_intolerance.py +3 -7
  19. canvas_sdk/v1/data/billing.py +2 -5
  20. canvas_sdk/v1/data/command.py +7 -9
  21. canvas_sdk/v1/data/condition.py +3 -7
  22. canvas_sdk/v1/data/detected_issue.py +4 -9
  23. canvas_sdk/v1/data/device.py +4 -8
  24. canvas_sdk/v1/data/imaging.py +12 -17
  25. canvas_sdk/v1/data/lab.py +16 -29
  26. canvas_sdk/v1/data/medication.py +3 -7
  27. canvas_sdk/v1/data/note.py +7 -14
  28. canvas_sdk/v1/data/observation.py +4 -11
  29. canvas_sdk/v1/data/organization.py +1 -2
  30. canvas_sdk/v1/data/patient.py +0 -1
  31. canvas_sdk/v1/data/practicelocation.py +2 -4
  32. canvas_sdk/v1/data/protocol_override.py +3 -6
  33. canvas_sdk/v1/data/questionnaire.py +5 -15
  34. canvas_sdk/v1/data/staff.py +5 -7
  35. canvas_sdk/v1/data/task.py +5 -11
  36. canvas_sdk/v1/data/user.py +0 -1
  37. canvas_sdk/v1/models.py +4 -0
  38. plugin_runner/plugin_installer.py +1 -1
  39. plugin_runner/plugin_runner.py +5 -25
  40. plugin_runner/sandbox.py +105 -9
  41. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/CANVAS_MANIFEST.json +38 -0
  42. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/README.md +11 -0
  43. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/__init__.py +0 -0
  44. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/my_protocol.py +33 -0
  45. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/__init__.py +3 -0
  46. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/base.py +6 -0
  47. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/__init__.py +5 -0
  48. plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/base.py +4 -0
  49. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/CANVAS_MANIFEST.json +29 -0
  50. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/README.md +12 -0
  51. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/__init__.py +0 -0
  52. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/base.py +10 -0
  53. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/__init__.py +0 -0
  54. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/my_protocol.py +18 -0
  55. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/CANVAS_MANIFEST.json +29 -0
  56. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/README.md +12 -0
  57. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/__init__.py +0 -0
  58. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/base.py +10 -0
  59. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/__init__.py +0 -0
  60. plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/my_protocol.py +18 -0
  61. plugin_runner/tests/test_application.py +9 -9
  62. plugin_runner/tests/test_plugin_installer.py +12 -1
  63. plugin_runner/tests/test_plugin_runner.py +171 -32
  64. plugin_runner/tests/test_sandbox.py +5 -13
  65. settings.py +3 -1
  66. canvas_sdk/models/__init__.py +0 -8
  67. {canvas-0.14.0.dist-info → canvas-0.15.0.dist-info}/WHEEL +0 -0
  68. {canvas-0.14.0.dist-info → canvas-0.15.0.dist-info}/entry_points.txt +0 -0
@@ -1,14 +1,17 @@
1
1
  import random
2
2
  import shutil
3
3
  import string
4
+ import threading
4
5
  from contextlib import chdir
5
6
  from datetime import datetime
6
7
  from decimal import Decimal
7
8
  from pathlib import Path
8
9
  from typing import Any, cast
10
+ from urllib.parse import urlparse
9
11
 
10
12
  import pytest
11
13
  import requests
14
+ import websocket
12
15
  from pydantic import ValidationError
13
16
  from typer.testing import CliRunner
14
17
 
@@ -187,17 +190,25 @@ class Protocol(BaseProtocol):
187
190
  def install_plugin(plugin_name: str, token: MaskedValue) -> None:
188
191
  """Install a plugin."""
189
192
  with open(_build_package(Path(f"./custom-plugins/{plugin_name}")), "rb") as package:
190
- requests.post(
193
+ message_received_event = wait_for_log(
194
+ cast(str, settings.INTEGRATION_TEST_URL),
195
+ token.value,
196
+ f"Loading plugin '{plugin_name}",
197
+ )
198
+ response = requests.post(
191
199
  plugin_url(cast(str, settings.INTEGRATION_TEST_URL)),
192
200
  data={"is_enabled": True},
193
201
  files={"package": package},
194
202
  headers={"Authorization": f"Bearer {token.value}"},
195
203
  )
204
+ response.raise_for_status()
205
+
206
+ message_received_event.wait(timeout=5.0)
196
207
 
197
208
 
198
209
  def trigger_plugin_event(token: MaskedValue) -> None:
199
210
  """Trigger a plugin event."""
200
- requests.post(
211
+ response = requests.post(
201
212
  f"{settings.INTEGRATION_TEST_URL}/api/Note/",
202
213
  headers={
203
214
  "Authorization": f"Bearer {token.value}",
@@ -212,18 +223,22 @@ def trigger_plugin_event(token: MaskedValue) -> None:
212
223
  "lastModifiedBySessionKey": "8fee3c03a525cebee1d8a6b8e63dd4dg",
213
224
  },
214
225
  )
226
+ response.raise_for_status()
215
227
 
216
228
 
217
229
  def get_original_note_body_commands(new_note_id: int, token: MaskedValue) -> list[str]:
218
230
  """Get the commands from the original note body."""
219
- original_note = requests.get(
231
+ response = requests.get(
220
232
  f"{settings.INTEGRATION_TEST_URL}/api/Note/{new_note_id}",
221
233
  headers={
222
234
  "Authorization": f"Bearer {token.value}",
223
235
  "Content-Type": "application/json",
224
236
  "Accept": "application/json",
225
237
  },
226
- ).json()
238
+ )
239
+ response.raise_for_status()
240
+
241
+ original_note = response.json()
227
242
 
228
243
  body = original_note["body"]
229
244
  return [
@@ -243,18 +258,21 @@ def clean_up_files_and_plugins(plugin_name: str, token: MaskedValue) -> None:
243
258
  shutil.rmtree(Path(f"./custom-plugins/{plugin_name}"))
244
259
 
245
260
  # disable
246
- requests.patch(
261
+ response = requests.patch(
247
262
  plugin_url(cast(str, settings.INTEGRATION_TEST_URL), plugin_name),
248
263
  data={"is_enabled": False},
249
264
  headers={
250
265
  "Authorization": f"Bearer {token.value}",
251
266
  },
252
267
  )
268
+ response.raise_for_status()
269
+
253
270
  # delete
254
- requests.delete(
271
+ response = requests.delete(
255
272
  plugin_url(cast(str, settings.INTEGRATION_TEST_URL), plugin_name),
256
273
  headers={"Authorization": f"Bearer {token.value}"},
257
274
  )
275
+ response.raise_for_status()
258
276
 
259
277
 
260
278
  # For reuse with the protocol code
@@ -287,21 +305,61 @@ def create_new_note(token: MaskedValue) -> dict:
287
305
  "note_type_version": 1,
288
306
  "lastModifiedBySessionKey": "8fee3c03a525cebee1d8a6b8e63dd4dg",
289
307
  }
290
- return requests.post(
308
+ response = requests.post(
291
309
  f"{settings.INTEGRATION_TEST_URL}/api/Note/", headers=headers, json=data
292
- ).json()
310
+ )
311
+ response.raise_for_status()
312
+ return response.json()
293
313
 
294
314
 
295
315
  def get_token() -> MaskedValue:
296
316
  """Get a valid token."""
297
- return MaskedValue(
298
- requests.post(
299
- f"{settings.INTEGRATION_TEST_URL}/auth/token/",
300
- headers={"Content-Type": "application/x-www-form-urlencoded"},
301
- data={
302
- "grant_type": "client_credentials",
303
- "client_id": settings.INTEGRATION_TEST_CLIENT_ID,
304
- "client_secret": settings.INTEGRATION_TEST_CLIENT_SECRET,
305
- },
306
- ).json()["access_token"]
317
+ response = requests.post(
318
+ f"{settings.INTEGRATION_TEST_URL}/auth/token/",
319
+ headers={"Content-Type": "application/x-www-form-urlencoded"},
320
+ data={
321
+ "grant_type": "client_credentials",
322
+ "client_id": settings.INTEGRATION_TEST_CLIENT_ID,
323
+ "client_secret": settings.INTEGRATION_TEST_CLIENT_SECRET,
324
+ },
307
325
  )
326
+ response.raise_for_status()
327
+
328
+ return MaskedValue(response.json()["access_token"])
329
+
330
+
331
+ def wait_for_log(host: str, token: str, message: str) -> threading.Event:
332
+ """Wait for a specific log message."""
333
+ hostname = cast(str, urlparse(host).hostname)
334
+ instance = hostname.removesuffix(".canvasmedical.com")
335
+
336
+ websocket_uri = f"wss://logs.console.canvasmedical.com/{instance}?token={token}"
337
+
338
+ connected_event = threading.Event()
339
+ message_received_event = threading.Event()
340
+
341
+ def _on_message(ws: websocket.WebSocket, received_message: str) -> None:
342
+ try:
343
+ if "Log stream connected" in received_message:
344
+ connected_event.set()
345
+ if message.lower() in received_message.lower():
346
+ message_received_event.set()
347
+ ws.close()
348
+ except Exception as ex:
349
+ print(f"Error processing message: {ex}")
350
+
351
+ def _on_error(ws: websocket.WebSocket, error: str) -> None:
352
+ print(f"WebSocket error: {error}")
353
+
354
+ ws = websocket.WebSocketApp(
355
+ websocket_uri,
356
+ on_message=_on_message,
357
+ on_error=_on_error,
358
+ )
359
+
360
+ thread = threading.Thread(target=ws.run_forever)
361
+ thread.start()
362
+
363
+ connected_event.wait(timeout=5.0)
364
+
365
+ return message_received_event
@@ -14,7 +14,7 @@ from typer.testing import CliRunner
14
14
  import settings
15
15
  from canvas_cli.apps.plugin.plugin import _build_package, plugin_url
16
16
  from canvas_cli.main import app
17
- from canvas_sdk.commands.tests.test_utils import MaskedValue
17
+ from canvas_sdk.commands.tests.test_utils import MaskedValue, wait_for_log
18
18
  from canvas_sdk.effects.banner_alert import AddBannerAlert, RemoveBannerAlert
19
19
 
20
20
  runner = CliRunner()
@@ -23,17 +23,18 @@ runner = CliRunner()
23
23
  @pytest.fixture(scope="session")
24
24
  def token() -> MaskedValue:
25
25
  """Get a valid token."""
26
- return MaskedValue(
27
- requests.post(
28
- f"{settings.INTEGRATION_TEST_URL}/auth/token/",
29
- headers={"Content-Type": "application/x-www-form-urlencoded"},
30
- data={
31
- "grant_type": "client_credentials",
32
- "client_id": settings.INTEGRATION_TEST_CLIENT_ID,
33
- "client_secret": settings.INTEGRATION_TEST_CLIENT_SECRET,
34
- },
35
- ).json()["access_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
+ },
36
34
  )
35
+ response.raise_for_status()
36
+
37
+ return MaskedValue(response.json()["access_token"])
37
38
 
38
39
 
39
40
  @pytest.fixture(scope="session")
@@ -44,7 +45,9 @@ def first_patient_id(token: MaskedValue) -> dict:
44
45
  "Content-Type": "application/json",
45
46
  "Accept": "application/json",
46
47
  }
47
- patients = requests.get(f"{settings.INTEGRATION_TEST_URL}/api/Patient", headers=headers).json()
48
+ response = requests.get(f"{settings.INTEGRATION_TEST_URL}/api/Patient", headers=headers)
49
+ response.raise_for_status()
50
+ patients = response.json()
48
51
  return patients["entry"][0]["resource"]["key"]
49
52
 
50
53
 
@@ -89,13 +92,22 @@ class Protocol(BaseProtocol):
89
92
  protocol.write(protocol_code)
90
93
 
91
94
  with open(_build_package(Path(f"./custom-plugins/{plugin_name}")), "rb") as package:
95
+ message_received_event = wait_for_log(
96
+ settings.INTEGRATION_TEST_URL,
97
+ token.value,
98
+ f"Loading plugin '{plugin_name}:{plugin_name}.protocols.my_protocol:Protocol'",
99
+ )
100
+
92
101
  # install the plugin
93
- requests.post(
102
+ response = requests.post(
94
103
  plugin_url(settings.INTEGRATION_TEST_URL),
95
104
  data={"is_enabled": True},
96
105
  files={"package": package},
97
106
  headers={"Authorization": f"Bearer {token.value}"},
98
107
  )
108
+ response.raise_for_status()
109
+
110
+ message_received_event.wait(timeout=5.0)
99
111
 
100
112
  yield
101
113
 
@@ -104,26 +116,31 @@ class Protocol(BaseProtocol):
104
116
  shutil.rmtree(Path(f"./custom-plugins/{plugin_name}"))
105
117
 
106
118
  # disable
107
- requests.patch(
119
+ response = requests.patch(
108
120
  plugin_url(settings.INTEGRATION_TEST_URL, plugin_name),
109
121
  data={"is_enabled": False},
110
122
  headers={
111
123
  "Authorization": f"Bearer {token.value}",
112
124
  },
113
125
  )
126
+ response.raise_for_status()
127
+
114
128
  # delete
115
- requests.delete(
129
+ response = requests.delete(
116
130
  plugin_url(settings.INTEGRATION_TEST_URL, plugin_name),
117
131
  headers={"Authorization": f"Bearer {token.value}"},
118
132
  )
133
+ response.raise_for_status()
119
134
 
120
135
  # confirm no more banner
121
- patient_banners_none = requests.get(
136
+ response = requests.get(
122
137
  f"{settings.INTEGRATION_TEST_URL}/api/BannerAlert/?patient__key={first_patient_id}",
123
138
  headers={
124
139
  "Authorization": f"Bearer {token.value}",
125
140
  },
126
- ).json()
141
+ )
142
+ response.raise_for_status()
143
+ patient_banners_none = response.json()
127
144
  patient_banner = next(
128
145
  (b for b in patient_banners_none["results"] if b["key"] == plugin_name), None
129
146
  )
@@ -139,7 +156,7 @@ def test_protocol_that_adds_banner_alert(
139
156
  ) -> None:
140
157
  """Test that the protocol adds a banner alert."""
141
158
  # trigger the event
142
- requests.post(
159
+ response = requests.post(
143
160
  f"{settings.INTEGRATION_TEST_URL}/api/Note/",
144
161
  headers={
145
162
  "Authorization": f"Bearer {token.value}",
@@ -154,13 +171,17 @@ def test_protocol_that_adds_banner_alert(
154
171
  "lastModifiedBySessionKey": "8fee3c03a525cebee1d8a6b8e63dd4dg",
155
172
  },
156
173
  )
174
+ response.raise_for_status()
157
175
 
158
- patient_banners = requests.get(
176
+ response = requests.get(
159
177
  f"{settings.INTEGRATION_TEST_URL}/api/BannerAlert/?patient__key={first_patient_id}",
160
178
  headers={
161
179
  "Authorization": f"Bearer {token.value}",
162
180
  },
163
- ).json()
181
+ )
182
+ response.raise_for_status()
183
+
184
+ patient_banners = response.json()
164
185
  assert patient_banners["count"] > 0
165
186
 
166
187
  patient_banner = next(b for b in patient_banners["results"] if b["key"] == plugin_name)
canvas_sdk/events/base.py CHANGED
@@ -33,9 +33,7 @@ class Event:
33
33
 
34
34
  def __init__(self, event_request: EventRequest) -> None:
35
35
  try:
36
- target_model = apps.get_model(
37
- app_label="canvas_sdk", model_name=event_request.target_type
38
- )
36
+ target_model = apps.get_model(app_label="v1", model_name=event_request.target_type)
39
37
  except LookupError:
40
38
  target_model = None
41
39
 
@@ -42,13 +42,16 @@ class ActionButton(BaseHandler):
42
42
  EventType.SHOW_NOTE_HEADER_BUTTON,
43
43
  EventType.SHOW_NOTE_FOOTER_BUTTON,
44
44
  ):
45
- if self.context["location"].lower() == self.BUTTON_LOCATION.value and self.visible():
45
+ if (
46
+ self.event.context["location"].lower() == self.BUTTON_LOCATION.value
47
+ and self.visible()
48
+ ):
46
49
  return [ShowButtonEffect(key=self.BUTTON_KEY, title=self.BUTTON_TITLE).apply()]
47
50
  else:
48
51
  return []
49
52
  elif (
50
53
  self.event.type == EventType.ACTION_BUTTON_CLICKED
51
- and self.context["key"] == self.BUTTON_KEY
54
+ and self.event.context["key"] == self.BUTTON_KEY
52
55
  ):
53
56
  return self.handle()
54
57
 
@@ -14,7 +14,7 @@ class Application(BaseHandler, ABC):
14
14
  """Handle the application events."""
15
15
  match self.event.type:
16
16
  case EventType.APPLICATION__ON_OPEN:
17
- return [self.on_open()] if self.target == self.identifier else []
17
+ return [self.on_open()] if self.event.target.id == self.identifier else []
18
18
  case _:
19
19
  return []
20
20
 
@@ -29,7 +29,7 @@ class CronTask(BaseHandler):
29
29
  """
30
30
  if not self.SCHEDULE:
31
31
  raise ValueError("You must set a SCHEDULE.")
32
- datetime = arrow.get(self.target).datetime
32
+ datetime = arrow.get(self.event.target.id).datetime
33
33
  if datetime in Cron(self.SCHEDULE):
34
34
  return self.execute()
35
35
  return []
@@ -94,7 +94,7 @@ class ClinicalQualityMeasure(BaseProtocol):
94
94
 
95
95
  def patient_id(model: "type[Model]") -> str:
96
96
  if model == Patient:
97
- return self.target
97
+ return self.event.target.id
98
98
  else:
99
99
  return cast(
100
100
  str,
canvas_sdk/v1/apps.py ADDED
@@ -0,0 +1,7 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class CanvasSdkV1Config(AppConfig):
5
+ """AppConfig for v1 of the SDK data module."""
6
+
7
+ name = "canvas_sdk.v1"
@@ -1,23 +1,94 @@
1
+ from .allergy_intolerance import AllergyIntolerance, AllergyIntoleranceCoding
1
2
  from .billing import BillingLineItem
3
+ from .command import Command
2
4
  from .condition import Condition, ConditionCoding
5
+ from .detected_issue import DetectedIssue, DetectedIssueEvidence
6
+ from .device import Device
7
+ from .imaging import ImagingOrder, ImagingReport, ImagingReview
8
+ from .lab import (
9
+ LabOrder,
10
+ LabOrderReason,
11
+ LabOrderReasonCondition,
12
+ LabReport,
13
+ LabReview,
14
+ LabTest,
15
+ LabValue,
16
+ LabValueCoding,
17
+ )
3
18
  from .medication import Medication, MedicationCoding
19
+ from .note import Note, NoteType
20
+ from .observation import (
21
+ Observation,
22
+ ObservationCoding,
23
+ ObservationComponent,
24
+ ObservationComponentCoding,
25
+ ObservationValueCoding,
26
+ )
4
27
  from .organization import Organization
5
28
  from .patient import Patient
6
- from .practicelocation import PracticeLocation
29
+ from .practicelocation import PracticeLocation, PracticeLocationSetting
30
+ from .protocol_override import ProtocolOverride
31
+ from .questionnaire import (
32
+ Interview,
33
+ InterviewQuestionnaireMap,
34
+ InterviewQuestionResponse,
35
+ Question,
36
+ Questionnaire,
37
+ QuestionnaireQuestionMap,
38
+ ResponseOption,
39
+ ResponseOptionSet,
40
+ )
7
41
  from .staff import Staff
8
- from .task import Task, TaskComment, TaskLabel
42
+ from .task import Task, TaskComment, TaskLabel, TaskTaskLabel
43
+ from .user import CanvasUser
9
44
 
10
- __all__ = (
45
+ __all__ = [
46
+ "AllergyIntolerance",
47
+ "AllergyIntoleranceCoding",
11
48
  "BillingLineItem",
49
+ "CanvasUser",
50
+ "Command",
12
51
  "Condition",
13
52
  "ConditionCoding",
53
+ "DetectedIssue",
54
+ "DetectedIssueEvidence",
55
+ "Device",
56
+ "ImagingOrder",
57
+ "ImagingReport",
58
+ "ImagingReview",
59
+ "Interview",
60
+ "InterviewQuestionnaireMap",
61
+ "InterviewQuestionResponse",
62
+ "LabOrder",
63
+ "LabOrderReason",
64
+ "LabOrderReasonCondition",
65
+ "LabReport",
66
+ "LabReview",
67
+ "LabTest",
68
+ "LabValue",
69
+ "LabValueCoding",
14
70
  "Medication",
15
71
  "MedicationCoding",
72
+ "Note",
73
+ "NoteType",
74
+ "Observation",
75
+ "ObservationCoding",
76
+ "ObservationComponent",
77
+ "ObservationComponentCoding",
78
+ "ObservationValueCoding",
16
79
  "Organization",
17
80
  "Patient",
18
81
  "PracticeLocation",
82
+ "PracticeLocationSetting",
83
+ "ProtocolOverride",
84
+ "Question",
85
+ "Questionnaire",
86
+ "QuestionnaireQuestionMap",
87
+ "ResponseOption",
88
+ "ResponseOptionSet",
19
89
  "Staff",
20
90
  "Task",
21
91
  "TaskComment",
22
92
  "TaskLabel",
23
- )
93
+ "TaskTaskLabel",
94
+ ]
@@ -1,8 +1,6 @@
1
1
  from django.db import models
2
2
 
3
3
  from canvas_sdk.v1.data.base import CommittableModelManager, ValueSetLookupQuerySet
4
- from canvas_sdk.v1.data.patient import Patient
5
- from canvas_sdk.v1.data.user import CanvasUser
6
4
 
7
5
 
8
6
  class AllergyIntolerance(models.Model):
@@ -10,7 +8,6 @@ class AllergyIntolerance(models.Model):
10
8
 
11
9
  class Meta:
12
10
  managed = False
13
- app_label = "canvas_sdk"
14
11
  db_table = "canvas_sdk_data_api_allergyintolerance_001"
15
12
 
16
13
  objects = CommittableModelManager().from_queryset(ValueSetLookupQuerySet)()
@@ -20,10 +17,10 @@ class AllergyIntolerance(models.Model):
20
17
  created = models.DateTimeField()
21
18
  modified = models.DateTimeField()
22
19
  deleted = models.BooleanField()
23
- committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
24
- entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
20
+ committer = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
21
+ entered_in_error = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
25
22
  patient = models.ForeignKey(
26
- Patient,
23
+ "v1.Patient",
27
24
  on_delete=models.DO_NOTHING,
28
25
  related_name="allergy_intolerances",
29
26
  null=True,
@@ -46,7 +43,6 @@ class AllergyIntoleranceCoding(models.Model):
46
43
 
47
44
  class Meta:
48
45
  managed = False
49
- app_label = "canvas_sdk"
50
46
  db_table = "canvas_sdk_data_api_allergyintolerancecoding_001"
51
47
 
52
48
  dbid = models.BigIntegerField(primary_key=True)
@@ -3,8 +3,6 @@ from typing import TYPE_CHECKING
3
3
  from django.db import models
4
4
 
5
5
  from canvas_sdk.v1.data.base import ValueSetTimeframeLookupQuerySet
6
- from canvas_sdk.v1.data.note import Note
7
- from canvas_sdk.v1.data.patient import Patient
8
6
  from canvas_sdk.value_set.value_set import CodeConstants
9
7
 
10
8
  if TYPE_CHECKING:
@@ -36,7 +34,6 @@ class BillingLineItem(models.Model):
36
34
 
37
35
  class Meta:
38
36
  managed = False
39
- app_label = "canvas_sdk"
40
37
  db_table = "canvas_sdk_data_api_billinglineitem_001"
41
38
 
42
39
  # objects = BillingLineItemQuerySet.as_manager()
@@ -47,10 +44,10 @@ class BillingLineItem(models.Model):
47
44
  created = models.DateTimeField()
48
45
  modified = models.DateTimeField()
49
46
  note = models.ForeignKey(
50
- Note, on_delete=models.DO_NOTHING, related_name="billing_line_items", null=True
47
+ "v1.Note", on_delete=models.DO_NOTHING, related_name="billing_line_items", null=True
51
48
  )
52
49
  patient = models.ForeignKey(
53
- Patient, on_delete=models.DO_NOTHING, related_name="billing_line_items", null=True
50
+ "v1.Patient", on_delete=models.DO_NOTHING, related_name="billing_line_items", null=True
54
51
  )
55
52
  cpt = models.CharField()
56
53
  charge = models.DecimalField()
@@ -1,27 +1,23 @@
1
1
  from django.apps import apps
2
2
  from django.db import models
3
3
 
4
- from canvas_sdk.v1.data.patient import Patient
5
- from canvas_sdk.v1.data.user import CanvasUser
6
-
7
4
 
8
5
  class Command(models.Model):
9
6
  """Command."""
10
7
 
11
8
  class Meta:
12
9
  managed = False
13
- app_label = "canvas_sdk"
14
10
  db_table = "canvas_sdk_data_commands_command_001"
15
11
 
16
12
  id = models.UUIDField()
17
13
  dbid = models.BigIntegerField(primary_key=True)
18
14
  created = models.DateTimeField()
19
15
  modified = models.DateTimeField()
20
- originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
21
- committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
22
- entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
16
+ originator = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
17
+ committer = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
18
+ entered_in_error = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
23
19
  state = models.CharField()
24
- patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING, null=True)
20
+ patient = models.ForeignKey("v1.Patient", on_delete=models.DO_NOTHING, null=True)
25
21
  note_id = models.BigIntegerField()
26
22
  schema_key = models.TextField()
27
23
  data = models.JSONField()
@@ -36,5 +32,7 @@ class Command(models.Model):
36
32
  """
37
33
  # TODO: Is the anchor object type enough here, or do we need a mapping? The home-app model
38
34
  # names might not exactly match the plugins model names.
39
- anchor_model = apps.get_model(app_label="canvas_sdk", model_name=self.anchor_object_type)
35
+ anchor_model = apps.get_model(
36
+ app_label=self._meta.app_label, model_name=self.anchor_object_type
37
+ )
40
38
  return anchor_model.objects.get(dbid=self.anchor_object_dbid)
@@ -2,8 +2,6 @@ from django.db import models
2
2
  from django.db.models import TextChoices
3
3
 
4
4
  from canvas_sdk.v1.data.base import ValueSetLookupQuerySet
5
- from canvas_sdk.v1.data.patient import Patient
6
- from canvas_sdk.v1.data.user import CanvasUser
7
5
 
8
6
 
9
7
  class ClinicalStatus(TextChoices):
@@ -27,7 +25,6 @@ class Condition(models.Model):
27
25
 
28
26
  class Meta:
29
27
  managed = False
30
- app_label = "canvas_sdk"
31
28
  db_table = "canvas_sdk_data_api_condition_001"
32
29
 
33
30
  objects = ConditionQuerySet.as_manager()
@@ -35,10 +32,10 @@ class Condition(models.Model):
35
32
  id = models.UUIDField()
36
33
  dbid = models.BigIntegerField(primary_key=True)
37
34
  deleted = models.BooleanField()
38
- entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
39
- committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
35
+ entered_in_error = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
36
+ committer = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
40
37
  patient = models.ForeignKey(
41
- Patient, on_delete=models.DO_NOTHING, related_name="conditions", null=True
38
+ "v1.Patient", on_delete=models.DO_NOTHING, related_name="conditions", null=True
42
39
  )
43
40
  onset_date = models.DateField()
44
41
  resolution_date = models.DateField()
@@ -50,7 +47,6 @@ class ConditionCoding(models.Model):
50
47
 
51
48
  class Meta:
52
49
  managed = False
53
- app_label = "canvas_sdk"
54
50
  db_table = "canvas_sdk_data_api_conditioncoding_001"
55
51
 
56
52
  dbid = models.BigIntegerField(primary_key=True)
@@ -1,15 +1,11 @@
1
1
  from django.db import models
2
2
 
3
- from canvas_sdk.v1.data import Patient
4
- from canvas_sdk.v1.data.user import CanvasUser
5
-
6
3
 
7
4
  class DetectedIssue(models.Model):
8
5
  """DetectedIssue."""
9
6
 
10
7
  class Meta:
11
8
  managed = False
12
- app_label = "canvas_sdk"
13
9
  db_table = "canvas_sdk_data_api_detectedissue_001"
14
10
 
15
11
  id = models.UUIDField()
@@ -18,11 +14,11 @@ class DetectedIssue(models.Model):
18
14
  modified = models.DateTimeField()
19
15
  identified = models.DateTimeField()
20
16
  deleted = models.BooleanField()
21
- originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
22
- committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
23
- entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
17
+ originator = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
18
+ committer = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
19
+ entered_in_error = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
24
20
  patient = models.ForeignKey(
25
- Patient, on_delete=models.DO_NOTHING, related_name="detected_issues", null=True
21
+ "v1.Patient", on_delete=models.DO_NOTHING, related_name="detected_issues", null=True
26
22
  )
27
23
  code = models.CharField()
28
24
  status = models.CharField()
@@ -38,7 +34,6 @@ class DetectedIssueEvidence(models.Model):
38
34
 
39
35
  class Meta:
40
36
  managed = False
41
- app_label = "canvas_sdk"
42
37
  db_table = "canvas_sdk_data_api_detectedissueevidence_001"
43
38
 
44
39
  dbid = models.BigIntegerField(primary_key=True)