Skip to content

Python

Client sends predictions to a running TServe server. It accepts native Python tables, converts them to Arrow, and posts to /predict/bytes.

Methods

call what it gives you
Client(url, timeout=60.0) a client bound to one server
client.predict(past=..., fh=...) a prediction as a PredictResponse
client.health() process liveness
client.models() loaded models
client.stats() uptime, memory, per-model metrics
client.close() closes the HTTP session

predict returns predictions, quantiles, model, and request_id. Full signatures are in the Python API reference.

Start a server

Point forecasts use chronos_bolt. Quantiles use timesfm_2_5, because Chronos Bolt cannot return them:

docker run --rm -p 8000:8000 sktime/tserve:hub chronos_bolt timesfm_2_5

Other ways to start: Server. The client calls this process.

Install

Install the client extra. Python 3.12 or newer is required.

uv pip install "tserve[client]"
pip install "tserve[client]"

The client extra is enough on a machine that only calls a server. Add server and the required family extra only when the same environment also runs the server.

Connect

Use the client as a context manager so its HTTP session is closed:

from tserve.client import Client

with Client("http://127.0.0.1:8000", timeout=120.0) as client:
    print(client.health())
    print(client.models())
    print(client.stats())

models() reports what this process loaded, not the registry catalog, so it is the quickest way to check which model values a prediction can use.

The default timeout is 60 seconds. Increase it for forecasts that need more time.

Send a prediction

The method takes the same fields as JSON POST /predict. This example sends five days of sales and requests the next three:

from tserve.client import Client

past = {
    "timestamp": [
        "2024-01-01",
        "2024-01-02",
        "2024-01-03",
        "2024-01-04",
        "2024-01-05",
    ],
    "sales": [120, 135, 128, 142, 138],
}

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        time="timestamp",
        target=["sales"],
        fh=3,
        model="chronos_bolt",
    )

print(result.predictions)
print(result.model)
print(result.request_id)

result.predictions is a column dictionary because past was one:

{
    "timestamp": [
        Timestamp("2024-01-06 00:00:00"),
        Timestamp("2024-01-07 00:00:00"),
        Timestamp("2024-01-08 00:00:00"),
    ],
    "sales": [139.96, 138.93, 138.26],
}

See Data specification for all fields, inference rules, and table constraints.

Use native tables

predictions and quantiles use the same table type as past. The following examples send the same data in four native formats.

import pandas as pd
from tserve.client import Client

past = pd.DataFrame(
    {
        "timestamp": pd.date_range("2024-01-01", periods=5, freq="D"),
        "sales": [120, 135, 128, 142, 138],
    }
)

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        time="timestamp",
        target=["sales"],
        fh=3,
        model="chronos_bolt",
    )

print(type(result.predictions))  # pandas.DataFrame
import polars as pl
from tserve.client import Client

past = pl.DataFrame(
    {
        "timestamp": [
            "2024-01-01",
            "2024-01-02",
            "2024-01-03",
            "2024-01-04",
            "2024-01-05",
        ],
        "sales": [120, 135, 128, 142, 138],
    }
)

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        time="timestamp",
        target=["sales"],
        fh=3,
        model="chronos_bolt",
    )

print(type(result.predictions))  # polars.DataFrame
import pyarrow as pa
from tserve.client import Client

past = pa.table(
    {
        "timestamp": [
            "2024-01-01",
            "2024-01-02",
            "2024-01-03",
            "2024-01-04",
            "2024-01-05",
        ],
        "sales": [120, 135, 128, 142, 138],
    }
)

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        time="timestamp",
        target=["sales"],
        fh=3,
        model="chronos_bolt",
    )

print(type(result.predictions))  # pyarrow.Table
import narwhals as nw
import pandas as pd
from tserve.client import Client

past = nw.from_native(
    pd.DataFrame(
        {
            "timestamp": pd.date_range("2024-01-01", periods=5, freq="D"),
            "sales": [120, 135, 128, 142, 138],
        }
    ),
    eager_only=True,
)

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        time="timestamp",
        target=["sales"],
        fh=3,
        model="chronos_bolt",
    )

print(type(result.predictions))  # narwhals.DataFrame

pandas and polars are not installed by the client extra. Install either package separately if you use it. pyarrow and Narwhals are core TServe dependencies.

Use an indexed pandas frame

Time must be a column. Reset a pandas or sktime index before forecasting:

from tserve.client import Client
from sktime.datasets import load_airline

past = load_airline().to_frame("passengers").reset_index()
past = past.rename(columns={"Period": "timestamp"})
past["timestamp"] = past["timestamp"].astype(str)

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        time="timestamp",
        target=["passengers"],
        fh=3,
        model="chronos_bolt",
    )

print(result.predictions)

Panel and hierarchical sktime data are not supported.

Request covariates

A covariate is used only when it is in both past and future. static is one row and does not need future. This example needs chronos_2. Stop the starter server and restart with the chronos image:

docker run --rm -p 8000:8000 sktime/tserve:chronos chronos_2
import pandas as pd
from tserve.client import Client

past = pd.DataFrame(
    {
        "month": pd.date_range("2024-01-01", periods=5, freq="MS"),
        "sales": [120, 135, 128, 142, 150],
        "promo": [0, 1, 0, 0, 1],
    }
)
future = pd.DataFrame(
    {
        "month": pd.date_range("2024-06-01", periods=3, freq="MS"),
        "promo": [1, 0, 0],
    }
)
static = pd.DataFrame({"store_type": ["urban"]})

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        future=future,
        static=static,
        time="month",
        target=["sales"],
        fh=3,
        model="chronos_2",
    )

print(result.predictions)

Rules: Future and static data. The forecast timestamps are the next fh steps after the last past row. future has to cover those steps; it does not choose different ones.

Request quantiles

Add quantiles when the loaded estimator supports quantile prediction. This example uses the compatible timesfm_2_5 model; Chronos Bolt and TTM do not support quantiles:

from tserve.client import Client

past = {
    "month": [
        "2024-01-01",
        "2024-02-01",
        "2024-03-01",
        "2024-04-01",
        "2024-05-01",
    ],
    "sales": [120, 135, 128, 142, 150],
}

with Client("http://127.0.0.1:8000") as client:
    result = client.predict(
        past=past,
        time="month",
        target=["sales"],
        fh=3,
        model="timesfm_2_5",
        quantiles=[0.1, 0.5, 0.9],
    )

print(result.predictions)
print(result.quantiles)

predictions remains the point forecast. Many estimators name quantile columns {target}_{level} (sales_0.1, sales_0.5, sales_0.9). timesfm_2_5 currently uses a positional prefix (0_0.1, 0_0.5, 0_0.9).

Handle errors

Local checks raise Pydantic ValidationError before any HTTP call. Server responses with status 400 or higher become RuntimeError. Connection and timeout failures raise httpx2.RequestError (import httpx2; the PyPI package httpx is a different module).

See Errors for the messages each case produces.