# ovok_sdk.resources.measurements

Canonical page: https://docs.ovok.com/python-sdk/reference/resources/measurements

Measurement building, saving with an offline retry queue, and latest-value reads.

## offline_measurement_storage_key() [#offline_measurement_storage_key]

```python
offline_measurement_storage_key(tenant_code: str, base_url: str) -> str
```

Return the storage key of the offline measurement queue for one tenant and API.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `tenant_code` | `str` |  | The tenant code. |
| `base_url` | `str` |  | The API base URL; its origin and path are part of the key. |

**Returns**

- `str`: The storage key.

## MeasurementsResource [#measurementsresource]

```python
MeasurementsResource(
    http: HttpClient,
    fhir: FhirResource,
    session: UserSession | None,
    settings: OvokSettings,
)
```

Builds, saves and reads measurements as FHIR Observations.

Created by `Ovok`; access it as `ovok.measurements`. Signed-in saves go through an offline
queue in the client's storage, so a reading that fails to send is retried later.

**Examples**

```python
result = ovok.measurements.save({
    "measurement": {
        "measurement_type_key": "blood-pressure",
        "systolic": 120,
        "diastolic": 80,
    },
})
```

### build() [#build]

```python
build(params: Resource) -> list[Resource]
```

Build the Observations for a reading without saving them.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `params` | `Resource` |  | `measurement` (with `measurement_type_key` and its values) and optional `patient_id`, `device`, `effective_date_time` and `source_id`. Without `patient_id` the subject is the signed-in user. |

**Returns**

- `list[Resource]`: The Observations, main one first.

**Raises**

- `OvokValidationError`: No patient is named and no user is signed in, or the reading is invalid.

### save() [#save]

```python
save(params: Resource, options: Resource | None = None) -> Resource
```

Build and save a reading.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `params` | `Resource` |  | The reading, as for `build`. |
| `options` | `Resource \| None` | `None` | As for `save_observations`. |

**Returns**

- `Resource`: As for `save_observations`.

### save_observations() [#save_observations]

```python
save_observations(
    observations: list[Resource],
    options: Resource | None = None,
) -> Resource
```

Save Observations in a transaction, idempotently.

Later Observations are linked to the first with `hasMember`. When a user or machine
client owns the save, it goes through the offline queue: a retryable failure keeps it
queued for `offline_queue.flush()`.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `observations` | `list[Resource]` |  | Observations to save, main one first. |
| `options` | `Resource \| None` | `None` | `replace` overwrites earlier readings with the same device-reading identifier; `identifier_systems` adds identifier systems that mark a reading. |

**Returns**

- `Resource`: `{"status": "saved", "response": bundle}` or `{"status": "queued", "queue_id": id}`.

**Raises**

- `OvokError`: The server refused the save with a non-retryable error.

### latest() [#latest]

```python
latest(params: Resource) -> Bundle
```

Read the latest Observation per code with FHIR `$lastn`.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `params` | `Resource` |  | `me=True` for the signed-in user or `patient_id`; optional `codes` (comma-separated, see `codes_for`) and `date` (lower bound). |

**Returns**

- `Bundle`: A searchset Bundle.

**Raises**

- `OvokValidationError`: Neither a signed-in user nor `patient_id` is available.

### last_for_patient() [#last_for_patient]

```python
last_for_patient(patient_id: str, query: QueryParams) -> Bundle
```

Read a patient's last Observations through Ovok's patient route.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `patient_id` | `str` |  | The Patient's ID. |
| `query` | `QueryParams` |  | Query parameters for the route. |

**Returns**

- `Bundle`: The route's Bundle.

### codes_for() [#codes_for]

```python
codes_for(
    types: list[MeasurementTypeKey | str] | tuple[MeasurementTypeKey | str, ...],
) -> str
```

Return the LOINC codes for measurement types, for a `code` search.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `types` | `list[MeasurementTypeKey \| str] \| tuple[MeasurementTypeKey \| str, ...]` |  | Measurement types; unknown ones are skipped. |

**Returns**

- `str`: Comma-separated, de-duplicated codes.

## OfflineMeasurementQueueApi [#offlinemeasurementqueueapi]

```python
OfflineMeasurementQueueApi(queue: OfflineMeasurementQueue)
```

The offline measurement queue; access it as `ovok.measurements.offline_queue`.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `queue` | `OfflineMeasurementQueue` |  | The queue it exposes. |

### flush() [#flush]

```python
flush(*, include_exhausted: bool = False, reset_exhausted: bool = False) -> Resource
```

Retry the current owner's queued saves that are due.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `include_exhausted` | `bool` | `False` | Also retry saves that used up their retries. |
| `reset_exhausted` | `bool` | `False` | Reset exhausted saves to a fresh retry budget first. |

**Returns**

- `Resource`: Counts (`attempted`, `saved`, `queued`, `exhausted`) and per-save
- `Resource`: `responses` and `failures`.

## OfflineMeasurementQueue [#offlinemeasurementqueue]

```python
OfflineMeasurementQueue(
    storage: OvokStorage,
    storage_key: str,
    get_owner_key: Any,
    send: Any,
)
```

Persists pending measurement saves in storage and retries them with backoff.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `storage` | `OvokStorage` |  | Where the queue is kept. |
| `storage_key` | `str` |  | Key of the queue in `storage`. |
| `get_owner_key` | `Any` |  | Returns the current owner's key; only that owner's saves are sent. |
| `send` | `Any` |  | Sends one transaction Bundle for an owner key. |

### enqueue_and_flush() [#enqueue_and_flush]

```python
enqueue_and_flush(entries: list[BundleEntry], owner_key: str) -> Resource
```

Queue a save once, then flush the queue.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `entries` | `list[BundleEntry]` |  | The save's Bundle entries. |
| `owner_key` | `str` |  | Key of the owner the save belongs to. |

**Returns**

- `Resource`: The save's queue `id` and the `flush` result.

**Raises**

- `OvokError`: This flush hit a non-retryable error; that save is dropped.

### flush() [#flush-1]

```python
flush(*, include_exhausted: bool = False, reset_exhausted: bool = False) -> Resource
```

Retry the current owner's queued saves that are due.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `include_exhausted` | `bool` | `False` | Also retry saves that used up their retries. |
| `reset_exhausted` | `bool` | `False` | Reset exhausted saves to a fresh retry budget first. |

**Returns**

- `Resource`: The flush counts, `responses` and `failures`.

## BundleError [#bundleerror]

```python
BundleError(bundle: Bundle)
```

Bases: `Exception`

A Bundle response had an entry with a 4xx or 5xx status.

**Parameters**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `bundle` | `Bundle` |  | The response Bundle. |
