BentoML icon indicating copy to clipboard operation
BentoML copied to clipboard

feature: support for pylock.toml

Open pietermarsman opened this issue 4 months ago • 3 comments

Feature request

I would like it if BentoML also supports using pylock.toml to specify Python dependencies.

Motivation

The current options to specify Python dependencies have their limitations because it is impossible to easily configure per-dependency index urls.

  • Using bentoml.images.Image().python_packages()
    • will duplicate dependency specification (e.g. for the project in pyproject.toml, and for the bento the service).
    • does not support --extra-index-url. In other words, GPU acceleration with torch does not work.
  • Using bentoml.images.Image().requirements_file()
    • only supports --extra-index-url when specified in the file, but uv explicitly does not export these becuase requirements.txt is not powerful enough.
    • BentoML can add the --extra-index-url to the requirements.txt file on the fly, but this will apply to all packages.
    • BentoML can add pip_args to specify --index-strategy unsafe-best-match but these are added to the uv pip install. Maybe the documentation is outdated?
  • Using bentoml.images.Image().run() or run_script().
    • There is no way to copy artifacts (e.g. a requirements.txt, or pylock.toml) to the Docker before executing the run.

Hence, any situation where some package require conflicting --extra-index-url the current setup is not sufficient. I downgraded to bentoml<1.3 to fix this.

I think supporting pylock.toml will fix this, because it explicitly defines all the index urls.

Other

I'm creating this as a feature request, because I don't think there is a good solution based on requirements.txt. That will only work when specifying the index urls per package line, but uv is not going to do that.

pietermarsman avatar Sep 12 '25 09:09 pietermarsman

As an example, trying to install both torch and certifi fails because it tries to install the latter from the pytorch index.

pyproject.toml

[project]
name = "bentoml-index-example"
version = "0.1.0"
description = "Add your description here"
requires-python = ">=3.13"
dependencies = [
    "torch",
    "certifi",
    "bentoml",
]

[tool.uv.sources]
torch = [
    { index = "pytorch-cpu" },
]

[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true

requirements.txt

Generated with

uv export --prune bentoml --no-annotate --no-hashes -o requirements.txt
# This file was autogenerated by uv via the following command:
#    uv export --prune bentoml --no-annotate --no-hashes -o requirements.txt
certifi==2025.8.3
filelock==3.19.1
fsspec==2025.9.0
jinja2==3.1.6
markupsafe==3.0.2
mpmath==1.3.0
networkx==3.5
setuptools==80.9.0
sympy==1.14.0
torch==2.8.0 ; sys_platform == 'darwin'
torch==2.8.0+cpu ; sys_platform != 'darwin'
typing-extensions==4.15.0

service.py

import bentoml


@bentoml.service()
class Service:

    @bentoml.api
    def predict(self) -> dict:
        return {}

bentofile.yaml

python:
  requirements_txt: "requirements.txt"
  lock_packages: false
  extra_index_url:
    - "https://download.pytorch.org/whl/cpu"
  pip_args: "--index-strategy unsafe-best-match"

Note that without specifying the extra_index_url in the bentofile.yaml the result is unexpected. It will install torch from PyPI and this is the cuda version (on linux).

Also note that the pip_args are not applied apparently.

Output

When building and containerizing the bento with the following command.

uv run bentoml build --containerize

The output is.

 => ERROR [base-container 10/12] RUN --mount=type=cache,target=/root/.cache/ uv --directory ./env/python/ pip install -r requirements.txt                                                                                                                                                    0.8s
------                                                                                                                                                                                                                                                                                            
 > [base-container 10/12] RUN --mount=type=cache,target=/root/.cache/ uv --directory ./env/python/ pip install -r requirements.txt:                                                                                                                                                               
0.195 Using Python 3.13.7 environment at: /app/.venv                                                                                                                                                                                                                                              
0.775   × No solution found when resolving dependencies:
0.775   ╰─▶ Because there is no version of certifi==2025.8.3 and you require
0.775       certifi==2025.8.3, we can conclude that your requirements are
0.775       unsatisfiable.
0.775 
0.775       hint: `certifi` was found on https://download.pytorch.org/whl/cpu, but
0.775       not at the requested version (certifi==2025.8.3). A compatible version
0.775       may be available on a subsequent index (e.g., https://pypi.org/simple).
0.775       By default, uv will only consider versions that are published on the
0.775       first index that contains a given package, to avoid dependency confusion
0.775       attacks. If all indexes are equally trusted, use `--index-strategy
0.775       unsafe-best-match` to consider all versions from all indexes, regardless
0.775       of the order in which they were defined.
------
Dockerfile:48
--------------------
  46 |     COPY --chown=bentoml:bentoml ./env/python ./env/python/
  47 |     # install python packages
  48 | >>> RUN --mount=type=cache,target=/root/.cache/ uv --directory ./env/python/ pip install -r requirements.txt
  49 |     
  50 |     
--------------------
ERROR: failed to build: failed to solve: process "/bin/sh -c uv --directory ./env/python/ pip install -r requirements.txt" did not complete successfully: exit code: 1
ERROR: 
Encountered exception while trying to building image: Command '['/usr/bin/docker', 'build', '--tag', 'service:rtuiryepykufzbfj', '--file', '/tmp/tmpsby28cua/env/docker/Dockerfile', '/tmp/tmpsby28cua']' returned non-zero exit status 1.
Traceback (most recent call last):
  File "/home/pieter/projects/orbisk/bentoml-index-example/.venv/lib/python3.13/site-packages/bentoml/_internal/container/__init__.py", line 253, in build
    return builder.build(**kwargs)
           ~~~~~~~~~~~~~^^^^^^^^^^
  File "/home/pieter/projects/orbisk/bentoml-index-example/.venv/lib/python3.13/site-packages/bentoml/_internal/container/base.py", line 190, in build
    raise BentoMLException(str(e)) from None
bentoml.exceptions.BentoMLException: Command '['/usr/bin/docker', 'build', '--tag', 'service:rtuiryepykufzbfj', '--file', '/tmp/tmpsby28cua/env/docker/Dockerfile', '/tmp/tmpsby28cua']' returned non-zero exit status 1.
(bentoml-index-example) [pieter@neelay bentoml-index-example]$ uv export --prune bentoml --no-annotate --no-hashes -o requirements.txt

pietermarsman avatar Sep 12 '25 10:09 pietermarsman

Also note that the pip_args are not applied apparently.

Use env vars UV_INDEX_STRATEGY=unsafe-best-match, set it in @service() decorator.

frostming avatar Sep 18 '25 03:09 frostming

@pietermarsman @frostming Can i work on this, if it is not assign to anyone : can u assign it to me ?

immortal71 avatar Nov 25 '25 04:11 immortal71