> This page is for Structured Data Models Client.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/sdgm/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/sdgm/_mcp/server.

# Python SDK API

> Public Python interfaces for connecting to a NIM serving kumo-tabular

Install the SDK by following [Install and Connect](/sdgm/kumo-tabular/get-started/sdk-getting-started). This reference documents the sdm-client interfaces used by the Kumo Tabular workflow.

> **Note**
>
> What is public is defined precisely: everything named in `sdm_client.__all__`. Anything beginning with `_`, and any submodule not re-exported at the top level, is an implementation detail that can change in any release. See the [stability contract](https://github.com/NVIDIA/structured-data-models-client/blob/main/docs/reference/stability.md).

Import the supported public interfaces from `sdm_client`:

```python
from sdm_client import (
    SDMClient, Schema, Request, PredictiveQuery, KumoTabular, PredictionResult,
)
```

## `SDMClient`

```text
SDMClient(
    url: str,
    api_key: str | None = None,
    *,
    verify_ssl: bool = True,
    timeout: float = 60.0,
    max_retries: int = 3,
)
```

A connection to one NIM, serving every model it can reach. No request is made by the constructor; the endpoint is first contacted by `health_ready()`, `models()`, or a prediction. Use it as a context manager, or call `close()` explicitly.

| Method                                               | Description                                                                                                       |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `health_ready()`                                     | Whether the NIM answers `GET /v1/health/ready` with 200.                                                          |
| `models()`                                           | Model ids **the endpoint** advertises, read from `/v1/models`.                                                    |
| `capabilities(model)`                                | What `model` supports, as far as this client knows. Client-side, tagged `source='sdk'`; needs no live connection. |
| `predict(request, *, model, outputs=None)`           | Answer `request` with `model`. Returns a `PredictionResult`.                                                      |
| `fit(request, *, model, outputs=None, holdout=None)` | Pin `request`'s context on the endpoint and return a `FittedModel`.                                               |
| `close()`                                            | Releases pooled connections and permanently retires the client.                                                   |

Each client owns its own transport, so several can target different endpoints or tenants at once, including from several threads — a prediction always goes to the endpoint and credential of the client that started it.

## `KumoTabular`

```python
from sdm_client import KumoTabular

client.predict(request, model=KumoTabular())
```

A thin, stateless handle naming the tabular model. One table in, a prediction per row out.

|                |                                                                       |
| -------------- | --------------------------------------------------------------------- |
| Task kinds     | `classification`, `regression`                                        |
| Output fields  | `prediction`, `probabilities`, `quantiles`                            |
| Relationships  | None — a request carrying related tables is refused before it is sent |
| Extra required | None — ships in the base install, runs anywhere                       |

## `Schema`

```text
Schema.from_data(
    tables: Mapping[str, pandas.DataFrame],
    *,
    primary_keys: Mapping[str, str | Sequence[str]] | None = None,
    time_columns: Mapping[str, str | None] | None = None,
    relationships: Sequence[Relationship] | None = None,
) -> Schema
```

Infers dtype, semantic type, primary key, and time column for every column of every table. Index it by table name, and index a table by column name:

```python
schema = Schema.from_data({"users": users_df})
schema["users"].primary_key = "user_id"
schema["users"]["churn"].stype = "categorical"
```

`Schema.from_source()`, which samples a warehouse or database in place without loading it into memory, exists but is refused for a tabular question — it is for the relational model. See [Prepare Your Data](/sdgm/kumo-tabular/user-guide/prepare-data/data-requirements).

## `Request`

```text
Request(
    context: pandas.DataFrame,
    predict: pandas.DataFrame,
    *,
    target: str,
    task: str,
    related_tables: Mapping[str, pandas.DataFrame] | None = None,
    schema: Schema | None = None,
    entity_table: str = "instance",
    inference: Mapping[str, Any] | None = None,
    task_options: Mapping[str, Any] | None = None,
)
```

The wire envelope minus the two things that are `predict()` arguments: which model answers it, and which output fields you want back. A Kumo Tabular request is sent in one call; this adapter does not automatically split it into batches. Refer to [Limits](/sdgm/kumo-tabular/user-guide/configure-and-scale/limits) for the context-row cap.

| Argument  | Meaning                                                                                                      |
| --------- | ------------------------------------------------------------------------------------------------------------ |
| `context` | Rows where the answer is known. Must contain `target`, with at least one non-null value.                     |
| `predict` | Rows being asked about. Must not contain `target`.                                                           |
| `target`  | The column being predicted.                                                                                  |
| `task`    | `"classification"` or `"regression"` for Kumo Tabular. Stated, never inferred from the target's cardinality. |
| `schema`  | Override the inferred schema. Rarely needed.                                                                 |

Read-only properties: `is_relational`, `context_rows`, `predict_rows`, `nothing_to_score`. `request.task` is a `Task(kind, target, entity_table, options)`; `request.task.target` is a `Target(column_name, dtype, table_name)`; `request.context`/`request.predict` are each a `Split(instance_table, related_tables)`. These are read-only descriptions of a request, not something you construct by hand.

## `ModelCapabilities`

What `client.capabilities(model)` returns: `model`, `tasks`, `outputs`, `single_table`, `multiple_tables`, `relationships`, `explanation_formats`, and `sessions`. Describes this client, not the endpoint.

## `PredictiveQuery`

```text
PredictiveQuery(query: str, data: Schema | Mapping[str, pandas.DataFrame])

.materialize(
    *,
    indices: Sequence[Any] | None = None,
    predict: pandas.DataFrame | None = None,
    num_context_samples: int | None = None,
    model: str | Model | None = None,
    task: str | None = None,
) -> Request
```

Resolves and validates the query when `materialize()` builds a request. Pass exactly one of `indices` (existing rows, looked up by key) or `predict` (rows supplied directly). See [Make Predictions](/sdgm/kumo-tabular/user-guide/make-predictions/make-predictions).

## `PredictionResult`

```python
result = client.predict(request, model=KumoTabular())
```

| Attribute / Method  | Description                                                                                                                                                                                     |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`             | The model id that answered.                                                                                                                                                                     |
| `request_id`        | The endpoint's id for the call.                                                                                                                                                                 |
| `items`             | The response items, in the order the endpoint returned them.                                                                                                                                    |
| `metadata`          | Whatever the endpoint reported alongside the predictions.                                                                                                                                       |
| `explanations`      | Container with `.gradients` and `.columns` when requested and supported. See [explanation availability and examples](/sdgm/kumo-tabular/user-guide/explain-predictions/explain-tabular-predictions). |
| `to_pandas()`       | The predictions as a DataFrame. See [Prediction Results](/sdgm/kumo-tabular/user-guide/work-with-prediction-results/prediction-results).                                                             |
| `absent(requested)` | Which of `requested` the answer does not carry.                                                                                                                                                 |

## `FittedModel`

Returned by `SDMClient.fit()`. `predict(request)` scores rows against the pinned context; `close()` releases it. Use as a context manager or call `close()` explicitly.

## Errors

```python
from sdm_client import (
    StructuredDataError, UnknownModelError, UnsupportedRequestError,
    MissingExtraError, NimRequestError,
)
```

Every call on `SDMClient` raises `StructuredDataError` or a subclass, so `except StructuredDataError` catches anything the client reports. Every error carries a stable `code` to branch on; messages are written for people and will change.

| Class                     | `code`                     | Raised when                                                                                                                                                                                                                                                                                                                            |
| ------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `UnknownModelError`       | `UNKNOWN_MODEL`            | `model` is not one the contract carries.                                                                                                                                                                                                                                                                                               |
| `UnsupportedRequestError` | `UNSUPPORTED_REQUEST`      | The model cannot answer this request — related tables, an output field it does not produce, or a size over a limit. Raised before anything is sent.                                                                                                                                                                                    |
| `MissingExtraError`       | `MISSING_EXTRA`            | An optional dependency the call needs is not installed.                                                                                                                                                                                                                                                                                |
| `NimRequestError`         | varies, plus `status_code` | The NIM answered, and the answer was an error. `SDMClient` automatically retries 429, 502, 503, and 504 (plus eligible connection failures); it does not retry 500, since the endpoint can use that status for a repeatable request or model error rather than a transient one — inspect a 500 rather than assuming a retry will help. |

## `sdm_connectors`

```python
from sdm_connectors import read

df = read("snowflake", table="orders", account="...", user="...", password="...")
```

See [Connect Data Sources](/sdgm/kumo-tabular/user-guide/prepare-data/connect-data-sources) for `read()` and per-backend arguments.