Skip to content

Commit 6a3acd3

Browse files
refactor!: Use uv to install python virtual env (#353)
#### Description of changes Uses `uv` rather than `pip` to install the virtual environment in the docker image. This should be transparent to users: the virtual environment created at the end is the same. On a test tesseract build, I observed the installation of dependencies into the virtual env speed up by ~6x. There's another case I've run into where pip is actually unable to resolve the dependencies and gets stuck; I've been using this branch to get around that. I referred to the following documentation page when making this change: https://docs.astral.sh/uv/guides/integration/docker/ #### Testing done - Added an example tesseract containing a custom `pip install` build step and corresponding test case - Manual testing: I've been using this patch for my own tesseract builds for about a month, and seen no issues. --------- Co-authored-by: Alessandro Angioi <alessandro.angioi@simulation.science>
1 parent 4ac4740 commit 6a3acd3

File tree

7 files changed

+66
-7
lines changed

7 files changed

+66
-7
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2025 Pasteur Labs. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from pydantic import BaseModel, Field
5+
6+
7+
class InputSchema(BaseModel):
8+
name: str = Field(description="Name of the person you want to greet.")
9+
10+
11+
class OutputSchema(BaseModel):
12+
greeting: str = Field(description="A greeting!")
13+
14+
15+
def apply(inputs: InputSchema) -> OutputSchema:
16+
"""Greet a person whose name is given as input."""
17+
return OutputSchema(greeting=f"Hello {inputs.name}!")
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: "helloworld"
2+
version: "1.0.0"
3+
description: "A sample Python app"
4+
5+
build_config:
6+
# Base image to use for the container, must be Ubuntu or Debian-based
7+
# base_image: "debian:bookworm-slim"
8+
9+
# Platform to build the container for. In general, images can only be executed
10+
# on the platform they were built for.
11+
# target_platform: "native"
12+
13+
# Additional packages to install in the container (via apt-get)
14+
# extra_packages:
15+
# - package_name
16+
17+
# Data to copy into the container, relative to the project root
18+
# package_data:
19+
# - [path/to/source, path/to/destination]
20+
21+
# Additional Dockerfile commands to run during the build process
22+
custom_build_steps:
23+
- RUN pip install numpy
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Add Python requirements like this:
2+
# numpy==1.18.1
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
torch --index-url https://download.pytorch.org/whl/cpu
1+
--index-url https://download.pytorch.org/whl/cpu
2+
torch

tesseract_core/sdk/templates/Dockerfile.base

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ FROM {{ config.build_config.base_image }} AS build_stage
55
FROM --platform={{ config.build_config.target_platform }} {{ config.build_config.base_image }} AS build_stage
66
{% endif %}
77

8+
# Obtain uv and companions
9+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
10+
11+
ENV UV_LINK_MODE=copy
12+
813
# Install Python if necessary
914
RUN if [ ! -x "$(command -v python3)" ]; then \
1015
apt-get update && apt-get install -y --no-install-recommends \
@@ -40,7 +45,7 @@ COPY local_requirements/ ./local_requirements
4045

4146
# Build a python venv from python provider build scripts.
4247
# The build script has to create a venv at /python-env
43-
RUN {% if use_ssh_mount %}--mount=type=ssh{% endif %} bash {{ config.build_config.requirements._build_script }}
48+
RUN --mount=type=cache,target=/root/.cache/uv {% if use_ssh_mount %}--mount=type=ssh{% endif %} bash {{ config.build_config.requirements._build_script }}
4449
ENV PATH="/python-env/bin:$PATH"
4550

4651
# Stage 2: Set up runtime environment

tesseract_core/sdk/templates/build_pip_venv.sh

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
set -e # Exit immediately if a command exits with a non-zero status
44

5-
python3 -m venv /python-env
6-
7-
# Activate virtual environment
5+
uv venv /python-env
86
source /python-env/bin/activate
97

108
# Collect dependencies
@@ -14,7 +12,7 @@ TESSERACT_DEPS=$(find ./local_requirements/ -mindepth 1 -maxdepth 1 2>/dev/null
1412
TESSERACT_DEPS+=" -r tesseract_requirements.txt"
1513

1614
# Install dependencies
17-
pip install $TESSERACT_DEPS
15+
uv -v pip install --compile-bytecode $TESSERACT_DEPS
1816

1917
# HACK: If `tesseract_core` is part of tesseract_requirements.txt, it may install an incompatible version
2018
# of the runtime from PyPI. We remove the runtime folder and install the local version instead.
@@ -23,4 +21,7 @@ if [ -d "$runtime_path" ]; then
2321
rm -rf "$runtime_path"/runtime
2422
fi
2523

26-
pip install ./tesseract_runtime
24+
uv -v pip install --compile-bytecode ./tesseract_runtime
25+
26+
# Install pip itself into the virtual environment for use by any custom build steps
27+
uv pip install pip

tests/endtoend_tests/test_examples.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ class Config:
107107
),
108108
],
109109
),
110+
"pip_custom_step": Config(
111+
test_with_random_inputs=True,
112+
sample_requests=[
113+
SampleRequest(
114+
endpoint="apply",
115+
payload={"inputs": {"name": "Ozzy"}},
116+
output_contains_pattern="Hello Ozzy!",
117+
),
118+
],
119+
),
110120
"pyvista-arm64": Config(
111121
test_with_random_inputs=True,
112122
sample_requests=[

0 commit comments

Comments
 (0)