Installing dependencies from a lockfile

View on GitHub

Context

Instead of a flat tesseract_requirements.txt, a Tesseract can install its dependencies from a PEP 751 lockfile (pylock.toml). A lockfile pins every dependency’s exact version, source index, and artifact hashes, so installing it performs no dependency resolution. The lockfile is used both for the environment Tesseract.from_source builds and for container images built with tesseract build.

Point the Tesseract at a lockfile with requirements_file in tesseract_config.yaml:

name: "pylock"
version: "0.1.0"
description: |
  Tesseract whose dependencies are installed from a PEP 751 lockfile
  (build_config.requirements.requirements_file: pylock.toml) instead of a flat
  tesseract_requirements.txt. The committed pylock.toml spans two indexes (PyPI
  for numpy, the PyTorch CPU index for torch) with platform markers.

  See README.md for how to regenerate the lockfile from _pyproject.toml.

build_config:
  requirements:
    provider: uv-pip
    requirements_file: pylock.toml

Any PEP 751 filename is accepted, either pylock.toml or a named variant like pylock.prod.toml. The format is inferred from the name.

If you already have a pyproject.toml (or a uv.lock), export a lockfile with uv export:

$ uv export --format pylock.toml -o pylock.toml

Example Tesseract

The example computes a sum with torch and passes it through numpy, so both packages from the committed lockfile must be installed and importable for apply to succeed:

# Copyright 2025 Pasteur Labs. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

from pydantic import BaseModel

#
# Schemas
#


class InputSchema(BaseModel):
    a: float
    b: float


class OutputSchema(BaseModel):
    # Sum computed with torch and passed through numpy, so both packages from the
    # committed pylock.toml must be installed and importable for apply to succeed.
    result: float


#
# Required endpoints
#


def apply(inputs: InputSchema) -> OutputSchema:
    import numpy as np
    import torch

    total = torch.tensor(inputs.a) + torch.tensor(inputs.b)
    return OutputSchema(result=float(np.asarray(total).item()))

Then run it as usual:

>>> from tesseract_core import Tesseract
>>> with Tesseract.from_source("examples/pylock/tesseract_api.py") as t:
...     print(t.apply({"a": 2.0, "b": 3.0}))
{'result': 5.0}

Or package it as a container image:

$ tesseract build examples/pylock
$ tesseract run pylock apply '{"inputs": {"a": 2.0, "b": 3.0}}'
{"result":5.0}

The Tesseract runtime is installed on top

Warning

The lockfile is installed first, then the Tesseract runtime and its dependencies are installed into the same environment. If a runtime dependency requires a version outside the range your lockfile pins, that package is adjusted to satisfy the runtime, so a handful of packages in the final environment may differ from the lockfile. Everything else is installed exactly as pinned. Keep this in mind if you rely on the environment or image matching the lockfile byte-for-byte.

Private and multi-index lockfiles

A lockfile records each package’s index location and hashes, but never credentials. To install from an authenticated index (a private PyPI, an Azure Artifacts feed, etc.) in a container build, declare the host under build_config.host_credentials and supply the token at build time with tesseract build --secret. Tesseract.from_source ignores host_credentials and installs with uv using your own credentials (for example ~/.netrc, a keyring, or UV_INDEX_* environment variables).