hubble-sdk-python 0.2.1__py3-none-any.whl → 0.3.1__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.
Files changed (36) hide show
  1. hubble_sdk/__init__.py +24 -4
  2. hubble_sdk/_generated/api/default/create_consent.py +193 -0
  3. hubble_sdk/_generated/api/default/create_consent_link.py +8 -4
  4. hubble_sdk/_generated/api/default/export_patient_fhir.py +49 -12
  5. hubble_sdk/_generated/api/default/export_patient_pdf.py +93 -12
  6. hubble_sdk/_generated/api/default/get_application_token.py +194 -0
  7. hubble_sdk/_generated/api/default/get_patient_pdf_export.py +55 -20
  8. hubble_sdk/_generated/api/default/list_consents.py +16 -4
  9. hubble_sdk/_generated/api/default/read_fhir.py +70 -13
  10. hubble_sdk/_generated/models/__init__.py +24 -0
  11. hubble_sdk/_generated/models/application_token_error.py +54 -0
  12. hubble_sdk/_generated/models/application_token_error_error.py +31 -0
  13. hubble_sdk/_generated/models/application_token_request.py +72 -0
  14. hubble_sdk/_generated/models/application_token_response.py +69 -0
  15. hubble_sdk/_generated/models/attach_client_authorization_body.py +1 -1
  16. hubble_sdk/_generated/models/client_supplied_discloser.py +107 -0
  17. hubble_sdk/_generated/models/client_supplied_discloser_facility_type.py +28 -0
  18. hubble_sdk/_generated/models/consent.py +5 -4
  19. hubble_sdk/_generated/models/created_consent.py +152 -0
  20. hubble_sdk/_generated/models/export_patient_pdf_combined.py +27 -0
  21. hubble_sdk/_generated/models/export_patient_pdf_hubble_version.py +27 -0
  22. hubble_sdk/_generated/models/facility_address.py +78 -0
  23. hubble_sdk/_generated/models/facility_address_state.py +77 -0
  24. hubble_sdk/_generated/models/operation_outcome.py +1 -3
  25. hubble_sdk/_generated/models/patient_address.py +13 -5
  26. hubble_sdk/_generated/models/patient_address_state.py +77 -0
  27. hubble_sdk/_generated/models/patient_demographics.py +1 -1
  28. hubble_sdk/_generated/models/provider_seed.py +2 -1
  29. hubble_sdk/_hubble.py +387 -54
  30. hubble_sdk/_params.py +86 -0
  31. hubble_sdk/_webhooks.py +2 -2
  32. hubble_sdk/py.typed +0 -0
  33. {hubble_sdk_python-0.2.1.dist-info → hubble_sdk_python-0.3.1.dist-info}/METADATA +45 -16
  34. {hubble_sdk_python-0.2.1.dist-info → hubble_sdk_python-0.3.1.dist-info}/RECORD +36 -20
  35. {hubble_sdk_python-0.2.1.dist-info → hubble_sdk_python-0.3.1.dist-info}/WHEEL +1 -1
  36. {hubble_sdk_python-0.2.1.dist-info → hubble_sdk_python-0.3.1.dist-info}/licenses/LICENSE +0 -0
hubble_sdk/__init__.py CHANGED
@@ -5,10 +5,12 @@ Import the high-level client from here:
5
5
  from hubble_sdk import Hubble
6
6
 
7
7
  hub = Hubble(client_id="hbl_client_...", client_secret="hbl_prod_...")
8
- link = hub.create_link(patient_ref="abc123")
9
- print(link.verification_uri_complete) # send the patient here
10
- session = hub.wait_for_authorization(link)
11
- bundle = session.everything() # reads FHIR with the consent token
8
+ consent = hub.create_consent(patient_ref="abc123")
9
+ print(consent.link_url) # send the patient here
10
+ bundle = hub.everything(consent.id) # read whenever you like
11
+
12
+ The device flow (``create_link`` / ``wait_for_authorization``) still works for
13
+ existing integrations.
12
14
 
13
15
  The generated low-level client lives under ``hubble_sdk._generated``
14
16
  if you need direct access to raw operations and models.
@@ -17,6 +19,7 @@ if you need direct access to raw operations and models.
17
19
  from ._generated.models import (
18
20
  Consent,
19
21
  ConsentStatus,
22
+ CreatedConsent,
20
23
  DeviceAuthorizationResponse,
21
24
  TokenResponse,
22
25
  )
@@ -28,6 +31,15 @@ from ._hubble import (
28
31
  PdfExport,
29
32
  TokenSet,
30
33
  )
34
+ from ._params import (
35
+ ConsentStatusFilter,
36
+ DiscloserParams,
37
+ FacilityAddressParams,
38
+ PatientAddressParams,
39
+ PatientParams,
40
+ ProviderSeedParams,
41
+ UsStateCode,
42
+ )
31
43
  from ._webhooks import (
32
44
  WEBHOOK_SIGNATURE_HEADER,
33
45
  WebhookEvent,
@@ -43,6 +55,13 @@ __all__ = [
43
55
  "ConsentTimeout",
44
56
  "TokenSet",
45
57
  "PdfExport",
58
+ "ConsentStatusFilter",
59
+ "PatientParams",
60
+ "PatientAddressParams",
61
+ "ProviderSeedParams",
62
+ "DiscloserParams",
63
+ "FacilityAddressParams",
64
+ "UsStateCode",
46
65
  "construct_webhook_event",
47
66
  "WebhookEvent",
48
67
  "WebhookEventSource",
@@ -50,6 +69,7 @@ __all__ = [
50
69
  "WEBHOOK_SIGNATURE_HEADER",
51
70
  "Consent",
52
71
  "ConsentStatus",
72
+ "CreatedConsent",
53
73
  "DeviceAuthorizationResponse",
54
74
  "TokenResponse",
55
75
  ]
@@ -0,0 +1,193 @@
1
+ from http import HTTPStatus
2
+ from typing import Any
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...models.api_error import ApiError
9
+ from ...models.consent_link_request import ConsentLinkRequest
10
+ from ...models.created_consent import CreatedConsent
11
+ from ...types import UNSET, Response, Unset
12
+
13
+
14
+ def _get_kwargs(
15
+ *,
16
+ body: ConsentLinkRequest | Unset = UNSET,
17
+ ) -> dict[str, Any]:
18
+ headers: dict[str, Any] = {}
19
+
20
+ _kwargs: dict[str, Any] = {
21
+ "method": "post",
22
+ "url": "/api/v1/consents",
23
+ }
24
+
25
+ if not isinstance(body, Unset):
26
+ _kwargs["json"] = body.to_dict()
27
+
28
+ headers["Content-Type"] = "application/json"
29
+
30
+ _kwargs["headers"] = headers
31
+ return _kwargs
32
+
33
+
34
+ def _parse_response(
35
+ *, client: AuthenticatedClient | Client, response: httpx.Response
36
+ ) -> ApiError | CreatedConsent | None:
37
+ if response.status_code == 201:
38
+ response_201 = CreatedConsent.from_dict(response.json())
39
+
40
+ return response_201
41
+
42
+ if response.status_code == 400:
43
+ response_400 = ApiError.from_dict(response.json())
44
+
45
+ return response_400
46
+
47
+ if response.status_code == 401:
48
+ response_401 = ApiError.from_dict(response.json())
49
+
50
+ return response_401
51
+
52
+ if response.status_code == 403:
53
+ response_403 = ApiError.from_dict(response.json())
54
+
55
+ return response_403
56
+
57
+ if client.raise_on_unexpected_status:
58
+ raise errors.UnexpectedStatus(response.status_code, response.content)
59
+ else:
60
+ return None
61
+
62
+
63
+ def _build_response(
64
+ *, client: AuthenticatedClient | Client, response: httpx.Response
65
+ ) -> Response[ApiError | CreatedConsent]:
66
+ return Response(
67
+ status_code=HTTPStatus(response.status_code),
68
+ content=response.content,
69
+ headers=response.headers,
70
+ parsed=_parse_response(client=client, response=response),
71
+ )
72
+
73
+
74
+ def sync_detailed(
75
+ *,
76
+ client: AuthenticatedClient,
77
+ body: ConsentLinkRequest | Unset = UNSET,
78
+ ) -> Response[ApiError | CreatedConsent]:
79
+ """Create a consent
80
+
81
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
82
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
83
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
84
+
85
+ Args:
86
+ body (ConsentLinkRequest | Unset):
87
+
88
+ Raises:
89
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
90
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
91
+
92
+ Returns:
93
+ Response[ApiError | CreatedConsent]
94
+ """
95
+
96
+ kwargs = _get_kwargs(
97
+ body=body,
98
+ )
99
+
100
+ response = client.get_httpx_client().request(
101
+ **kwargs,
102
+ )
103
+
104
+ return _build_response(client=client, response=response)
105
+
106
+
107
+ def sync(
108
+ *,
109
+ client: AuthenticatedClient,
110
+ body: ConsentLinkRequest | Unset = UNSET,
111
+ ) -> ApiError | CreatedConsent | None:
112
+ """Create a consent
113
+
114
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
115
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
116
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
117
+
118
+ Args:
119
+ body (ConsentLinkRequest | Unset):
120
+
121
+ Raises:
122
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
123
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
124
+
125
+ Returns:
126
+ ApiError | CreatedConsent
127
+ """
128
+
129
+ return sync_detailed(
130
+ client=client,
131
+ body=body,
132
+ ).parsed
133
+
134
+
135
+ async def asyncio_detailed(
136
+ *,
137
+ client: AuthenticatedClient,
138
+ body: ConsentLinkRequest | Unset = UNSET,
139
+ ) -> Response[ApiError | CreatedConsent]:
140
+ """Create a consent
141
+
142
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
143
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
144
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
145
+
146
+ Args:
147
+ body (ConsentLinkRequest | Unset):
148
+
149
+ Raises:
150
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
151
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
152
+
153
+ Returns:
154
+ Response[ApiError | CreatedConsent]
155
+ """
156
+
157
+ kwargs = _get_kwargs(
158
+ body=body,
159
+ )
160
+
161
+ response = await client.get_async_httpx_client().request(**kwargs)
162
+
163
+ return _build_response(client=client, response=response)
164
+
165
+
166
+ async def asyncio(
167
+ *,
168
+ client: AuthenticatedClient,
169
+ body: ConsentLinkRequest | Unset = UNSET,
170
+ ) -> ApiError | CreatedConsent | None:
171
+ """Create a consent
172
+
173
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
174
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
175
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
176
+
177
+ Args:
178
+ body (ConsentLinkRequest | Unset):
179
+
180
+ Raises:
181
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
182
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
183
+
184
+ Returns:
185
+ ApiError | CreatedConsent
186
+ """
187
+
188
+ return (
189
+ await asyncio_detailed(
190
+ client=client,
191
+ body=body,
192
+ )
193
+ ).parsed
@@ -77,7 +77,8 @@ def sync_detailed(
77
77
  Mints a pending consent and a one-time patient link. Send the patient to
78
78
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
79
79
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
80
- consent.
80
+ consent. To read with an application access token instead, create the consent with POST
81
+ /api/v1/consents, which has no device code.
81
82
 
82
83
  Args:
83
84
  body (ConsentLinkRequest | Unset):
@@ -112,7 +113,8 @@ def sync(
112
113
  Mints a pending consent and a one-time patient link. Send the patient to
113
114
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
114
115
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
115
- consent.
116
+ consent. To read with an application access token instead, create the consent with POST
117
+ /api/v1/consents, which has no device code.
116
118
 
117
119
  Args:
118
120
  body (ConsentLinkRequest | Unset):
@@ -142,7 +144,8 @@ async def asyncio_detailed(
142
144
  Mints a pending consent and a one-time patient link. Send the patient to
143
145
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
144
146
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
145
- consent.
147
+ consent. To read with an application access token instead, create the consent with POST
148
+ /api/v1/consents, which has no device code.
146
149
 
147
150
  Args:
148
151
  body (ConsentLinkRequest | Unset):
@@ -175,7 +178,8 @@ async def asyncio(
175
178
  Mints a pending consent and a one-time patient link. Send the patient to
176
179
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
177
180
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
178
- consent.
181
+ consent. To read with an application access token instead, create the consent with POST
182
+ /api/v1/consents, which has no device code.
179
183
 
180
184
  Args:
181
185
  body (ConsentLinkRequest | Unset):
@@ -1,5 +1,6 @@
1
1
  from http import HTTPStatus
2
2
  from typing import Any
3
+ from uuid import UUID
3
4
 
4
5
  import httpx
5
6
 
@@ -14,6 +15,8 @@ from ...types import UNSET, Response, Unset
14
15
 
15
16
  def _get_kwargs(
16
17
  *,
18
+ consent: UUID | Unset = UNSET,
19
+ connection: UUID | Unset = UNSET,
17
20
  field_count: int | Unset = UNSET,
18
21
  field_offset: int | Unset = UNSET,
19
22
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -24,6 +27,16 @@ def _get_kwargs(
24
27
 
25
28
  params: dict[str, Any] = {}
26
29
 
30
+ json_consent: str | Unset = UNSET
31
+ if not isinstance(consent, Unset):
32
+ json_consent = str(consent)
33
+ params["consent"] = json_consent
34
+
35
+ json_connection: str | Unset = UNSET
36
+ if not isinstance(connection, Unset):
37
+ json_connection = str(connection)
38
+ params["connection"] = json_connection
39
+
27
40
  params["_count"] = field_count
28
41
 
29
42
  params["_offset"] = field_offset
@@ -103,6 +116,8 @@ def _build_response(
103
116
  def sync_detailed(
104
117
  *,
105
118
  client: AuthenticatedClient,
119
+ consent: UUID | Unset = UNSET,
120
+ connection: UUID | Unset = UNSET,
106
121
  field_count: int | Unset = UNSET,
107
122
  field_offset: int | Unset = UNSET,
108
123
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -113,11 +128,13 @@ def sync_detailed(
113
128
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
114
129
  Bundle containing the captured provider sources, including each source's Patient and warnings for
115
130
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
116
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
117
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
118
- request for one already running reuses it. Payer records are not included.
131
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
132
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
133
+ one already running reuses it. Payer records are not included.
119
134
 
120
135
  Args:
136
+ consent (UUID | Unset):
137
+ connection (UUID | Unset):
121
138
  field_count (int | Unset):
122
139
  field_offset (int | Unset):
123
140
  prefer (ExportPatientFhirPrefer | Unset):
@@ -131,6 +148,8 @@ def sync_detailed(
131
148
  """
132
149
 
133
150
  kwargs = _get_kwargs(
151
+ consent=consent,
152
+ connection=connection,
134
153
  field_count=field_count,
135
154
  field_offset=field_offset,
136
155
  prefer=prefer,
@@ -146,6 +165,8 @@ def sync_detailed(
146
165
  def sync(
147
166
  *,
148
167
  client: AuthenticatedClient,
168
+ consent: UUID | Unset = UNSET,
169
+ connection: UUID | Unset = UNSET,
149
170
  field_count: int | Unset = UNSET,
150
171
  field_offset: int | Unset = UNSET,
151
172
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -156,11 +177,13 @@ def sync(
156
177
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
157
178
  Bundle containing the captured provider sources, including each source's Patient and warnings for
158
179
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
159
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
160
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
161
- request for one already running reuses it. Payer records are not included.
180
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
181
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
182
+ one already running reuses it. Payer records are not included.
162
183
 
163
184
  Args:
185
+ consent (UUID | Unset):
186
+ connection (UUID | Unset):
164
187
  field_count (int | Unset):
165
188
  field_offset (int | Unset):
166
189
  prefer (ExportPatientFhirPrefer | Unset):
@@ -175,6 +198,8 @@ def sync(
175
198
 
176
199
  return sync_detailed(
177
200
  client=client,
201
+ consent=consent,
202
+ connection=connection,
178
203
  field_count=field_count,
179
204
  field_offset=field_offset,
180
205
  prefer=prefer,
@@ -184,6 +209,8 @@ def sync(
184
209
  async def asyncio_detailed(
185
210
  *,
186
211
  client: AuthenticatedClient,
212
+ consent: UUID | Unset = UNSET,
213
+ connection: UUID | Unset = UNSET,
187
214
  field_count: int | Unset = UNSET,
188
215
  field_offset: int | Unset = UNSET,
189
216
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -194,11 +221,13 @@ async def asyncio_detailed(
194
221
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
195
222
  Bundle containing the captured provider sources, including each source's Patient and warnings for
196
223
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
197
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
198
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
199
- request for one already running reuses it. Payer records are not included.
224
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
225
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
226
+ one already running reuses it. Payer records are not included.
200
227
 
201
228
  Args:
229
+ consent (UUID | Unset):
230
+ connection (UUID | Unset):
202
231
  field_count (int | Unset):
203
232
  field_offset (int | Unset):
204
233
  prefer (ExportPatientFhirPrefer | Unset):
@@ -212,6 +241,8 @@ async def asyncio_detailed(
212
241
  """
213
242
 
214
243
  kwargs = _get_kwargs(
244
+ consent=consent,
245
+ connection=connection,
215
246
  field_count=field_count,
216
247
  field_offset=field_offset,
217
248
  prefer=prefer,
@@ -225,6 +256,8 @@ async def asyncio_detailed(
225
256
  async def asyncio(
226
257
  *,
227
258
  client: AuthenticatedClient,
259
+ consent: UUID | Unset = UNSET,
260
+ connection: UUID | Unset = UNSET,
228
261
  field_count: int | Unset = UNSET,
229
262
  field_offset: int | Unset = UNSET,
230
263
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -235,11 +268,13 @@ async def asyncio(
235
268
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
236
269
  Bundle containing the captured provider sources, including each source's Patient and warnings for
237
270
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
238
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
239
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
240
- request for one already running reuses it. Payer records are not included.
271
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
272
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
273
+ one already running reuses it. Payer records are not included.
241
274
 
242
275
  Args:
276
+ consent (UUID | Unset):
277
+ connection (UUID | Unset):
243
278
  field_count (int | Unset):
244
279
  field_offset (int | Unset):
245
280
  prefer (ExportPatientFhirPrefer | Unset):
@@ -255,6 +290,8 @@ async def asyncio(
255
290
  return (
256
291
  await asyncio_detailed(
257
292
  client=client,
293
+ consent=consent,
294
+ connection=connection,
258
295
  field_count=field_count,
259
296
  field_offset=field_offset,
260
297
  prefer=prefer,