canvas 0.44.3__py3-none-any.whl → 0.45.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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: canvas
3
- Version: 0.44.3
3
+ Version: 0.45.0
4
4
  Summary: SDK to customize event-driven actions in your Canvas instance
5
5
  Author-email: Canvas Team <engineering@canvasmedical.com>
6
6
  License-Expression: MIT
@@ -16,6 +16,7 @@ Requires-Dist: frozendict>=2.4.6
16
16
  Requires-Dist: grpcio<2,>=1.60.1
17
17
  Requires-Dist: ipython<9,>=8.21.0
18
18
  Requires-Dist: jsonschema<5,>=4.21.1
19
+ Requires-Dist: pathspec>=0.12.1
19
20
  Requires-Dist: protobuf<5,>=4.25.3
20
21
  Requires-Dist: psycopg[binary,pool]<4,>=3.2.2
21
22
  Requires-Dist: pydantic<3,>=2.6.1
@@ -68,7 +68,7 @@ canvas_cli/apps/emit/event_fixtures/VITAL_SIGN_UPDATED.ndjson,sha256=Er0aUWIYkqb
68
68
  canvas_cli/apps/logs/__init__.py,sha256=ehY9SRb6nBw81xZF50yyBlUZJtNR2VeVSNI5sFuWJ7o,64
69
69
  canvas_cli/apps/logs/logs.py,sha256=BFpZ-2OF2Rs1EMLePo5UjqC9fKQeqm8qZobNTFNCL_M,1972
70
70
  canvas_cli/apps/plugin/__init__.py,sha256=G_nLsu6cdko5OjatnbqUyEboGcNlGGLwpZmCBxMKdfo,236
71
- canvas_cli/apps/plugin/plugin.py,sha256=vDlk0IFUrukPUgOonBy2caznCzRscnjwhnUUWlVoVlw,15835
71
+ canvas_cli/apps/plugin/plugin.py,sha256=HWsl1wRu-FcNSiIzShTv16tFNORhQ4DqX9nSOh6Bheg,16462
72
72
  canvas_cli/apps/run_plugins/__init__.py,sha256=iAMgX_6D3CdjQodGx_azwhSjouaxquOm8Z8QVXnlTFE,117
73
73
  canvas_cli/apps/run_plugins/run_plugins.py,sha256=w4JTsXFiHckZahvbSOJAqZo3jWwedxlHLiXct1j_6cY,392
74
74
  canvas_cli/templates/plugins/application/cookiecutter.json,sha256=cI4Wpj68TkKeBP3P16PrjKacTHzsTIpl_rDdzyUpwz4,129
@@ -214,7 +214,7 @@ canvas_sdk/templates/__init__.py,sha256=LtUmLDsGSTq249T6sA7PUzkl2OfCAyvtIOGPNHr6
214
214
  canvas_sdk/templates/utils.py,sha256=_AIYcGQD3ePWzQpH7ZirkV_ATtIHlzf-T_03mHoeIWI,1460
215
215
  canvas_sdk/utils/__init__.py,sha256=PADveJMf-BtOapK5Cczy-nOuZzVh-HT2H6sfJW_SK9U,198
216
216
  canvas_sdk/utils/db.py,sha256=wOZORBfyBVxQkay5vyEtQ4i0KVCfASFGREmecHMR8DE,409
217
- canvas_sdk/utils/http.py,sha256=BkHmLdTP-m33W0Ufp_NkQU_L0uxbkJzzilk1JNbmYlA,10691
217
+ canvas_sdk/utils/http.py,sha256=BUpDcc8s_MVViiM9Y3FOAMZWW8bj2a8zIuQCl8bXt_s,10729
218
218
  canvas_sdk/utils/metrics.py,sha256=ojCbXgjLSy1pEavHgRs8j4OVNdAUMa1nLqZdkA0uCQQ,5987
219
219
  canvas_sdk/utils/plugins.py,sha256=xxJUeVJBzfQWhlD1kO7HlFWxDAl01kkvbsf07Z08dOM,1551
220
220
  canvas_sdk/v1/__init__.py,sha256=YYXr5tEQlnwMgTXJbOG963tKSPiUOM4mUkX8wuiqp7U,17
@@ -245,7 +245,7 @@ canvas_sdk/v1/data/lab.py,sha256=ifsMcVJd5Lq4Dz6SExclh-si8-uQEtRRH6zhb1p4HvI,130
245
245
  canvas_sdk/v1/data/line_item_transaction.py,sha256=JVZANCBFuZz777837S9ILVjHR31QrBbvQ3Lwc6GyuA0,2440
246
246
  canvas_sdk/v1/data/medication.py,sha256=5mTbqozFo0EdGALXeV1aAywzVFn_J6UxXqNpU_FLFyw,2382
247
247
  canvas_sdk/v1/data/message.py,sha256=P95_oeOnaSDEPFoCx6Gcl54-NgYbW8BgIXizl5pBSiQ,2435
248
- canvas_sdk/v1/data/note.py,sha256=E92cgA90hQCAZjIEqFzZOcWJ74RoVEwDpG4Fx35NCkM,6790
248
+ canvas_sdk/v1/data/note.py,sha256=wdQhfYZw6Kx9oQSltm_zO_zu5eFA3d8cdfYTNbq786o,9139
249
249
  canvas_sdk/v1/data/observation.py,sha256=Hh8UKY1iqIYAqySWhwoj86Gmkbhz90C2m4GIx56ucyo,4034
250
250
  canvas_sdk/v1/data/organization.py,sha256=-q1MbjPWihCaoKx6ZkRSY2JD3VNzAHIGGd6foMDwAy8,1031
251
251
  canvas_sdk/v1/data/patient.py,sha256=M91WSFFXg03Fu0qP7MRNVvn02EHJ4sMmBZnQMNehnyc,8915
@@ -293,14 +293,14 @@ plugin_runner/exceptions.py,sha256=YnRZiQVzbU3HrVlmEXLje_np99009YnhTRVHHyBCtqc,4
293
293
  plugin_runner/installation.py,sha256=LLjtnzPk-w4go3UbXnBItJTKz1ajR_5kGQbFXTaWTFU,7693
294
294
  plugin_runner/load_all_plugins.py,sha256=4T2gW2YljhIx4xfwf1c0F_8oIbE1ubsLj0ShkHRtlVY,5847
295
295
  plugin_runner/plugin_runner.py,sha256=Z7ySPJSY4AMGRR0PtdXA_I3z8rxlDpjssuMspHIc79U,21655
296
- plugin_runner/sandbox.py,sha256=B6b8AfmazA-nhXh6Z3s8-9yg0EpD1gbiToCVafCC3yc,28628
296
+ plugin_runner/sandbox.py,sha256=yNkGDdsSFHaRNNga731LhXeZunpXkdtUWG_xTs1IEfg,28708
297
297
  protobufs/canvas_generated/messages/effects.proto,sha256=L5QGPfnmiefjD7qsGzKRbHAAyAstQmVvMrndwg1lumQ,8807
298
298
  protobufs/canvas_generated/messages/events.proto,sha256=DSxbxKp7BTZpI4M14Sm7-XpHdUnN3bC3RapRqZbxgiQ,48751
299
299
  protobufs/canvas_generated/messages/plugins.proto,sha256=oNainUPWFYQjgCX7bJEPI9_VnHC5VZduzOqgR4Q7dNM,109
300
300
  protobufs/canvas_generated/services/plugin_runner.proto,sha256=doadBKn5k4xAtOgR-q_pEvW4yzxpUaHNOowMG6CL5GY,304
301
301
  pubsub/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
302
302
  pubsub/pubsub.py,sha256=PHIvJ5SD3M-jQSYeGGSj1FuG6CvP6BQffAoGax9Uudk,1423
303
- canvas-0.44.3.dist-info/METADATA,sha256=H0_lRz3g2L965YjCc3akgG8N67cmV58OnP8qTYF4sJk,4424
304
- canvas-0.44.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
305
- canvas-0.44.3.dist-info/entry_points.txt,sha256=0Vs_9GmTVUNniH6eDBlRPgofmADMV4BES6Ao26M4AbM,47
306
- canvas-0.44.3.dist-info/RECORD,,
303
+ canvas-0.45.0.dist-info/METADATA,sha256=P8Y0uYZDq_oS1JwSqeeiSQ104VyG-smdqe4YfBiNlX4,4456
304
+ canvas-0.45.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
305
+ canvas-0.45.0.dist-info/entry_points.txt,sha256=0Vs_9GmTVUNniH6eDBlRPgofmADMV4BES6Ao26M4AbM,47
306
+ canvas-0.45.0.dist-info/RECORD,,
@@ -7,6 +7,7 @@ from pathlib import Path
7
7
  from typing import Any, cast
8
8
  from urllib.parse import urljoin
9
9
 
10
+ import pathspec
10
11
  import requests
11
12
  import typer
12
13
  from cookiecutter.exceptions import OutputDirExistsException
@@ -16,6 +17,8 @@ from canvas_cli.apps.auth.utils import get_default_host, get_or_request_api_toke
16
17
  from canvas_cli.utils.context import context
17
18
  from canvas_cli.utils.validators import validate_manifest_file
18
19
 
20
+ CANVAS_IGNORE_FILENAME = ".canvasignore"
21
+
19
22
 
20
23
  def plugin_url(host: str, *paths: str) -> str:
21
24
  """Generates the plugin url for managing plugins in a Canvas instance."""
@@ -46,11 +49,27 @@ def _build_package(package: Path) -> Path:
46
49
  if not package.exists() or not package.is_dir():
47
50
  raise typer.BadParameter(f"Couldn't build {package}, not a dir")
48
51
 
52
+ ignore_file = Path.cwd() / CANVAS_IGNORE_FILENAME
53
+ if ignore_file.exists():
54
+ ignore_patterns = pathspec.PathSpec.from_lines(
55
+ pathspec.patterns.GitWildMatchPattern, ignore_file.read_text().splitlines()
56
+ )
57
+ else:
58
+ ignore_patterns = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, [])
59
+
49
60
  with tempfile.NamedTemporaryFile(suffix=".tar.gz", delete=False) as file:
50
61
  with tarfile.open(file.name, "w:gz") as tar:
51
62
  for root in package.rglob("*"):
52
- # Skip hidden files and directories (starting with '.') and symlinks
53
- if any(part.startswith(".") for part in root.parts) or root.is_symlink():
63
+ # Skip hidden files and directories (starting with '.')
64
+ if any(part.startswith(".") for part in root.parts):
65
+ continue
66
+
67
+ # Skip symlinks
68
+ if root.is_symlink():
69
+ continue
70
+
71
+ # Skip files and directories matching the ignore patterns
72
+ if ignore_patterns.match_file(root):
54
73
  continue
55
74
 
56
75
  tar.add(root, arcname=root.relative_to(package))
canvas_sdk/utils/http.py CHANGED
@@ -308,7 +308,10 @@ class PharmacyHttp:
308
308
  self._http_client._session.verify = False
309
309
 
310
310
  def search_pharmacies(
311
- self, search_term: str, latitude: str | None = None, longitude: str | None = None
311
+ self,
312
+ search_term: str | None = " ",
313
+ latitude: str | None = None,
314
+ longitude: str | None = None,
312
315
  ) -> list[dict]:
313
316
  """Search for pharmacies by term and optional location."""
314
317
  params = {"search": search_term}
@@ -87,6 +87,30 @@ class NoteTypes(models.TextChoices):
87
87
  CCDA = "ccda", "C-CDA Import"
88
88
 
89
89
 
90
+ class NoteStates(models.TextChoices):
91
+ """Note states."""
92
+
93
+ NEW = "NEW", "Created"
94
+ PUSHED = "PSH", "Pushed the charges for"
95
+ LOCKED = "LKD", "Locked"
96
+ UNLOCKED = "ULK", "Unlocked"
97
+ DELETED = "DLT", "Deleted"
98
+ RELOCKED = "RLK", "Relocked"
99
+ RESTORED = "RST", "Restored"
100
+ RECALLED = "RCL", "Recalled"
101
+ UNDELETED = "UND", "Undeleted"
102
+ DISCHARGED = "DSC", "Discharged"
103
+ # Appointment note
104
+ SCHEDULING = "SCH", "Scheduling"
105
+ BOOKED = "BKD", "Booked"
106
+ CONVERTED = "CVD", "Checked in"
107
+ CANCELLED = "CLD", "Canceled"
108
+ NOSHOW = "NSW", "No show"
109
+ REVERTED = "RVT", "Reverted"
110
+ # C-CDA Import note
111
+ CONFIRM_IMPORT = "CNF", "Confirmed"
112
+
113
+
90
114
  class NoteType(models.Model):
91
115
  """NoteType."""
92
116
 
@@ -162,10 +186,58 @@ class Note(models.Model):
162
186
  place_of_service = models.CharField()
163
187
 
164
188
 
189
+ class NoteStateChangeEvent(models.Model):
190
+ """NoteStateChangeEvent."""
191
+
192
+ class Meta:
193
+ managed = False
194
+ db_table = "canvas_sdk_data_api_notestatechangeevent_001"
195
+
196
+ id = models.UUIDField()
197
+ dbid = models.BigIntegerField(primary_key=True)
198
+ created = models.DateTimeField()
199
+ modified = models.DateTimeField()
200
+ note = models.ForeignKey("v1.Note", on_delete=models.DO_NOTHING, related_name="state_history")
201
+ originator = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
202
+ state = models.CharField(choices=NoteStates.choices)
203
+ note_state_document = models.CharField()
204
+ note_state_html = models.TextField()
205
+
206
+
207
+ class CurrentNoteStateEvent(models.Model):
208
+ """
209
+ CurrentNoteStateEvent is a special model backed by a view which only includes the latest
210
+ NoteStateChangeEvent for any given note_id.
211
+ """
212
+
213
+ class Meta:
214
+ managed = False
215
+ app_label = "canvas_sdk"
216
+ db_table = "canvas_sdk_data_current_note_state_001"
217
+
218
+ id = models.UUIDField()
219
+ dbid: models.BigIntegerField = models.BigIntegerField(primary_key=True)
220
+ state: models.CharField = models.CharField(choices=NoteStates.choices)
221
+ note = models.ForeignKey("v1.Note", on_delete=models.DO_NOTHING, related_name="+")
222
+
223
+ def editable(self) -> bool:
224
+ """Returns a boolean to indicate if the related note can be edited."""
225
+ return self.state in [
226
+ NoteStates.NEW,
227
+ NoteStates.PUSHED,
228
+ NoteStates.UNLOCKED,
229
+ NoteStates.RESTORED,
230
+ NoteStates.UNDELETED,
231
+ ]
232
+
233
+
165
234
  __exports__ = (
166
235
  "NoteTypeCategories",
167
236
  "PracticeLocationPOS",
168
237
  "NoteTypes",
169
238
  "NoteType",
170
239
  "Note",
240
+ "NoteStates",
241
+ "NoteStateChangeEvent",
242
+ "CurrentNoteStateEvent",
171
243
  )
plugin_runner/sandbox.py CHANGED
@@ -127,6 +127,10 @@ STANDARD_LIBRARY_MODULES = {
127
127
  "annotations",
128
128
  },
129
129
  "_strptime": set(), # gets imported at runtime via datetime.datetime.strptime()
130
+ "abc": {
131
+ "ABC",
132
+ "abstractmethod",
133
+ },
130
134
  "base64": {
131
135
  "b64decode",
132
136
  "b64encode",
@@ -204,6 +208,7 @@ STANDARD_LIBRARY_MODULES = {
204
208
  "Final",
205
209
  "Iterable",
206
210
  "List",
211
+ "Literal",
207
212
  "NamedTuple",
208
213
  "NotRequired",
209
214
  "Protocol",