Skip to main content

Install

Hollerith is not on PyPI. It is served as a wheel from your own deployment’s origin under /sdk/, and the console Quickstart tab shows the exact current URL. The package requires Python 3.11 or 3.12. It depends on httpx>=0.27, numpy>=1.26 and pandas>=2.2.

Configure

Those are the only two environment variables the SDK reads. Both are required unless you pass api_key= and base_url= to the constructor.
__version__ is derived from the git tag the wheel was built at, so it names the commit you installed. In an unbuilt source tree with no installed metadata it reads '0+unknown'.

Hollerith

Only api_key is positional. Everything else is keyword-only. base_url has no default. If neither the argument nor HOLLERITH_BASE_URL is set, the constructor raises a plain ValueError — not a HollerithError, so an except HollerithError block will not catch it. The key is resolved first. A missing key therefore raises AuthenticationError(code="missing_api_key") before the base_url check ever runs.

Shared keyword arguments

These five recur across most methods, with two exceptions to hold on to. fit does not take on_progress, and FitHandle.wait() retries a warming worker only when you pass on_warming. on_warming is called with one argument — the ServiceUnavailableError that was swallowed. A hook written as lambda: print("warming") raises TypeError on the first cold start.
on_progress is accepted by predict, predict_proba, evaluate, forecast and both handles’ wait(). It is not accepted by fit, which passes only on_warming down to the fit handle.

fit

Pass either fit(df, target="col") or fit(X, y). Passing both raises ValueError, and passing neither raises ValueError. Returns self when wait=True, so you can chain. Returns a FitHandle when wait=False.
  • The task is inferred from the target unless you override it. A non-numeric or boolean target is classification, and so is an integral numeric target with 20 or fewer distinct values.
  • Classification reads at most 160 distinct labels. A 161st raises ValidationError (dataset_too_large) client-side, before anything is uploaded.
  • The 5,000,000,000-byte compressed upload ceiling is not checked locally. An oversize payload is serialized and gzipped, then rejected at the presign step with payload_too_large. Nothing reaches storage.
Two things wait=False changes:
  • No context is bound. fitted_context_id_ stays None and the next predict re-uploads the whole training table inline.
  • evaluate=True is silently dropped. The early return happens before the evaluation is started. There is no error and no warning.
Raises ValidationError for a missing target column (missing_target_column), an all-null target (unsupported_task), no feature columns (schema_mismatch), an empty frame (malformed_csv) or any limit breach (dataset_too_large). It raises ValueError for the calling-convention mistakes above, TimeoutError on deadline, and the typed HollerithError for the code the fit job failed with.

predict

A DataFrame must carry every column named in feature_names_in_; extra columns are dropped and the rest are reordered to match. An array-like is assumed to be in the fitted column order. Returns a plain Python list when wait=True and quantiles is None. Not an ndarray, not a Series — preds[0] is the label or number for the first row.
With quantiles=, it returns a pandas.DataFrame with a prediction column holding the mean, plus one column per level the engine scored.
The quantile column labels are strings. frame[0.1] raises KeyError; you have to index with "0.1". With wait=False you get a PredictionHandle in every case, including with quantiles=. The handle’s result carries .quantiles and .quantile_levels as raw lists, and no DataFrame is ever assembled for you. Raised before anything is submitted:
  • RuntimeError("call fit() or Hollerith.from_fitted_context() before predict()") when nothing is fitted.
  • ValueError when quantiles is passed for a classification task.
  • ValidationError for rows missing a fitted feature column or of the wrong width (schema_mismatch), an empty frame (malformed_csv), or more than 200,000 rows (dataset_too_large).
Raised while waiting:
  • TimeoutError on the deadline.
  • NotFoundError (training_ref_expired) if the job was purged before its result was read.
  • The typed HollerithError carried by a failed job.

predict_proba

Returns a numpy.ndarray of shape (n_rows, n_classes) and dtype float64. Columns are ordered by classes_, so proba[:, clf.classes_.index("fraud")] is one label’s column. This method always blocks. There is no wait=False. It overwrites classes_ with the engine’s ordering before returning, so the array and the attribute stay aligned. Read classes_ after the call, not before. Raises ValueError("predict_proba is only available for classification") for a regression task, plus everything predict raises.

evaluate

Takes no positional arguments. It re-sends the labeled training table, label column included, and the service splits it and scores it. The whole table is re-checked before the upload, against 1,000,000 rows, 2,000 columns, 100,000,000 cells and 160 classes. A breach raises ValidationError (dataset_too_large). Returns an EvaluationResult, a frozen dataclass, and also stores it on evaluation_.
Raises RuntimeError("call fit() before predict()") if fit was never called on this client. A client built by from_fitted_context has no training table in memory, so it can never evaluate. It otherwise raises the same set as predict: ValidationError on a limit breach, TimeoutError on deadline, NotFoundError on a purged job, and the typed error a failed job carried.

submit

Uploads the payload, enqueues one prediction job, and returns its handle without polling. This is what predict(wait=False) calls. At most 200,000 scored rows, checked client-side before the upload. A breach raises ValidationError (dataset_too_large). Returns a PredictionHandle. It raises the same submit-time errors as predictRuntimeError, ValueError for classification quantiles, and ValidationError for a schema or limit problem.

forecast

Pass exactly one of prediction_length or future. Every column that is not the timestamp, target or series column is treated as a covariate. Returns a pandas.DataFrame with a mean column plus one string-labelled column per quantile level. A single series is indexed by timestamp; with item_id= the index is a MultiIndex of (item_id, timestamp), and the timestamp level is datetime-typed either way.
  • Output rows are capped at 200,000. They are counted as prediction_length × series count, or as len(future) when you pass a future frame.
  • Covariate columns are capped at 2,000.
  • No fit is involved. forecast never uses a fitted context, so nothing about fit-once, predict-many applies to it.
It raises TypeError if context or future is not a DataFrame, and ValueError for a horizon that is not exactly one of the two options, a non-positive prediction_length, a quantile outside (0, 1), a missing timestamp or target column, or a future frame missing a covariate.

from_fitted_context

The other arguments are the constructor’s and mean the same thing. There is no server_context argument here, because a resumed client is context-backed by definition. This is a network call. It fetches the context, checks its status, and binds its schema onto the new client. Returns a Hollerith with feature_names_in_, n_features_in_, n_rows_in_, target_name_, task_, fitted_context_id_ and fitted_context_expires_at_ already set.
  • Raises NotFoundError if the context is not ready. The code is fitted_context_expired when its status is expired or deleted, and fitted_context_not_found for any other non-ready status.
  • Contexts live for 7 days. After that, fit again — there is no way to extend one.

fitted

A read-only property. It is True once fit has staged a training table or a context is bound, and False on a fresh client.

Instance attributes

sklearn convention: a trailing underscore means the attribute appears as a result of fitting, not at construction. Reading one before it is set raises AttributeError. Two of these surprise people.
  • A resumed client has no classes_. from_fitted_context binds the schema, which does not carry the label set. The attribute appears the first time predict_proba runs.
  • predict_proba overwrites classes_. It replaces the sorted list from fit with the engine’s ordering, so the probability columns and the labels stay aligned.
fitted_context_id_ is a raw document id. It carries no ctx_ prefix and you should treat it as opaque. Use hasattr(clf, "evaluation_") to test for an evaluation. It is False after a plain fit, and False after fit(evaluate=True, wait=False).

PredictionHandle

Returned by submit() and by predict(wait=False).
wait() blocks to a terminal state and returns a PredictionResult.

PredictionResult

What a finished prediction job scored. It carries predictions, task, classes, probabilities, quantiles and quantile_levels, and fields the task did not produce are None. predictions is row-aligned with the rows you submitted. classes is the label order the engine used, which is what makes probabilities interpretable.

PredictionJob

The status view you get from handle.job, handle.refresh() and every on_progress call. It is a frozen dataclass of hashes and counts, never data. It carries id, status, task, train_rows, output_rows, cols, target_column, engine_version, created_at, duration_ms, input_hash and error. It also exposes rows, the sum of train_rows and output_rows.

FitHandle

Returned by fit(wait=False).
FitHandle.wait() takes no on_progress. It returns the FittedContext once its status is ready, and raises the context’s typed error otherwise.
  • Waiting does not bind the context to your client. To predict against a context you polled yourself, pass its id to from_fitted_context.
  • FitHandle.wait() only retries a warming worker when you pass on_warming. Without the hook, a retryable ServiceUnavailableError propagates instead of being waited out. PredictionHandle.wait() retries either way.

FittedContext

The server-side artifact a fit produces, read through FitHandle.context or FitHandle.refresh(). It carries id, status, task, train_rows, cols, target_column, feature_columns, engine_version, artifact_schema_version, train_hash, artifact_hash, created_at, expires_at, last_used_at, created_by_job_id and error, plus a done property.

read_csv and read_csv_text

The reader is forgiving about form and strict about structure. It sniffs the delimiter from the header line among comma, tab, semicolon and pipe, with comma winning ties.
  • Encoding is resolved from the byte-order mark first, which pins UTF-8 or UTF-16 unambiguously. With no mark it tries UTF-8, then Windows-1252, and stops there rather than silencing a real encoding problem.
  • Blank lines are dropped. A row of empty fields is kept and width-checked, and line numbers stay correct across quoted multiline fields.
Every column comes back as Python str. No dtype inference is performed, which means a numeric target read this way infers as classification. Cast the columns you need, or pass task="regression" to fit.

CSV parse errors

Every failure raises ValidationError with code malformed_csv, and the problem field names the 1-based source line or the column position at fault. Dataset contents never appear in the message — only structure.
  • Ragged rowLine 3 has 2 fields but the header defines 3 columns.
  • Duplicate header name — names the repeated column.
  • Blank header name — names the 1-based column position.
  • Empty input, or a header with no data rows.
  • Undecodable bytes — names the byte position that failed under UTF-8.
  • Unreadable path — a missing file or a permissions problem, not an OSError.

Exceptions

There are nine classes: HollerithError and eight subclasses, one per error category. Catch a subclass to handle one category, or HollerithError to handle them all.

Exception attributes

Every instance carries the same seven attributes. str(err) renders the problem followed by indented Cause, Fix, Docs and Request lines, so printing a caught error gives a readable report. The category selects the class; the code is what you branch on. The full catalogue of codes, their HTTP statuses and which four are retryable is in Errors.
  • Three exceptions are not HollerithError at all. ValueError covers calling mistakes, TypeError a wrongly typed forecast frame, and TimeoutError a lapsed deadline.
  • There is no backoff-retry layer. The SDK retries a retryable ServiceUnavailableError inside the poll loop at a fixed poll_interval, and nothing else.

Also exported

The names above are what most code touches. hollerith.__all__ carries more, and these are supported.
  • Ingest and inference helpersinfer_task, prepare_training_data, TrainingData, Task.
  • Request dataclassesPredictionRequest, FitRequest, ContextPredictionRequest, EvaluationRequest, ForecastRequest. The views they return are documented above.
  • Transport seamTransport, the protocol you implement to substitute one, and HttpTransport, the HTTPS implementation.
  • Config helpersresolve_api_key, API_KEY_ENV_VAR, BASE_URL_ENV_VAR.
  • Error helperserror_from_payload builds the typed exception for a wire envelope, and raise_for_payload raises it.

Checklist

  • Set HOLLERITH_API_KEY and HOLLERITH_BASE_URL, or pass both to the constructor.
  • Check task_ after fit if your target is numeric and low-cardinality.
  • Index quantile columns with strings: frame["0.5"], never frame[0.5].
  • Read classes_ after predict_proba, not before.
  • Give on_warming one parameter.
  • Persist fitted_context_id_ if you want to resume, and re-fit after 7 days.

Next