@@ -500,10 +500,28 @@ pub(crate) async fn pip_install(
500500 ) ;
501501
502502 let ( resolution, hasher) = if let Some ( pylock) = pylock {
503- // Read the `pylock.toml` from disk, and deserialize it from TOML.
504- let install_path = std:: path:: absolute ( & pylock) ?;
505- let install_path = install_path. parent ( ) . unwrap ( ) ;
506- let content = fs_err:: tokio:: read_to_string ( & pylock) . await ?;
503+ // Read the `pylock.toml` from disk or URL, and deserialize it from TOML.
504+ let ( install_path, content) =
505+ if pylock. starts_with ( "http://" ) || pylock. starts_with ( "https://" ) {
506+ // Fetch the `pylock.toml` over HTTP(S).
507+ let url = uv_redacted:: DisplaySafeUrl :: parse ( & pylock. to_string_lossy ( ) ) ?;
508+ let client = client_builder. build ( ) ;
509+ let response = client
510+ . for_host ( & url)
511+ . get ( url:: Url :: from ( url. clone ( ) ) )
512+ . send ( )
513+ . await ?;
514+ response. error_for_status_ref ( ) ?;
515+ let content = response. text ( ) . await ?;
516+ // Use the current working directory as the install path for remote lock files.
517+ let install_path = std:: env:: current_dir ( ) ?;
518+ ( install_path, content)
519+ } else {
520+ let install_path = std:: path:: absolute ( & pylock) ?;
521+ let install_path = install_path. parent ( ) . unwrap ( ) . to_path_buf ( ) ;
522+ let content = fs_err:: tokio:: read_to_string ( & pylock) . await ?;
523+ ( install_path, content)
524+ } ;
507525 let lock = toml:: from_str :: < PylockToml > ( & content) . with_context ( || {
508526 format ! ( "Not a valid `pylock.toml` file: {}" , pylock. user_display( ) )
509527 } ) ?;
@@ -537,7 +555,7 @@ pub(crate) async fn pip_install(
537555 . collect :: < Vec < _ > > ( ) ;
538556
539557 let resolution = lock. to_resolution (
540- install_path,
558+ & install_path,
541559 marker_env. markers ( ) ,
542560 & extras,
543561 & groups,
0 commit comments