@@ -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