1# Copyright 2023 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""render_pkg_aliases tests""" 16 17load("@rules_testing//lib:test_suite.bzl", "test_suite") 18load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility 19load("//python/private/pypi:config_settings.bzl", "config_settings") # buildifier: disable=bzl-visibility 20load( 21 "//python/private/pypi:render_pkg_aliases.bzl", 22 "get_filename_config_settings", 23 "get_whl_flag_versions", 24 "multiplatform_whl_aliases", 25 "render_multiplatform_pkg_aliases", 26 "render_pkg_aliases", 27 "whl_alias", 28) # buildifier: disable=bzl-visibility 29 30def _normalize_label_strings(want): 31 """normalize expected strings. 32 33 This function ensures that the desired `render_pkg_aliases` outputs are 34 normalized from `bzlmod` to `WORKSPACE` values so that we don't have to 35 have to sets of expected strings. The main difference is that under 36 `bzlmod` the `str(Label("//my_label"))` results in `"@@//my_label"` whereas 37 under `non-bzlmod` we have `"@//my_label"`. This function does 38 `string.replace("@@", "@")` to normalize the strings. 39 40 NOTE, in tests, we should only use keep `@@` usage in expectation values 41 for the test cases where the whl_alias has the `config_setting` constructed 42 from a `Label` instance. 43 """ 44 if "@@" not in want: 45 fail("The expected string does not have '@@' labels, consider not using the function") 46 47 if BZLMOD_ENABLED: 48 # our expectations are already with double @ 49 return want 50 51 return want.replace("@@", "@") 52 53_tests = [] 54 55def _test_empty(env): 56 actual = render_pkg_aliases( 57 aliases = None, 58 ) 59 60 want = {} 61 62 env.expect.that_dict(actual).contains_exactly(want) 63 64_tests.append(_test_empty) 65 66def _test_legacy_aliases(env): 67 actual = render_pkg_aliases( 68 aliases = { 69 "foo": [ 70 whl_alias(repo = "pypi_foo"), 71 ], 72 }, 73 ) 74 75 want_key = "foo/BUILD.bazel" 76 want_content = """\ 77load("@bazel_skylib//lib:selects.bzl", "selects") 78 79package(default_visibility = ["//visibility:public"]) 80 81alias( 82 name = "foo", 83 actual = ":pkg", 84) 85 86alias( 87 name = "pkg", 88 actual = "@pypi_foo//:pkg", 89) 90 91alias( 92 name = "whl", 93 actual = "@pypi_foo//:whl", 94) 95 96alias( 97 name = "data", 98 actual = "@pypi_foo//:data", 99) 100 101alias( 102 name = "dist_info", 103 actual = "@pypi_foo//:dist_info", 104)""" 105 106 env.expect.that_dict(actual).contains_exactly({want_key: want_content}) 107 108_tests.append(_test_legacy_aliases) 109 110def _test_bzlmod_aliases(env): 111 # Use this function as it is used in pip_repository 112 actual = render_multiplatform_pkg_aliases( 113 default_config_setting = "//:my_config_setting", 114 aliases = { 115 "bar-baz": [ 116 whl_alias(version = "3.2", repo = "pypi_32_bar_baz", config_setting = "//:my_config_setting"), 117 ], 118 }, 119 ) 120 121 want_key = "bar_baz/BUILD.bazel" 122 want_content = """\ 123load("@bazel_skylib//lib:selects.bzl", "selects") 124 125package(default_visibility = ["//visibility:public"]) 126 127alias( 128 name = "bar_baz", 129 actual = ":pkg", 130) 131 132alias( 133 name = "pkg", 134 actual = selects.with_or( 135 { 136 ( 137 "//:my_config_setting", 138 "//conditions:default", 139 ): "@pypi_32_bar_baz//:pkg", 140 }, 141 ), 142) 143 144alias( 145 name = "whl", 146 actual = selects.with_or( 147 { 148 ( 149 "//:my_config_setting", 150 "//conditions:default", 151 ): "@pypi_32_bar_baz//:whl", 152 }, 153 ), 154) 155 156alias( 157 name = "data", 158 actual = selects.with_or( 159 { 160 ( 161 "//:my_config_setting", 162 "//conditions:default", 163 ): "@pypi_32_bar_baz//:data", 164 }, 165 ), 166) 167 168alias( 169 name = "dist_info", 170 actual = selects.with_or( 171 { 172 ( 173 "//:my_config_setting", 174 "//conditions:default", 175 ): "@pypi_32_bar_baz//:dist_info", 176 }, 177 ), 178)""" 179 180 env.expect.that_str(actual.pop("_config/BUILD.bazel")).equals( 181 """\ 182load("@rules_python//python/private/pypi:config_settings.bzl", "config_settings") 183 184config_settings( 185 name = "config_settings", 186 glibc_versions = [], 187 muslc_versions = [], 188 osx_versions = [], 189 python_versions = ["3.2"], 190 target_platforms = [], 191 visibility = ["//:__subpackages__"], 192)""", 193 ) 194 env.expect.that_collection(actual.keys()).contains_exactly([want_key]) 195 env.expect.that_str(actual[want_key]).equals(want_content) 196 197_tests.append(_test_bzlmod_aliases) 198 199def _test_bzlmod_aliases_with_no_default_version(env): 200 actual = render_multiplatform_pkg_aliases( 201 default_config_setting = None, 202 aliases = { 203 "bar-baz": [ 204 whl_alias( 205 version = "3.2", 206 repo = "pypi_32_bar_baz", 207 # pass the label to ensure that it gets converted to string 208 config_setting = Label("//python/config_settings:is_python_3.2"), 209 ), 210 whl_alias(version = "3.1", repo = "pypi_31_bar_baz"), 211 ], 212 }, 213 ) 214 215 want_key = "bar_baz/BUILD.bazel" 216 want_content = """\ 217load("@bazel_skylib//lib:selects.bzl", "selects") 218 219package(default_visibility = ["//visibility:public"]) 220 221_NO_MATCH_ERROR = \"\"\"\\ 222No matching wheel for current configuration's Python version. 223 224The current build configuration's Python version doesn't match any of the Python 225wheels available for this wheel. This wheel supports the following Python 226configuration settings: 227 //_config:is_python_3.1 228 @@//python/config_settings:is_python_3.2 229 230To determine the current configuration's Python version, run: 231 `bazel config <config id>` (shown further below) 232and look for 233 rules_python//python/config_settings:python_version 234 235If the value is missing, then the "default" Python version is being used, 236which has a "null" version value and will not match version constraints. 237\"\"\" 238 239alias( 240 name = "bar_baz", 241 actual = ":pkg", 242) 243 244alias( 245 name = "pkg", 246 actual = selects.with_or( 247 { 248 "//_config:is_python_3.1": "@pypi_31_bar_baz//:pkg", 249 "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg", 250 }, 251 no_match_error = _NO_MATCH_ERROR, 252 ), 253) 254 255alias( 256 name = "whl", 257 actual = selects.with_or( 258 { 259 "//_config:is_python_3.1": "@pypi_31_bar_baz//:whl", 260 "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl", 261 }, 262 no_match_error = _NO_MATCH_ERROR, 263 ), 264) 265 266alias( 267 name = "data", 268 actual = selects.with_or( 269 { 270 "//_config:is_python_3.1": "@pypi_31_bar_baz//:data", 271 "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data", 272 }, 273 no_match_error = _NO_MATCH_ERROR, 274 ), 275) 276 277alias( 278 name = "dist_info", 279 actual = selects.with_or( 280 { 281 "//_config:is_python_3.1": "@pypi_31_bar_baz//:dist_info", 282 "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info", 283 }, 284 no_match_error = _NO_MATCH_ERROR, 285 ), 286)""" 287 288 actual.pop("_config/BUILD.bazel") 289 env.expect.that_collection(actual.keys()).contains_exactly([want_key]) 290 env.expect.that_str(actual[want_key]).equals(_normalize_label_strings(want_content)) 291 292_tests.append(_test_bzlmod_aliases_with_no_default_version) 293 294def _test_bzlmod_aliases_for_non_root_modules(env): 295 actual = render_pkg_aliases( 296 # NOTE @aignas 2024-01-17: if the default X.Y version coincides with the 297 # versions that are used in the root module, then this would be the same as 298 # as _test_bzlmod_aliases. 299 # 300 # However, if the root module uses a different default version than the 301 # non-root module, then we will have a no-match-error because the 302 # default_config_setting is not in the list of the versions in the 303 # whl_map. 304 default_config_setting = "//_config:is_python_3.3", 305 aliases = { 306 "bar-baz": [ 307 whl_alias(version = "3.2", repo = "pypi_32_bar_baz"), 308 whl_alias(version = "3.1", repo = "pypi_31_bar_baz"), 309 ], 310 }, 311 ) 312 313 want_key = "bar_baz/BUILD.bazel" 314 want_content = """\ 315load("@bazel_skylib//lib:selects.bzl", "selects") 316 317package(default_visibility = ["//visibility:public"]) 318 319_NO_MATCH_ERROR = \"\"\"\\ 320No matching wheel for current configuration's Python version. 321 322The current build configuration's Python version doesn't match any of the Python 323wheels available for this wheel. This wheel supports the following Python 324configuration settings: 325 //_config:is_python_3.1 326 //_config:is_python_3.2 327 328To determine the current configuration's Python version, run: 329 `bazel config <config id>` (shown further below) 330and look for 331 rules_python//python/config_settings:python_version 332 333If the value is missing, then the "default" Python version is being used, 334which has a "null" version value and will not match version constraints. 335\"\"\" 336 337alias( 338 name = "bar_baz", 339 actual = ":pkg", 340) 341 342alias( 343 name = "pkg", 344 actual = selects.with_or( 345 { 346 "//_config:is_python_3.1": "@pypi_31_bar_baz//:pkg", 347 "//_config:is_python_3.2": "@pypi_32_bar_baz//:pkg", 348 }, 349 no_match_error = _NO_MATCH_ERROR, 350 ), 351) 352 353alias( 354 name = "whl", 355 actual = selects.with_or( 356 { 357 "//_config:is_python_3.1": "@pypi_31_bar_baz//:whl", 358 "//_config:is_python_3.2": "@pypi_32_bar_baz//:whl", 359 }, 360 no_match_error = _NO_MATCH_ERROR, 361 ), 362) 363 364alias( 365 name = "data", 366 actual = selects.with_or( 367 { 368 "//_config:is_python_3.1": "@pypi_31_bar_baz//:data", 369 "//_config:is_python_3.2": "@pypi_32_bar_baz//:data", 370 }, 371 no_match_error = _NO_MATCH_ERROR, 372 ), 373) 374 375alias( 376 name = "dist_info", 377 actual = selects.with_or( 378 { 379 "//_config:is_python_3.1": "@pypi_31_bar_baz//:dist_info", 380 "//_config:is_python_3.2": "@pypi_32_bar_baz//:dist_info", 381 }, 382 no_match_error = _NO_MATCH_ERROR, 383 ), 384)""" 385 386 env.expect.that_collection(actual.keys()).contains_exactly([want_key]) 387 env.expect.that_str(actual[want_key]).equals(want_content) 388 389_tests.append(_test_bzlmod_aliases_for_non_root_modules) 390 391def _test_aliases_are_created_for_all_wheels(env): 392 actual = render_pkg_aliases( 393 default_config_setting = "//_config:is_python_3.2", 394 aliases = { 395 "bar": [ 396 whl_alias(version = "3.1", repo = "pypi_31_bar"), 397 whl_alias(version = "3.2", repo = "pypi_32_bar"), 398 ], 399 "foo": [ 400 whl_alias(version = "3.1", repo = "pypi_32_foo"), 401 whl_alias(version = "3.2", repo = "pypi_31_foo"), 402 ], 403 }, 404 ) 405 406 want_files = [ 407 "bar/BUILD.bazel", 408 "foo/BUILD.bazel", 409 ] 410 411 env.expect.that_dict(actual).keys().contains_exactly(want_files) 412 413_tests.append(_test_aliases_are_created_for_all_wheels) 414 415def _test_aliases_with_groups(env): 416 actual = render_pkg_aliases( 417 default_config_setting = "//_config:is_python_3.2", 418 aliases = { 419 "bar": [ 420 whl_alias(version = "3.1", repo = "pypi_31_bar"), 421 whl_alias(version = "3.2", repo = "pypi_32_bar"), 422 ], 423 "baz": [ 424 whl_alias(version = "3.1", repo = "pypi_31_baz"), 425 whl_alias(version = "3.2", repo = "pypi_32_baz"), 426 ], 427 "foo": [ 428 whl_alias(version = "3.1", repo = "pypi_32_foo"), 429 whl_alias(version = "3.2", repo = "pypi_31_foo"), 430 ], 431 }, 432 requirement_cycles = { 433 "group": ["bar", "baz"], 434 }, 435 ) 436 437 want_files = [ 438 "bar/BUILD.bazel", 439 "foo/BUILD.bazel", 440 "baz/BUILD.bazel", 441 "_groups/BUILD.bazel", 442 ] 443 env.expect.that_dict(actual).keys().contains_exactly(want_files) 444 445 want_key = "_groups/BUILD.bazel" 446 447 # Just check that it contains a private whl 448 env.expect.that_str(actual[want_key]).contains("//bar:_whl") 449 450 want_key = "bar/BUILD.bazel" 451 452 # Just check that it contains a private whl 453 env.expect.that_str(actual[want_key]).contains("name = \"_whl\"") 454 env.expect.that_str(actual[want_key]).contains("name = \"whl\"") 455 env.expect.that_str(actual[want_key]).contains("\"//_groups:group_whl\"") 456 457_tests.append(_test_aliases_with_groups) 458 459def _test_empty_flag_versions(env): 460 got = get_whl_flag_versions( 461 aliases = [], 462 ) 463 want = {} 464 env.expect.that_dict(got).contains_exactly(want) 465 466_tests.append(_test_empty_flag_versions) 467 468def _test_get_python_versions(env): 469 got = get_whl_flag_versions( 470 aliases = [ 471 whl_alias(repo = "foo", version = "3.3"), 472 whl_alias(repo = "foo", version = "3.2"), 473 ], 474 ) 475 want = { 476 "python_versions": ["3.2", "3.3"], 477 } 478 env.expect.that_dict(got).contains_exactly(want) 479 480_tests.append(_test_get_python_versions) 481 482def _test_get_python_versions_from_filenames(env): 483 got = get_whl_flag_versions( 484 aliases = [ 485 whl_alias( 486 repo = "foo", 487 version = "3.3", 488 filename = "foo-0.0.0-py3-none-" + plat + ".whl", 489 ) 490 for plat in [ 491 "linux_x86_64", 492 "manylinux_2_17_x86_64", 493 "manylinux_2_14_aarch64.musllinux_1_1_aarch64", 494 "musllinux_1_0_x86_64", 495 "manylinux2014_x86_64.manylinux_2_17_x86_64", 496 "macosx_11_0_arm64", 497 "macosx_10_9_x86_64", 498 "macosx_10_9_universal2", 499 "windows_x86_64", 500 ] 501 ], 502 ) 503 want = { 504 "glibc_versions": [(2, 14), (2, 17)], 505 "muslc_versions": [(1, 0), (1, 1)], 506 "osx_versions": [(10, 9), (11, 0)], 507 "python_versions": ["3.3"], 508 "target_platforms": [ 509 "linux_aarch64", 510 "linux_x86_64", 511 "osx_aarch64", 512 "osx_x86_64", 513 "windows_x86_64", 514 ], 515 } 516 env.expect.that_dict(got).contains_exactly(want) 517 518_tests.append(_test_get_python_versions_from_filenames) 519 520def _test_get_flag_versions_from_alias_target_platforms(env): 521 got = get_whl_flag_versions( 522 aliases = [ 523 whl_alias( 524 repo = "foo", 525 version = "3.3", 526 filename = "foo-0.0.0-py3-none-" + plat + ".whl", 527 ) 528 for plat in [ 529 "windows_x86_64", 530 ] 531 ] + [ 532 whl_alias( 533 repo = "foo", 534 version = "3.3", 535 filename = "foo-0.0.0-py3-none-any.whl", 536 target_platforms = [ 537 "cp33_linux_x86_64", 538 ], 539 ), 540 ], 541 ) 542 want = { 543 "python_versions": ["3.3"], 544 "target_platforms": [ 545 "linux_x86_64", 546 "windows_x86_64", 547 ], 548 } 549 env.expect.that_dict(got).contains_exactly(want) 550 551_tests.append(_test_get_flag_versions_from_alias_target_platforms) 552 553def _test_config_settings( 554 env, 555 *, 556 filename, 557 want, 558 want_versions = {}, 559 target_platforms = [], 560 glibc_versions = [], 561 muslc_versions = [], 562 osx_versions = [], 563 python_version = "", 564 python_default = True): 565 got, got_default_version_settings = get_filename_config_settings( 566 filename = filename, 567 target_platforms = target_platforms, 568 glibc_versions = glibc_versions, 569 muslc_versions = muslc_versions, 570 osx_versions = osx_versions, 571 python_version = python_version, 572 python_default = python_default, 573 ) 574 env.expect.that_collection(got).contains_exactly(want) 575 env.expect.that_dict(got_default_version_settings).contains_exactly(want_versions) 576 577def _test_sdist(env): 578 # Do the first test for multiple extensions 579 for ext in [".tar.gz", ".zip"]: 580 _test_config_settings( 581 env, 582 filename = "foo-0.0.1" + ext, 583 want = [":is_sdist"], 584 ) 585 586 ext = ".zip" 587 _test_config_settings( 588 env, 589 filename = "foo-0.0.1" + ext, 590 target_platforms = [ 591 "linux_aarch64", 592 ], 593 want = [":is_sdist_linux_aarch64"], 594 ) 595 596 _test_config_settings( 597 env, 598 filename = "foo-0.0.1" + ext, 599 python_version = "3.2", 600 want = [ 601 ":is_sdist", 602 ":is_cp3.2_sdist", 603 ], 604 ) 605 606 _test_config_settings( 607 env, 608 filename = "foo-0.0.1" + ext, 609 python_version = "3.2", 610 python_default = True, 611 target_platforms = [ 612 "linux_aarch64", 613 "linux_x86_64", 614 ], 615 want = [ 616 ":is_sdist_linux_aarch64", 617 ":is_cp3.2_sdist_linux_aarch64", 618 ":is_sdist_linux_x86_64", 619 ":is_cp3.2_sdist_linux_x86_64", 620 ], 621 ) 622 623_tests.append(_test_sdist) 624 625def _test_py2_py3_none_any(env): 626 _test_config_settings( 627 env, 628 filename = "foo-0.0.1-py2.py3-none-any.whl", 629 want = [":is_py_none_any"], 630 ) 631 632 _test_config_settings( 633 env, 634 filename = "foo-0.0.1-py2.py3-none-any.whl", 635 target_platforms = [ 636 "linux_aarch64", 637 ], 638 want = [":is_py_none_any_linux_aarch64"], 639 ) 640 641 _test_config_settings( 642 env, 643 filename = "foo-0.0.1-py2.py3-none-any.whl", 644 python_version = "3.2", 645 python_default = True, 646 want = [ 647 ":is_py_none_any", 648 ":is_cp3.2_py_none_any", 649 ], 650 ) 651 652 _test_config_settings( 653 env, 654 filename = "foo-0.0.1-py2.py3-none-any.whl", 655 python_version = "3.2", 656 python_default = False, 657 target_platforms = [ 658 "osx_x86_64", 659 ], 660 want = [ 661 ":is_cp3.2_py_none_any_osx_x86_64", 662 ], 663 ) 664 665_tests.append(_test_py2_py3_none_any) 666 667def _test_py3_none_any(env): 668 _test_config_settings( 669 env, 670 filename = "foo-0.0.1-py3-none-any.whl", 671 want = [":is_py3_none_any"], 672 ) 673 674 _test_config_settings( 675 env, 676 filename = "foo-0.0.1-py3-none-any.whl", 677 target_platforms = ["linux_x86_64"], 678 want = [":is_py3_none_any_linux_x86_64"], 679 ) 680 681_tests.append(_test_py3_none_any) 682 683def _test_py3_none_macosx_10_9_universal2(env): 684 _test_config_settings( 685 env, 686 filename = "foo-0.0.1-py3-none-macosx_10_9_universal2.whl", 687 osx_versions = [ 688 (10, 9), 689 (11, 0), 690 ], 691 want = [], 692 want_versions = { 693 ":is_py3_none_osx_aarch64_universal2": { 694 (10, 9): ":is_py3_none_osx_10_9_aarch64_universal2", 695 (11, 0): ":is_py3_none_osx_11_0_aarch64_universal2", 696 }, 697 ":is_py3_none_osx_x86_64_universal2": { 698 (10, 9): ":is_py3_none_osx_10_9_x86_64_universal2", 699 (11, 0): ":is_py3_none_osx_11_0_x86_64_universal2", 700 }, 701 }, 702 ) 703 704_tests.append(_test_py3_none_macosx_10_9_universal2) 705 706def _test_cp37_abi3_linux_x86_64(env): 707 _test_config_settings( 708 env, 709 filename = "foo-0.0.1-cp37-abi3-linux_x86_64.whl", 710 want = [ 711 ":is_cp3x_abi3_linux_x86_64", 712 ], 713 ) 714 715 _test_config_settings( 716 env, 717 filename = "foo-0.0.1-cp37-abi3-linux_x86_64.whl", 718 python_version = "3.2", 719 python_default = True, 720 want = [ 721 ":is_cp3x_abi3_linux_x86_64", 722 ":is_cp3.2_cp3x_abi3_linux_x86_64", 723 ], 724 ) 725 726_tests.append(_test_cp37_abi3_linux_x86_64) 727 728def _test_cp37_abi3_windows_x86_64(env): 729 _test_config_settings( 730 env, 731 filename = "foo-0.0.1-cp37-abi3-windows_x86_64.whl", 732 want = [ 733 ":is_cp3x_abi3_windows_x86_64", 734 ], 735 ) 736 737_tests.append(_test_cp37_abi3_windows_x86_64) 738 739def _test_cp37_abi3_manylinux_2_17_x86_64(env): 740 _test_config_settings( 741 env, 742 filename = "foo-0.0.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", 743 glibc_versions = [ 744 (2, 16), 745 (2, 17), 746 (2, 18), 747 ], 748 want = [], 749 want_versions = { 750 ":is_cp3x_abi3_manylinux_x86_64": { 751 (2, 17): ":is_cp3x_abi3_manylinux_2_17_x86_64", 752 (2, 18): ":is_cp3x_abi3_manylinux_2_18_x86_64", 753 }, 754 }, 755 ) 756 757_tests.append(_test_cp37_abi3_manylinux_2_17_x86_64) 758 759def _test_cp37_abi3_manylinux_2_17_musllinux_1_1_aarch64(env): 760 # I've seen such a wheel being built for `uv` 761 _test_config_settings( 762 env, 763 filename = "foo-0.0.1-cp37-cp37-manylinux_2_17_arm64.musllinux_1_1_arm64.whl", 764 glibc_versions = [ 765 (2, 16), 766 (2, 17), 767 (2, 18), 768 ], 769 muslc_versions = [ 770 (1, 1), 771 ], 772 want = [], 773 want_versions = { 774 ":is_cp3x_cp_manylinux_aarch64": { 775 (2, 17): ":is_cp3x_cp_manylinux_2_17_aarch64", 776 (2, 18): ":is_cp3x_cp_manylinux_2_18_aarch64", 777 }, 778 ":is_cp3x_cp_musllinux_aarch64": { 779 (1, 1): ":is_cp3x_cp_musllinux_1_1_aarch64", 780 }, 781 }, 782 ) 783 784_tests.append(_test_cp37_abi3_manylinux_2_17_musllinux_1_1_aarch64) 785 786def _test_multiplatform_whl_aliases_empty(env): 787 # Check that we still work with an empty requirements.txt 788 got = multiplatform_whl_aliases(aliases = [], default_version = None) 789 env.expect.that_collection(got).contains_exactly([]) 790 791_tests.append(_test_multiplatform_whl_aliases_empty) 792 793def _test_multiplatform_whl_aliases_nofilename(env): 794 aliases = [ 795 whl_alias( 796 repo = "foo", 797 config_setting = "//:label", 798 version = "3.1", 799 ), 800 ] 801 got = multiplatform_whl_aliases(aliases = aliases, default_version = None) 802 env.expect.that_collection(got).contains_exactly(aliases) 803 804_tests.append(_test_multiplatform_whl_aliases_nofilename) 805 806def _test_multiplatform_whl_aliases_filename(env): 807 aliases = [ 808 whl_alias( 809 repo = "foo-py3-0.0.3", 810 filename = "foo-0.0.3-py3-none-any.whl", 811 version = "3.2", 812 ), 813 whl_alias( 814 repo = "foo-py3-0.0.1", 815 filename = "foo-0.0.1-py3-none-any.whl", 816 version = "3.1", 817 ), 818 whl_alias( 819 repo = "foo-0.0.2", 820 filename = "foo-0.0.2-py3-none-any.whl", 821 version = "3.1", 822 target_platforms = [ 823 "cp31_linux_x86_64", 824 "cp31_linux_aarch64", 825 ], 826 ), 827 ] 828 got = multiplatform_whl_aliases( 829 aliases = aliases, 830 default_version = "3.1", 831 glibc_versions = [], 832 muslc_versions = [], 833 osx_versions = [], 834 ) 835 want = [ 836 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_any", repo = "foo-py3-0.0.1", version = "3.1"), 837 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_any_linux_aarch64", repo = "foo-0.0.2", version = "3.1"), 838 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_any_linux_x86_64", repo = "foo-0.0.2", version = "3.1"), 839 whl_alias(config_setting = "//_config:is_cp3.2_py3_none_any", repo = "foo-py3-0.0.3", version = "3.2"), 840 whl_alias(config_setting = "//_config:is_py3_none_any", repo = "foo-py3-0.0.1", version = "3.1"), 841 whl_alias(config_setting = "//_config:is_py3_none_any_linux_aarch64", repo = "foo-0.0.2", version = "3.1"), 842 whl_alias(config_setting = "//_config:is_py3_none_any_linux_x86_64", repo = "foo-0.0.2", version = "3.1"), 843 ] 844 env.expect.that_collection(got).contains_exactly(want) 845 846_tests.append(_test_multiplatform_whl_aliases_filename) 847 848def _test_multiplatform_whl_aliases_filename_versioned(env): 849 aliases = [ 850 whl_alias( 851 repo = "glibc-2.17", 852 filename = "foo-0.0.1-py3-none-manylinux_2_17_x86_64.whl", 853 version = "3.1", 854 ), 855 whl_alias( 856 repo = "glibc-2.18", 857 filename = "foo-0.0.1-py3-none-manylinux_2_18_x86_64.whl", 858 version = "3.1", 859 ), 860 whl_alias( 861 repo = "musl", 862 filename = "foo-0.0.1-py3-none-musllinux_1_1_x86_64.whl", 863 version = "3.1", 864 ), 865 ] 866 got = multiplatform_whl_aliases( 867 aliases = aliases, 868 default_version = None, 869 glibc_versions = [(2, 17), (2, 18)], 870 muslc_versions = [(1, 1), (1, 2)], 871 osx_versions = [], 872 ) 873 want = [ 874 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_manylinux_2_17_x86_64", repo = "glibc-2.17", version = "3.1"), 875 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_manylinux_2_18_x86_64", repo = "glibc-2.18", version = "3.1"), 876 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_manylinux_x86_64", repo = "glibc-2.17", version = "3.1"), 877 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_musllinux_1_1_x86_64", repo = "musl", version = "3.1"), 878 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_musllinux_1_2_x86_64", repo = "musl", version = "3.1"), 879 whl_alias(config_setting = "//_config:is_cp3.1_py3_none_musllinux_x86_64", repo = "musl", version = "3.1"), 880 ] 881 env.expect.that_collection(got).contains_exactly(want) 882 883_tests.append(_test_multiplatform_whl_aliases_filename_versioned) 884 885def _test_config_settings_exist(env): 886 for py_tag in ["py2.py3", "py3", "py311", "cp311"]: 887 if py_tag == "py2.py3": 888 abis = ["none"] 889 elif py_tag.startswith("py"): 890 abis = ["none", "abi3"] 891 else: 892 abis = ["none", "abi3", "cp311"] 893 894 for abi_tag in abis: 895 for platform_tag, kwargs in { 896 "any": {}, 897 "macosx_11_0_arm64": { 898 "osx_versions": [(11, 0)], 899 "target_platforms": ["osx_aarch64"], 900 }, 901 "manylinux_2_17_x86_64": { 902 "glibc_versions": [(2, 17), (2, 18)], 903 "target_platforms": ["linux_x86_64"], 904 }, 905 "manylinux_2_18_x86_64": { 906 "glibc_versions": [(2, 17), (2, 18)], 907 "target_platforms": ["linux_x86_64"], 908 }, 909 "musllinux_1_1_aarch64": { 910 "muslc_versions": [(1, 2), (1, 1), (1, 0)], 911 "target_platforms": ["linux_aarch64"], 912 }, 913 }.items(): 914 aliases = [ 915 whl_alias( 916 repo = "repo", 917 filename = "foo-0.0.1-{}-{}-{}.whl".format(py_tag, abi_tag, platform_tag), 918 version = "3.11", 919 ), 920 ] 921 available_config_settings = [] 922 mock_rule = lambda name, **kwargs: available_config_settings.append(name) 923 config_settings( 924 python_versions = ["3.11"], 925 native = struct( 926 alias = mock_rule, 927 config_setting = mock_rule, 928 ), 929 **kwargs 930 ) 931 932 got_aliases = multiplatform_whl_aliases( 933 aliases = aliases, 934 default_version = None, 935 glibc_versions = kwargs.get("glibc_versions", []), 936 muslc_versions = kwargs.get("muslc_versions", []), 937 osx_versions = kwargs.get("osx_versions", []), 938 ) 939 got = [a.config_setting.partition(":")[-1] for a in got_aliases] 940 941 env.expect.that_collection(available_config_settings).contains_at_least(got) 942 943_tests.append(_test_config_settings_exist) 944 945def render_pkg_aliases_test_suite(name): 946 """Create the test suite. 947 948 Args: 949 name: the name of the test suite 950 """ 951 test_suite(name = name, basic_tests = _tests) 952