@@ -828,6 +828,110 @@ simple==0.0.1 --hash=sha256:deadb00f
828828
829829_tests .append (_test_index_url_precedence )
830830
831+ def _test_local_wheel_override (env ):
832+ def mock_simpleapi_download (* _ , ** __ ):
833+ return {
834+ "simple" : struct (
835+ whls = {
836+ "deadbeef" : struct (
837+ yanked = None ,
838+ filename = "simple-0.0.1-py3-none-any.whl" ,
839+ sha256 = "deadbeef" ,
840+ url = "example.com/simple-0.0.1.whl" ,
841+ ),
842+ },
843+ sdists = {},
844+ sha256s_by_version = {},
845+ index_url = "https://example.com" ,
846+ ),
847+ }
848+
849+ builder = hub_builder (
850+ env ,
851+ simpleapi_download_fn = mock_simpleapi_download ,
852+ )
853+ builder .pip_parse (
854+ mocks .mctx (
855+ mock_files = {
856+ "requirements.txt" : "simple==0.0.1 --hash=sha256:deadbeef" ,
857+ "MODULE.bazel" : "" ,
858+ "dist/simple-0.0.2-cp315-cp315-linux_x86_64.whl" : "" ,
859+ },
860+ os_name = "linux" ,
861+ arch_name = "x86_64" ,
862+ ),
863+ _parse (
864+ hub_name = "pypi" ,
865+ python_version = "3.15" ,
866+ experimental_index_url = "https://example.com" ,
867+ requirements_lock = "requirements.txt" ,
868+ local_wheels = {
869+ "simple" : "dist/simple-0.0.2-cp315-cp315-linux_x86_64.whl" ,
870+ },
871+ ),
872+ is_root = True ,
873+ )
874+ pypi = builder .build ()
875+
876+ pypi .exposed_packages ().contains_exactly (["simple" ])
877+ pypi .whl_map ().contains_exactly ({
878+ "simple" : {
879+ "pypi_315_simple_py3_none_any_deadbeef_local_override" : [
880+ whl_config_setting (version = "3.15" , target_platforms = ["cp315_linux_x86_64" ]),
881+ ],
882+ },
883+ })
884+ pypi .whl_libraries ().contains_exactly ({
885+ "pypi_315_simple_py3_none_any_deadbeef_local_override" : {
886+ "config_load" : "@pypi//:config.bzl" ,
887+ "dep_template" : "@pypi//{name}:{target}" ,
888+ "filename" : "simple-0.0.2-cp315-cp315-linux_x86_64.whl" ,
889+ "index_url" : "https://example.com" ,
890+ "requirement" : "simple==0.0.1" ,
891+ "sha256" : "" ,
892+ "urls" : ["file://dist/simple-0.0.2-cp315-cp315-linux_x86_64.whl" ],
893+ },
894+ })
895+ pypi .extra_aliases ().contains_exactly ({})
896+
897+ _tests .append (_test_local_wheel_override )
898+
899+ def _test_local_wheel_override_ignored_if_not_root (env ):
900+ builder = hub_builder (env )
901+ builder .pip_parse (
902+ mocks .mctx (
903+ mock_files = {
904+ "requirements.txt" : "simple==0.0.1 --hash=sha256:deadbeef" ,
905+ "MODULE.bazel" : "" ,
906+ "dist/simple-0.0.2-cp315-cp315-linux_x86_64.whl" : "" ,
907+ },
908+ os_name = "linux" ,
909+ arch_name = "x86_64" ,
910+ ),
911+ _parse (
912+ hub_name = "pypi" ,
913+ python_version = "3.15" ,
914+ requirements_lock = "requirements.txt" ,
915+ local_wheels = {
916+ "simple" : "dist/simple-0.0.2-cp315-cp315-linux_x86_64.whl" ,
917+ },
918+ ),
919+ is_root = False ,
920+ )
921+ pypi = builder .build ()
922+
923+ pypi .exposed_packages ().contains_exactly (["simple" ])
924+ pypi .whl_libraries ().contains_exactly ({
925+ "pypi_315_simple" : {
926+ "config_load" : "@pypi//:config.bzl" ,
927+ "dep_template" : "@pypi//{name}:{target}" ,
928+ "python_interpreter_target" : "unit_test_interpreter_target" ,
929+ "requirement" : "simple==0.0.1 --hash=sha256:deadbeef" ,
930+ },
931+ })
932+
933+ _tests .append (_test_local_wheel_override_ignored_if_not_root )
934+
831935def _test_download_only_multiple (env ):
832936 builder = hub_builder (env )
833937 builder .pip_parse (
@@ -1495,6 +1599,93 @@ Attempting to create a duplicate library pypi_315_foo for foo with different arg
14951599
14961600_tests .append (_test_err_duplicate_repos )
14971601
1602+ def _test_explicit_local_wheels (env ):
1603+ def mock_simpleapi_download (* _ , ** __ ):
1604+ return {
1605+ "simple" : struct (
1606+ whls = {
1607+ "deadbeef" : struct (
1608+ yanked = None ,
1609+ filename = "simple-0.0.1-py3-none-any.whl" ,
1610+ sha256 = "deadbeef" ,
1611+ url = "example.com/simple-0.0.1.whl" ,
1612+ ),
1613+ },
1614+ sdists = {},
1615+ sha256s_by_version = {},
1616+ index_url = "https://example.com" ,
1617+ ),
1618+ "libtpu" : struct (
1619+ whls = {
1620+ "deadbaaf" : struct (
1621+ yanked = None ,
1622+ filename = "libtpu-0.0.1-py3-none-any.whl" ,
1623+ sha256 = "deadbaaf" ,
1624+ url = "example.com/libtpu-0.0.1.whl" ,
1625+ ),
1626+ },
1627+ sdists = {},
1628+ sha256s_by_version = {},
1629+ index_url = "https://example.com" ,
1630+ ),
1631+ }
1632+
1633+ builder = hub_builder (
1634+ env ,
1635+ simpleapi_download_fn = mock_simpleapi_download ,
1636+ )
1637+ builder .pip_parse (
1638+ mocks .mctx (
1639+ mock_files = {
1640+ "requirements.txt" : """\
1641+ simple==0.0.1 --hash=sha256:deadbeef
1642+ libtpu==0.0.1 --hash=sha256:deadbaaf
1643+ """ ,
1644+ "MODULE.bazel" : "" ,
1645+ "custom_folder/libtpu-0.0.41.dev20260509+nightly-cp314-cp314t-manylinux_2_31_x86_64.whl" : "" ,
1646+ "custom_folder/simple-0.0.3-py3-none-any.whl" : "" ,
1647+ },
1648+ os_name = "linux" ,
1649+ arch_name = "x86_64" ,
1650+ ),
1651+ _parse (
1652+ hub_name = "pypi" ,
1653+ python_version = "3.15" ,
1654+ experimental_index_url = "https://example.com" ,
1655+ requirements_lock = "requirements.txt" ,
1656+ local_wheels = {
1657+ "simple" : "custom_folder/simple-0.0.3-py3-none-any.whl" ,
1658+ "libtpu" : "custom_folder/libtpu-*.whl" ,
1659+ },
1660+ ),
1661+ is_root = True ,
1662+ )
1663+ pypi = builder .build ()
1664+
1665+ pypi .exposed_packages ().contains_exactly (["libtpu" , "simple" ])
1666+ pypi .whl_libraries ().contains_exactly ({
1667+ "pypi_315_libtpu_py3_none_any_deadbaaf_local_override" : {
1668+ "config_load" : "@pypi//:config.bzl" ,
1669+ "dep_template" : "@pypi//{name}:{target}" ,
1670+ "filename" : "libtpu-0.0.41.dev20260509+nightly-cp314-cp314t-manylinux_2_31_x86_64.whl" ,
1671+ "index_url" : "https://example.com" ,
1672+ "requirement" : "libtpu==0.0.1" ,
1673+ "sha256" : "" ,
1674+ "urls" : ["file://custom_folder/libtpu-0.0.41.dev20260509+nightly-cp314-cp314t-manylinux_2_31_x86_64.whl" ],
1675+ },
1676+ "pypi_315_simple_py3_none_any_deadbeef_local_override" : {
1677+ "config_load" : "@pypi//:config.bzl" ,
1678+ "dep_template" : "@pypi//{name}:{target}" ,
1679+ "filename" : "simple-0.0.3-py3-none-any.whl" ,
1680+ "index_url" : "https://example.com" ,
1681+ "requirement" : "simple==0.0.1" ,
1682+ "sha256" : "" ,
1683+ "urls" : ["file://custom_folder/simple-0.0.3-py3-none-any.whl" ],
1684+ },
1685+ })
1686+
1687+ _tests .append (_test_explicit_local_wheels )
1688+
14981689def hub_builder_test_suite (name ):
14991690 """Create the test suite.
15001691
0 commit comments