Installing local Python modules into a Tesseract¶
Context¶
Sometimes it might be necessary to bundle local Python modules into a Tesseract.
There are 2 ways to do this:
Make them a proper Python package with
pyproject.tomland add the local path to thetesseract_requirements.txtfile. Both absolute and relative paths work, but in case they are relative paths, they should be relative to the Tesseract’s root folder (i.e., the one which contains thetesseract_api.pyfile).Just put them as
.pyfiles next totesseract_api.pyand add them tobuild_config.package_data(see also [packagedata.md]) intesseract_config.yamlto make sure they’re being included in container builds.
Example Tesseract¶
Here is an example Tesseract that highlights both ways to include dependencies.
# Copyright 2025 Pasteur Labs. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
from goodbyeworld import ungreet
from helloworld import greet
from pydantic import BaseModel, Field
class InputSchema(BaseModel):
name: str = Field(description="Name of the person you want to greet.")
class OutputSchema(BaseModel):
message: str = Field(description="A message!")
def apply(inputs: InputSchema) -> OutputSchema:
"""Greets and ungreets a person whose name is given as input."""
message = f"{greet(inputs.name)}\n{ungreet(inputs.name)}"
return OutputSchema(message=message)
The custom package helloworld is shipped with a file helloworld.py and a pyproject.toml that ensures it can be built as a Python package.
# Copyright 2025 Pasteur Labs. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def greet(name):
return f"Hello {name}!"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "helloworld"
version = "0.1.0"
Then, it can be added as a local dependency to tesseract_requirements.txt by passing a relative path:
./helloworld
The local module goodbyeworld.py is just a single Python file:
# Copyright 2025 Pasteur Labs. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def ungreet(name):
return f"Goodbye {name}!"
To ensure it gets added to built Tesseracts, we have to register it as package_data:
name: "localpackage"
version: "0.0.1"
description: ""
build_config:
package_data:
- ["goodbyeworld.py", "goodbyeworld.py"]
Now we are ready to build the Tesseract. This Tesseract will accept a name like “Tessie” as an input and return a message:
$ tesseract build examples/localpackage
$ tesseract run localpackage apply '{"inputs": {"name": "Tessie"}}'
{"message":"Hello Tessie!\nGoodbye Tessie!"}
This confirms that both custom dependencies are available to the Tesseract container.
To run the Tesseract without containerization, we have to make sure that helloworld is installed into our dev environment:
$ pip install examples/localpackage/helloworld
$ TESSERACT_API_PATH=examples/localpackage/tesseract_api.py tesseract-runtime apply '{"inputs": {"name": "Tessie"}}'
{"message":"Hello Tessie!\nGoodbye Tessie!"}
Advanced pattern: injecting private dependencies as local wheels¶
In case a Tesseract depends on private packages that are not accessible from the public Python package index (PyPI), injecting them as local files can be a useful way to side-step authentication issues.
This is especially powerful in conjunction with pip download (e.g. from a private PyPI registry) to obtain a pre-built wheel:
$ pip download cowsay==6.1
Collecting cowsay==6.1
Obtaining dependency information for cowsay==6.1 from https://files.pythonhosted.org/packages/f1/13/63c0a02c44024ee16f664e0b36eefeb22d54e93531630bd99e237986f534/cowsay-6.1-py3-none-any.whl.metadata
Downloading cowsay-6.1-py3-none-any.whl.metadata (5.6 kB)
Downloading cowsay-6.1-py3-none-any.whl (25 kB)
Saved ./cowsay-6.1-py3-none-any.whl
Successfully downloaded cowsay
We can then specify it as a local dependency in tesseract_requirements.txt by adding the following line:
./cowsay-6.1-py3-none-any.whl
Finally, let’s build the Tesseract, and verify it works
$ tesseract build mytess
[i] Building image ...
[i] Built image sha256:7d024, ['mytess:latest']
$ tesseract run mytess apply '{"inputs": {"message": "Hello, World!"}}'
{"out":" _____________\n| Hello, World! |\n =============\n \\\n \\\n ^__^\n (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||"}