Python API reference
Most names import from the top-level package: from paperlab_space import run. Each entry shows its import path.
Running
Run an evaluation and estimate its cost.
run
from paperlab_space import run
def run(
config: RunConfig,
data: Dataset | MappedDataset | None = None,
*,
backend: Backend | None = None,
on_progress: ProgressCallback | None = None,
previous: RunResults | None = None,
checkpoint: str | Path | None = None,
) -> RunResultsRun an evaluation and return outputs and scores.
Works in scripts and in Jupyter (where an event loop is already running).
See arun for the arguments.
arun
from paperlab_space import arun
async def arun(
config: RunConfig,
data: Dataset | MappedDataset | None = None,
*,
backend: Backend | None = None,
on_progress: ProgressCallback | None = None,
previous: RunResults | None = None,
checkpoint: str | Path | None = None,
sleep: Sleep = asyncio.sleep,
clock: Clock = time.monotonic,
) -> RunResultsRun an evaluation asynchronously.
Arguments
config: What to run.data: The data. If omitted, it is loaded fromconfig.dataset. A plainDatasetis mapped withconfig.mapping.backend: Where to send requests. Defaults toLiteLLMBackend.on_progress: Called after each row finishes.previous: Results of an earlier, interrupted run with the same config. Rows that already have an output are reused instead of requested again.checkpoint: Aresults.jsonpath to save finished rows to while the run goes, and when it stops early (Ctrl+C, an error). Pass the file aspreviousto continue. When the run finishes, the full results are written there.sleep, clock: Injection points for tests.
estimate
from paperlab_space import estimate
def estimate(
config: RunConfig,
data: Dataset | MappedDataset,
*,
backend: Backend | None = None,
latency_s: float = 3.0,
) -> EstimateEstimate tokens, cost, and wall time for each model.
Token counts use a script-aware heuristic, not the model's tokenizer, so treat them
as ballpark figures. latency_s is the assumed time per request.
Estimate
from paperlab_space.runner import Estimate
Estimate(models: list[ModelEstimate])| Attribute | Type | Default | Description |
|---|---|---|---|
models | list[ModelEstimate] | required |
Properties
cost_usd(float | None)minutes(float): Models run in parallel, so the slowest one sets the total.
Progress
from paperlab_space import Progress
Progress(
model: str,
done: int,
failed: int,
total: int,
record_id: str,
row: RowOutput | None = None,
)A progress update, sent after each row finishes.
| Attribute | Type | Default | Description |
|---|---|---|---|
model | str | required | The model's label. |
done | int | required | Rows finished for this model, successful or not. |
failed | int | required | Rows that failed so far for this model. |
total | int | required | Rows to run for this model. |
record_id | str | required | The row that just finished. |
row | RowOutput | None | None | Its output, so callers can checkpoint partial results (see previous in arun). |
LiteLLMBackend
from paperlab_space import LiteLLMBackend
LiteLLMBackend(
api_keys: Mapping[str, str] | None = None,
api_bases: Mapping[str, str] | None = None,
)Calls models through LiteLLM.
API keys are read from the usual environment variables (OPENROUTER_API_KEY,
GEMINI_API_KEY, OPENAI_API_KEY, ...) unless passed in api_keys, keyed by
provider prefix (e.g. {"openrouter": "sk-or-..."}). Keys are never stored in the
run config or results.
complete
async def complete(
model: ModelSpec,
messages: Messages,
*,
seed: int | None,
timeout: float,
) -> Completionprice
def price(model: ModelSpec) -> tuple[float, float] | NoneConfiguration
The run config and its parts. See the config file reference for the YAML form.
RunConfig
from paperlab_space import RunConfigEverything needed to run (and re-run) an evaluation.
| Attribute | Type | Default | Description |
|---|---|---|---|
dataset | DatasetSpec | None | None | Where to load the data from. Optional when the data is passed to run directly. |
mapping | ColumnMapping | required | Which columns are inputs, context, the answer key, and the row ID. |
prompt | PromptTemplate | required | The prompt template: a string, or an object with user and system. |
models | list[ModelSpec] | required | Models to evaluate, as IDs or objects with options. |
metrics | list[MetricSpec] | [] | Metrics to compute, as names or objects with options. Empty collects outputs only. |
seed | int | None | None | Default seed for models that do not set their own. |
concurrency | int | 4 | Parallel requests per model (rate limits still apply). |
retry | RetrySettings | RetrySettings() | Retry and timeout settings. |
model_seed
def model_seed(model: ModelSpec) -> int | Nonefrom_dict (classmethod)
def from_dict(data: dict[str, Any]) -> RunConfigBuild from a dict; also accepts a reproducibility file (config under config).
from_yaml (classmethod)
def from_yaml(path: str | Path) -> RunConfigLoad a YAML config. A relative dataset path is resolved against the file's folder.
to_dict
def to_dict() -> dict[str, Any]to_yaml
def to_yaml(path: str | Path | None = None) -> strModelSpec
from paperlab_space import ModelSpecA model to evaluate, addressed by its LiteLLM ID (provider/model).
| Attribute | Type | Default | Description |
|---|---|---|---|
id | str | required | LiteLLM model ID with its provider prefix, e.g. gemini/gemini-3.5-flash. |
label | str | None | None | Display name in tables. Defaults to the model ID without the provider prefix. |
temperature | float | 0.0 | Sampling temperature. 0 gives the most repeatable outputs. |
max_tokens | int | None | None | Cap on output tokens per response. |
top_p | float | None | None | Nucleus sampling cutoff. |
seed | int | None | None | Overrides the run-level seed for this model. |
requests_per_minute | float | None | None | Override the default rate limit for this model. |
concurrency | int | None | None | Override the run-level number of parallel requests for this model. |
params | dict[str, Any] | {} | Extra provider parameters passed through to LiteLLM. |
Properties
provider(str)name(str): The label used in outputs.
MetricSpec
from paperlab_space import MetricSpecA metric name plus its options, e.g. {"name": "exact_match", "ignore_case": false}.
| Attribute | Type | Default | Description |
|---|---|---|---|
name | str | required | A registered metric name; paperlab-space metrics lists them. |
label | str | None | None | Column name in outputs; needed to use the same metric twice with different options. |
params | dict[str, Any] | {} | Metric options such as labels or ignore_case. In YAML they can also sit next to name. |
Properties
key(str)
DatasetSpec
from paperlab_space import DatasetSpecWhere the data comes from. Optional when the dataset is passed in directly.
| Attribute | Type | Default | Description |
|---|---|---|---|
path | str | required | Data file. A relative path is resolved against the config file's folder. |
sheet | str | int | None | None | Excel sheet name or zero-based index. Defaults to the first sheet. |
RetrySettings
from paperlab_space import RetrySettingsHow failed requests are retried, and how long to wait for a response.
| Attribute | Type | Default | Description |
|---|---|---|---|
max_attempts | int | 5 | Tries per row, including the first. |
base_delay | float | 2.0 | Seconds before the first retry; doubles on each attempt. |
max_delay | float | 60.0 | Upper bound on the wait between retries, in seconds. |
timeout | float | 120.0 | Seconds to wait for one model response. |
ColumnMapping
from paperlab_space import ColumnMappingWhich columns are inputs, extra context, the expected answer, and the row ID.
Input and context columns become variables in the prompt template. The expected column is never exposed to the prompt, so answers cannot leak into it.
| Attribute | Type | Default | Description |
|---|---|---|---|
input | list[str] | required | Columns available to the prompt template. One name or a list. |
context | list[str] | [] | More columns available to the prompt, such as metadata. |
expected | str | None | None | The answer key that outputs are scored against. Never available to the prompt. |
id | str | None | None | A stable row ID. Defaults to the 1-based row number. |
answer_delimiter | str | None | None | Split the expected cell on this string to allow several valid answers, e.g. "|". |
Properties
fields(list[str]): Columns available to the prompt template.used_columns(list[str])
PromptTemplate
from paperlab_space import PromptTemplate
PromptTemplate(user: str | None = None, /, **data: Any)A user prompt (and optional system prompt) with column placeholders.
>>> PromptTemplate(user="Translate to English: {sentence}").render({"sentence": "สวัสดี"})
[{'role': 'user', 'content': 'Translate to English: สวัสดี'}]| Attribute | Type | Default | Description |
|---|---|---|---|
user | str | required | The user message, with {column} placeholders. |
system | str | None | None | An optional system message, with the same placeholders. |
Properties
variables(list[str]): Placeholder names in order of first appearance (user prompt, then system).
check
def check(columns: Iterable[str]) -> NoneRaise TemplateError if a placeholder is not one of columns.
render
def render(fields: Mapping[str, str | None]) -> list[dict[str, str]]Fill the template and return chat messages. Empty cells become empty strings.
Data
Load, map, and validate spreadsheet data.
load_dataset
from paperlab_space import load_dataset
def load_dataset(path: str | Path, sheet: str | int | None = None) -> DatasetLoad an .xlsx or .csv/.tsv file.
The first non-empty row is used as the header. Fully empty rows are dropped.
Arguments
path: File to load.sheet: Excel sheet name or zero-based index. Defaults to the first sheet. Ignored for CSV files.
list_sheets
from paperlab_space import list_sheets
def list_sheets(path: str | Path) -> list[str]Return the sheet names of an Excel file (a CSV file has a single unnamed sheet).
Dataset
from paperlab_space import Dataset
Dataset(
columns: list[str],
rows: list[Row],
source: str | None = None,
sheet: str | None = None,
sha256: str | None = None,
encoding: str | None = None,
warnings: list[str] = [],
)A rectangular table of string cells with named columns.
| Attribute | Type | Default | Description |
|---|---|---|---|
columns | list[str] | required | |
rows | list[Row] | required | |
source | str | None | None | |
sheet | str | None | None | |
sha256 | str | None | None | |
encoding | str | None | None | |
warnings | list[str] | [] |
column
def column(name: str) -> list[str | None]Return all values of one column.
map
def map(mapping: ColumnMapping) -> MappedDatasetApply a column mapping, producing records ready for prompting and scoring.
from_records (classmethod)
def from_records(
records: Sequence[dict[str, Any]],
source: str | None = None,
) -> DatasetBuild a dataset from a list of dicts (column order follows first appearance).
MappedDataset
from paperlab_space import MappedDataset
MappedDataset(
records: list[Record],
mapping: ColumnMapping,
dataset: Dataset,
)A dataset with a column mapping applied, ready for prompting and scoring.
| Attribute | Type | Default | Description |
|---|---|---|---|
records | list[Record] | required | |
mapping | ColumnMapping | required | |
dataset | Dataset | required | The unmapped data. |
Properties
has_answer_key(bool)
from_dataset (classmethod)
def from_dataset(dataset: Dataset, mapping: ColumnMapping) -> MappedDatasetvalidate
def validate() -> ValidationReportCheck the data for empty cells, duplicate IDs, and encoding problems.
preview
def preview(n: int = 5) -> list[dict[str, Any]]The first n records as JSON-ready dicts.
to_jsonl
def to_jsonl(path: str | Path | None = None) -> strSerialise all records as JSON Lines (UTF-8, non-ASCII kept as-is).
Record
from paperlab_space.data import Record
Record(
id: str,
fields: dict[str, str | None],
expected: list[str] | None,
row_number: int,
)One evaluation example.
| Attribute | Type | Default | Description |
|---|---|---|---|
id | str | required | The row ID, or the row number if the mapping has no ID column. |
fields | dict[str, str | None] | required | Input and context values by column name. |
expected | list[str] | None | required | Valid answers, or None without an answer key entry. |
row_number | int | required | 1-based position among the data rows (header excluded). |
to_json
def to_json() -> dict[str, Any]ValidationReport
from paperlab_space.data import ValidationReport
ValidationReport(issues: list[Issue], n_records: int)The result of validating mapped data.
| Attribute | Type | Default | Description |
|---|---|---|---|
issues | list[Issue] | required | |
n_records | int | required |
Properties
ok(bool):Trueif there are no errors (warnings are allowed).errors(list[Issue])warnings(list[Issue])
Issue
from paperlab_space.data import Issue
Issue(
level: Level,
code: str,
message: str,
rows: list[int] = [],
column: str | None = None,
)One problem found in the data.
| Attribute | Type | Default | Description |
|---|---|---|---|
level | Level | required | "error" blocks a run; "warning" does not. |
code | str | required | A stable identifier, e.g. empty_input or duplicate_id. |
message | str | required | |
rows | list[int] | [] | 1-based data row numbers (header excluded). |
column | str | None | None | The column the problem is in, if any. |
Results
What a run returns.
RunResults
from paperlab_space import RunResults
RunResults(
config: RunConfig,
data: MappedDataset,
runs: dict[str, ModelRun],
scores: dict[str, dict[str, MetricResult]] = {},
started_at: str | None = None,
finished_at: str | None = None,
environment: dict[str, str] = ...,
)Everything a run produced: outputs, scores, and the config and data behind them.
| Attribute | Type | Default | Description |
|---|---|---|---|
config | RunConfig | required | |
data | MappedDataset | required | The data the run used, with the mapping applied. |
runs | dict[str, ModelRun] | required | Model name -> outputs, in config order. |
scores | dict[str, dict[str, MetricResult]] | {} | Model name -> metric name -> result. |
started_at | str | None | None | ISO 8601 timestamp (UTC). |
finished_at | str | None | None | ISO 8601 timestamp (UTC). |
environment | dict[str, str] | ... | Python, paperlab-space, and LiteLLM versions. |
Properties
model_names(list[str])
output
def output(model: str, record_id: str) -> RowOutputto_dict
def to_dict() -> dict[str, Any]save_json
def save_json(path: str | Path) -> Nonefrom_dict (classmethod)
def from_dict(data: dict[str, Any]) -> RunResultsload_json (classmethod)
def load_json(path: str | Path) -> RunResultsModelRun
from paperlab_space import ModelRun
ModelRun(model: ModelSpec, rows: list[RowOutput])One model's outputs for every row.
| Attribute | Type | Default | Description |
|---|---|---|---|
model | ModelSpec | required | |
rows | list[RowOutput] | required | One output per data row, in data order. |
Properties
name(str)n_failed(int)cost_usd(float | None)input_tokens(int)output_tokens(int)model_versions(list[str])
RowOutput
from paperlab_space import RowOutput
RowOutput(
record_id: str,
output: str | None,
error: str | None = None,
attempts: int = 0,
latency_s: float | None = None,
input_tokens: int | None = None,
output_tokens: int | None = None,
cost_usd: float | None = None,
model_version: str | None = None,
)| Attribute | Type | Default | Description |
|---|---|---|---|
record_id | str | required | The ID of the data row. |
output | str | None | required | The model's answer, or None if every attempt failed. |
error | str | None | None | Why the request failed, if it did. |
attempts | int | 0 | Requests sent for this row, including retries. |
latency_s | float | None | None | Seconds the successful request took. |
input_tokens | int | None | None | |
output_tokens | int | None | None | |
cost_usd | float | None | None | Cost in USD, if the provider's price is known. |
model_version | str | None | None | The exact model name the provider reported. |
Properties
ok(bool)
MetricResult
from paperlab_space import MetricResult
MetricResult(
name: str,
value: float | None,
per_row: list[float | None] | None = None,
extra: dict[str, float] = {},
n_scored: int = 0,
higher_is_better: bool = True,
)The score of one metric for one model.
| Attribute | Type | Default | Description |
|---|---|---|---|
name | str | required | The metric's key: its label, or its name. |
value | float | None | required | The headline number (None if no row could be scored). |
per_row | list[float | None] | None | None | Row-level scores aligned with the dataset records, if the metric has them. |
extra | dict[str, float] | {} | Secondary numbers, e.g. precision and recall next to F1. |
n_scored | int | 0 | Rows that counted towards the score. |
higher_is_better | bool | True |
Metrics
Score results and add your own metrics. See Custom metrics.
score
from paperlab_space import score
def score(results: RunResults) -> dict[str, dict[str, MetricResult]]Compute every configured metric for every model in results.
available_metrics
from paperlab_space import available_metrics
def available_metrics() -> dict[str, type[Metric]]register
from paperlab_space import register
def register(cls: type[Metric]) -> type[Metric]Class decorator that makes a metric available by name in run configs.
Metric
from paperlab_space.metrics import MetricBase class for metrics. Subclasses declare their options as __init__ arguments.
| Attribute | Type | Default | Description |
|---|---|---|---|
name | str | required | The name used in run configs. |
description | str | '' | One sentence, shown by paperlab-space metrics. |
requires_reference | bool | True | Whether the metric needs an expected-answer column. |
higher_is_better | bool | True | Which way is better, so the LaTeX table bolds the right score. |
compute
def compute(predictions: Predictions, references: References) -> MetricResultScore all rows of one model.
result
def result(value: float | None, **kwargs: Any) -> MetricResultNormalizer
from paperlab_space.metrics import Normalizer
Normalizer(
nfkc: bool = True,
ignore_case: bool = True,
trim_punctuation: bool = True,
ignore_punctuation: bool = False,
remove_articles: bool = False,
)How to normalise text before comparing a prediction to a reference.
Defaults suit short answers and labels: NFKC (so full-width ABC equals ABC),
case-insensitive, whitespace collapsed, and quotes/punctuation trimmed from the ends
(so "Positive." matches positive).
| Attribute | Type | Default | Description |
|---|---|---|---|
nfkc | bool | True | Apply Unicode NFKC, so full-width characters equal their ASCII forms. |
ignore_case | bool | True | Compare case-insensitively. |
trim_punctuation | bool | True | Strip punctuation and quotes from the start and end only. |
ignore_punctuation | bool | False | Remove all punctuation, including inside the text. |
remove_articles | bool | False | Remove English articles (a, an, the), as in SQuAD-style evaluation. |
tokenize
from paperlab_space.metrics import tokenize
def tokenize(text: str) -> list[str]Split on whitespace, and into single characters for scripts written without spaces between words (Chinese, Japanese, Thai, Lao, Khmer, Burmese, Tibetan).
Korean uses spaces between words, so Hangul is split on whitespace like Latin text.
extract_label
from paperlab_space.metrics import extract_label
def extract_label(text: str, labels: Sequence[str], normalize: Normalizer) -> strMap a free-form answer to one of labels.
Returns the matching label if the normalised answer equals one, or if exactly one label
appears in it ("The sentiment is positive." -> positive). Otherwise the
normalised answer is returned unchanged and will not match any label.
Export
Write results to files. from paperlab_space import export.
write_all
from paperlab_space.export import write_all
def write_all(results: RunResults, out_dir: str | Path) -> dict[str, Path]Write every export format into out_dir and return the paths by format.
write_excel
from paperlab_space.export import write_excel
def write_excel(results: RunResults, path: str | Path) -> PathWrite results to an .xlsx workbook with Summary, Outputs, and Config sheets.
write_latex
from paperlab_space.export import write_latex
def write_latex(results: RunResults, path: str | Path, **options: Any) -> PathWrite latex_table output to path. Options are passed through.
latex_table
from paperlab_space.export import latex_table
def latex_table(
results: RunResults,
*,
metrics: Sequence[str] | None = None,
caption: str | None = None,
label: str | None = 'tab:results',
decimals: int = 1,
percent: bool = True,
bold_best: bool = True,
floating: bool = True,
) -> strBuild a model-by-metric comparison table.
Arguments
metrics: Metric keys to include, in order. Defaults to all configured metrics.percent: Show scores in [0, 1] as percentages.bold_best: Bold the best score in each column (all of them on ties).floating: Wrap the tabular in atableenvironment with caption and label.
write_repro
from paperlab_space.export import write_repro
def write_repro(results: RunResults, path: str | Path) -> Pathreproducibility
from paperlab_space.export import reproducibility
def reproducibility(results: RunResults) -> dict[str, Any]Backends
Send requests somewhere other than LiteLLM. See Custom backends.
Backend
from paperlab_space.runner import BackendA protocol: any class with these methods works.
complete
async def complete(
model: ModelSpec,
messages: Messages,
*,
seed: int | None,
timeout: float,
) -> CompletionReturn one completion, raising RetryableError or ProviderError.
price
def price(model: ModelSpec) -> tuple[float, float] | NoneUSD per input token and per output token, or None if unknown.
Completion
from paperlab_space.runner import Completion
Completion(
text: str,
input_tokens: int | None = None,
output_tokens: int | None = None,
cost_usd: float | None = None,
model_version: str | None = None,
)One model response, as a backend returns it.
| Attribute | Type | Default | Description |
|---|---|---|---|
text | str | required | The model's answer. |
input_tokens | int | None | None | Prompt tokens, as reported by the provider. |
output_tokens | int | None | None | Output tokens, as reported by the provider. |
cost_usd | float | None | None | Cost in USD, if known. |
model_version | str | None | None | The exact model name reported by the provider, if any. |
RetryableError
from paperlab_space.runner import RetryableError
RetryableError(message: str, retry_after: float | None = None)A transient failure (rate limit, timeout, server error) worth retrying.
Subclass of PaperLabError.
ProviderError
from paperlab_space.runner import ProviderError
ProviderError(message: str, fatal: bool = False)A permanent failure for one request.
If fatal is true the problem affects every request to this model (bad API key,
unknown model), so the runner stops sending requests to it.
Subclass of PaperLabError.
Errors
Every error the package raises on purpose is a PaperLabError.
PaperLabError
from paperlab_space import PaperLabErrorBase class for all paperlab-space errors.
Subclass of Exception.
ConfigError
from paperlab_space import ConfigErrorA run configuration is invalid.
Subclass of PaperLabError.
DataError
from paperlab_space import DataErrorThe input data or column mapping is invalid.
Subclass of PaperLabError.
TemplateError
from paperlab_space import TemplateErrorA prompt template is invalid or references unknown columns.
Subclass of PaperLabError.