Skip to content

Commit d0a47a3

Browse files
authored
feat: read dependencies from uv lock (#5379)
* feat: use dependencies from uv lock Signed-off-by: Frost Ming <me@frostming.com> * fix: verbose option Signed-off-by: Frost Ming <me@frostming.com>
1 parent 9bf170c commit d0a47a3

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

src/_bentoml_sdk/images.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class Image:
5151
post_commands: t.List[str] = attrs.field(factory=list)
5252
scripts: t.Dict[str, str] = attrs.field(factory=dict, init=False)
5353
_after_pip_install: bool = attrs.field(init=False, default=False, repr=False)
54+
_uv_lock: bool = attrs.field(init=False, default=False, repr=False)
5455

5556
def __attrs_post_init__(self) -> None:
5657
if not self.base_image:
@@ -100,7 +101,7 @@ def requirements_file(self, file_path: str) -> t.Self:
100101
self._after_pip_install = True
101102
return self
102103

103-
def pyproject_toml(self, file_path: str) -> t.Self:
104+
def pyproject_toml(self, file_path: str = "pyproject.toml") -> t.Self:
104105
"""Add a pyproject.toml to the image. Supports chaining call.
105106
106107
Example:
@@ -117,6 +118,11 @@ def pyproject_toml(self, file_path: str) -> t.Self:
117118
self.python_packages(*dependencies)
118119
return self
119120

121+
def uv_lock(self) -> t.Self:
122+
self._uv_lock = True
123+
self.lock_python_packages = False # skip locking if uv.lock is used
124+
return self
125+
120126
def python_packages(self, *packages: str) -> t.Self:
121127
"""Add python dependencies to the image. Supports chaining call.
122128
@@ -221,7 +227,26 @@ def _freeze_python_requirements(
221227
requirements_in = Path(
222228
bento_fs.getsyspath(fs.path.join(py_folder, "requirements.in"))
223229
)
224-
requirements_in.write_text(self.python_requirements)
230+
uv_cmd = get_uv_command()
231+
with requirements_in.open("w") as f:
232+
if self._uv_lock:
233+
uv_reqs = subprocess.check_output(
234+
[
235+
*uv_cmd,
236+
"export",
237+
"--no-header",
238+
"--frozen",
239+
"--no-annotate",
240+
"--no-hashes",
241+
"--no-emit-project",
242+
*(["--verbose"] if get_debug_mode() else []),
243+
],
244+
text=True,
245+
stderr=subprocess.DEVNULL if get_quiet_mode() else None,
246+
cwd=bento_fs.getsyspath("src"),
247+
)
248+
f.write(uv_reqs.rstrip("\n") + "\n")
249+
f.write(self.python_requirements)
225250
py_req = fs.path.join("env", "python", "requirements.txt")
226251
requirements_out = Path(bento_fs.getsyspath(py_req))
227252
# XXX: RequirementsFile.from_string() does not work due to bugs
@@ -276,7 +301,7 @@ def _freeze_python_requirements(
276301
DEFAULT_LOCK_PLATFORM,
277302
)
278303
lock_args.extend(["--python-platform", DEFAULT_LOCK_PLATFORM])
279-
cmd = [*get_uv_command(), "pip", "compile", *lock_args]
304+
cmd = [*uv_cmd, "pip", "compile", *lock_args]
280305
try:
281306
subprocess.check_call(
282307
cmd,

0 commit comments

Comments
 (0)