• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(
19    "//python/private/pypi:pkg_aliases.bzl",
20    "get_filename_config_settings",
21)  # buildifier: disable=bzl-visibility
22load(
23    "//python/private/pypi:render_pkg_aliases.bzl",
24    "get_whl_flag_versions",
25    "render_multiplatform_pkg_aliases",
26    "render_pkg_aliases",
27)  # buildifier: disable=bzl-visibility
28load("//python/private/pypi:whl_config_setting.bzl", "whl_config_setting")  # buildifier: disable=bzl-visibility
29
30_tests = []
31
32def _test_empty(env):
33    actual = render_pkg_aliases(
34        aliases = None,
35    )
36
37    want = {}
38
39    env.expect.that_dict(actual).contains_exactly(want)
40
41_tests.append(_test_empty)
42
43def _test_legacy_aliases(env):
44    actual = render_pkg_aliases(
45        aliases = {
46            "foo": "pypi_foo",
47        },
48    )
49
50    want_key = "foo/BUILD.bazel"
51    want_content = """\
52load("@rules_python//python/private/pypi:pkg_aliases.bzl", "pkg_aliases")
53
54package(default_visibility = ["//visibility:public"])
55
56pkg_aliases(
57    name = "foo",
58    actual = "pypi_foo",
59)"""
60
61    env.expect.that_dict(actual).contains_exactly({want_key: want_content})
62
63_tests.append(_test_legacy_aliases)
64
65def _test_bzlmod_aliases(env):
66    # Use this function as it is used in pip_repository
67    actual = render_multiplatform_pkg_aliases(
68        aliases = {
69            "bar-baz": {
70                whl_config_setting(
71                    version = "3.2",
72                    config_setting = "//:my_config_setting",
73                ): "pypi_32_bar_baz",
74                whl_config_setting(
75                    version = "3.2",
76                    config_setting = "//:my_config_setting",
77                    target_platforms = [
78                        "cp32_linux_x86_64",
79                    ],
80                ): "pypi_32_bar_baz_linux_x86_64",
81                whl_config_setting(
82                    version = "3.2",
83                    filename = "foo-0.0.0-py3-none-any.whl",
84                ): "filename_repo",
85                whl_config_setting(
86                    version = "3.2",
87                    filename = "foo-0.0.0-py3-none-any.whl",
88                    target_platforms = [
89                        "cp32_linux_x86_64",
90                    ],
91                ): "filename_repo_linux_x86_64",
92            },
93        },
94        extra_hub_aliases = {"bar_baz": ["foo"]},
95    )
96
97    want_key = "bar_baz/BUILD.bazel"
98    want_content = """\
99load("@rules_python//python/private/pypi:pkg_aliases.bzl", "pkg_aliases")
100load("@rules_python//python/private/pypi:whl_config_setting.bzl", "whl_config_setting")
101
102package(default_visibility = ["//visibility:public"])
103
104pkg_aliases(
105    name = "bar_baz",
106    actual = {
107        "//:my_config_setting": "pypi_32_bar_baz",
108        whl_config_setting(
109            target_platforms = ("cp32_linux_x86_64",),
110            config_setting = "//:my_config_setting",
111            version = "3.2",
112        ): "pypi_32_bar_baz_linux_x86_64",
113        whl_config_setting(
114            filename = "foo-0.0.0-py3-none-any.whl",
115            version = "3.2",
116        ): "filename_repo",
117        whl_config_setting(
118            filename = "foo-0.0.0-py3-none-any.whl",
119            target_platforms = ("cp32_linux_x86_64",),
120            version = "3.2",
121        ): "filename_repo_linux_x86_64",
122    },
123    extra_aliases = ["foo"],
124)"""
125
126    env.expect.that_str(actual.pop("_config/BUILD.bazel")).equals(
127        """\
128load("@rules_python//python/private/pypi:config_settings.bzl", "config_settings")
129
130config_settings(
131    name = "config_settings",
132    python_versions = ["3.2"],
133    target_platforms = ["linux_x86_64"],
134    visibility = ["//:__subpackages__"],
135)""",
136    )
137    env.expect.that_collection(actual.keys()).contains_exactly([want_key])
138    env.expect.that_str(actual[want_key]).equals(want_content)
139
140_tests.append(_test_bzlmod_aliases)
141
142def _test_aliases_are_created_for_all_wheels(env):
143    actual = render_pkg_aliases(
144        aliases = {
145            "bar": {
146                whl_config_setting(version = "3.1"): "pypi_31_bar",
147                whl_config_setting(version = "3.2"): "pypi_32_bar",
148            },
149            "foo": {
150                whl_config_setting(version = "3.1"): "pypi_32_foo",
151                whl_config_setting(version = "3.2"): "pypi_31_foo",
152            },
153        },
154    )
155
156    want_files = [
157        "bar/BUILD.bazel",
158        "foo/BUILD.bazel",
159    ]
160
161    env.expect.that_dict(actual).keys().contains_exactly(want_files)
162
163_tests.append(_test_aliases_are_created_for_all_wheels)
164
165def _test_aliases_with_groups(env):
166    actual = render_pkg_aliases(
167        aliases = {
168            "bar": {
169                whl_config_setting(version = "3.1"): "pypi_31_bar",
170                whl_config_setting(version = "3.2"): "pypi_32_bar",
171            },
172            "baz": {
173                whl_config_setting(version = "3.1"): "pypi_31_baz",
174                whl_config_setting(version = "3.2"): "pypi_32_baz",
175            },
176            "foo": {
177                whl_config_setting(version = "3.1"): "pypi_32_foo",
178                whl_config_setting(version = "3.2"): "pypi_31_foo",
179            },
180        },
181        requirement_cycles = {
182            "group": ["bar", "baz"],
183        },
184    )
185
186    want_files = [
187        "bar/BUILD.bazel",
188        "foo/BUILD.bazel",
189        "baz/BUILD.bazel",
190        "_groups/BUILD.bazel",
191    ]
192    env.expect.that_dict(actual).keys().contains_exactly(want_files)
193
194    want_key = "_groups/BUILD.bazel"
195
196    # Just check that it contains a private whl
197    env.expect.that_str(actual[want_key]).contains("//bar:_whl")
198
199    want_key = "bar/BUILD.bazel"
200
201    # Just check that we pass the group name
202    env.expect.that_str(actual[want_key]).contains("group_name = \"group\"")
203
204_tests.append(_test_aliases_with_groups)
205
206def _test_empty_flag_versions(env):
207    got = get_whl_flag_versions(
208        settings = [],
209    )
210    want = {}
211    env.expect.that_dict(got).contains_exactly(want)
212
213_tests.append(_test_empty_flag_versions)
214
215def _test_get_python_versions(env):
216    got = get_whl_flag_versions(
217        settings = {
218            whl_config_setting(version = "3.3"): "foo",
219            whl_config_setting(version = "3.2"): "foo",
220        },
221    )
222    want = {
223        "python_versions": ["3.2", "3.3"],
224    }
225    env.expect.that_dict(got).contains_exactly(want)
226
227_tests.append(_test_get_python_versions)
228
229def _test_get_python_versions_with_target_platforms(env):
230    got = get_whl_flag_versions(
231        settings = [
232            whl_config_setting(version = "3.3", target_platforms = ["cp33_linux_x86_64"]),
233            whl_config_setting(version = "3.2", target_platforms = ["cp32_linux_x86_64", "cp32_osx_aarch64"]),
234        ],
235    )
236    want = {
237        "python_versions": ["3.2", "3.3"],
238        "target_platforms": [
239            "linux_x86_64",
240            "osx_aarch64",
241        ],
242    }
243    env.expect.that_dict(got).contains_exactly(want)
244
245_tests.append(_test_get_python_versions_with_target_platforms)
246
247def _test_get_python_versions_from_filenames(env):
248    got = get_whl_flag_versions(
249        settings = [
250            whl_config_setting(
251                version = "3.3",
252                filename = "foo-0.0.0-py3-none-" + plat + ".whl",
253            )
254            for plat in [
255                "linux_x86_64",
256                "manylinux_2_17_x86_64",
257                "manylinux_2_14_aarch64.musllinux_1_1_aarch64",
258                "musllinux_1_0_x86_64",
259                "manylinux2014_x86_64.manylinux_2_17_x86_64",
260                "macosx_11_0_arm64",
261                "macosx_10_9_x86_64",
262                "macosx_10_9_universal2",
263                "windows_x86_64",
264            ]
265        ],
266    )
267    want = {
268        "glibc_versions": [(2, 14), (2, 17)],
269        "muslc_versions": [(1, 0), (1, 1)],
270        "osx_versions": [(10, 9), (11, 0)],
271        "python_versions": ["3.3"],
272        "target_platforms": [
273            "linux_aarch64",
274            "linux_x86_64",
275            "osx_aarch64",
276            "osx_x86_64",
277            "windows_x86_64",
278        ],
279    }
280    env.expect.that_dict(got).contains_exactly(want)
281
282_tests.append(_test_get_python_versions_from_filenames)
283
284def _test_get_flag_versions_from_alias_target_platforms(env):
285    got = get_whl_flag_versions(
286        settings = [
287            whl_config_setting(
288                version = "3.3",
289                filename = "foo-0.0.0-py3-none-" + plat + ".whl",
290            )
291            for plat in [
292                "windows_x86_64",
293            ]
294        ] + [
295            whl_config_setting(
296                version = "3.3",
297                filename = "foo-0.0.0-py3-none-any.whl",
298                target_platforms = [
299                    "cp33_linux_x86_64",
300                ],
301            ),
302        ],
303    )
304    want = {
305        "python_versions": ["3.3"],
306        "target_platforms": [
307            "linux_x86_64",
308            "windows_x86_64",
309        ],
310    }
311    env.expect.that_dict(got).contains_exactly(want)
312
313_tests.append(_test_get_flag_versions_from_alias_target_platforms)
314
315def _test_config_settings(
316        env,
317        *,
318        filename,
319        want,
320        python_version,
321        want_versions = {},
322        target_platforms = [],
323        glibc_versions = [],
324        muslc_versions = [],
325        osx_versions = []):
326    got, got_default_version_settings = get_filename_config_settings(
327        filename = filename,
328        target_platforms = target_platforms,
329        glibc_versions = glibc_versions,
330        muslc_versions = muslc_versions,
331        osx_versions = osx_versions,
332        python_version = python_version,
333    )
334    env.expect.that_collection(got).contains_exactly(want)
335    env.expect.that_dict(got_default_version_settings).contains_exactly(want_versions)
336
337def _test_sdist(env):
338    # Do the first test for multiple extensions
339    for ext in [".tar.gz", ".zip"]:
340        _test_config_settings(
341            env,
342            filename = "foo-0.0.1" + ext,
343            python_version = "3.2",
344            want = [":is_cp3.2_sdist"],
345        )
346
347    ext = ".zip"
348    _test_config_settings(
349        env,
350        filename = "foo-0.0.1" + ext,
351        python_version = "3.2",
352        target_platforms = [
353            "linux_aarch64",
354            "linux_x86_64",
355        ],
356        want = [
357            ":is_cp3.2_sdist_linux_aarch64",
358            ":is_cp3.2_sdist_linux_x86_64",
359        ],
360    )
361
362_tests.append(_test_sdist)
363
364def _test_py2_py3_none_any(env):
365    _test_config_settings(
366        env,
367        filename = "foo-0.0.1-py2.py3-none-any.whl",
368        python_version = "3.2",
369        want = [
370            ":is_cp3.2_py_none_any",
371        ],
372    )
373
374    _test_config_settings(
375        env,
376        filename = "foo-0.0.1-py2.py3-none-any.whl",
377        python_version = "3.2",
378        target_platforms = [
379            "osx_x86_64",
380        ],
381        want = [":is_cp3.2_py_none_any_osx_x86_64"],
382    )
383
384_tests.append(_test_py2_py3_none_any)
385
386def _test_py3_none_any(env):
387    _test_config_settings(
388        env,
389        filename = "foo-0.0.1-py3-none-any.whl",
390        python_version = "3.1",
391        want = [":is_cp3.1_py3_none_any"],
392    )
393
394    _test_config_settings(
395        env,
396        filename = "foo-0.0.1-py3-none-any.whl",
397        python_version = "3.1",
398        target_platforms = ["linux_x86_64"],
399        want = [":is_cp3.1_py3_none_any_linux_x86_64"],
400    )
401
402_tests.append(_test_py3_none_any)
403
404def _test_py3_none_macosx_10_9_universal2(env):
405    _test_config_settings(
406        env,
407        filename = "foo-0.0.1-py3-none-macosx_10_9_universal2.whl",
408        python_version = "3.1",
409        osx_versions = [
410            (10, 9),
411            (11, 0),
412        ],
413        want = [],
414        want_versions = {
415            ":is_cp3.1_py3_none_osx_aarch64_universal2": {
416                (10, 9): ":is_cp3.1_py3_none_osx_10_9_aarch64_universal2",
417                (11, 0): ":is_cp3.1_py3_none_osx_11_0_aarch64_universal2",
418            },
419            ":is_cp3.1_py3_none_osx_x86_64_universal2": {
420                (10, 9): ":is_cp3.1_py3_none_osx_10_9_x86_64_universal2",
421                (11, 0): ":is_cp3.1_py3_none_osx_11_0_x86_64_universal2",
422            },
423        },
424    )
425
426_tests.append(_test_py3_none_macosx_10_9_universal2)
427
428def _test_cp37_abi3_linux_x86_64(env):
429    _test_config_settings(
430        env,
431        filename = "foo-0.0.1-cp37-abi3-linux_x86_64.whl",
432        python_version = "3.7",
433        want = [":is_cp3.7_cp3x_abi3_linux_x86_64"],
434    )
435
436_tests.append(_test_cp37_abi3_linux_x86_64)
437
438def _test_cp37_abi3_windows_x86_64(env):
439    _test_config_settings(
440        env,
441        filename = "foo-0.0.1-cp37-abi3-windows_x86_64.whl",
442        python_version = "3.7",
443        want = [":is_cp3.7_cp3x_abi3_windows_x86_64"],
444    )
445
446_tests.append(_test_cp37_abi3_windows_x86_64)
447
448def _test_cp37_abi3_manylinux_2_17_x86_64(env):
449    _test_config_settings(
450        env,
451        filename = "foo-0.0.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl",
452        python_version = "3.7",
453        glibc_versions = [
454            (2, 16),
455            (2, 17),
456            (2, 18),
457        ],
458        want = [],
459        want_versions = {
460            ":is_cp3.7_cp3x_abi3_manylinux_x86_64": {
461                (2, 17): ":is_cp3.7_cp3x_abi3_manylinux_2_17_x86_64",
462                (2, 18): ":is_cp3.7_cp3x_abi3_manylinux_2_18_x86_64",
463            },
464        },
465    )
466
467_tests.append(_test_cp37_abi3_manylinux_2_17_x86_64)
468
469def _test_cp37_abi3_manylinux_2_17_musllinux_1_1_aarch64(env):
470    # I've seen such a wheel being built for `uv`
471    _test_config_settings(
472        env,
473        filename = "foo-0.0.1-cp37-cp37-manylinux_2_17_arm64.musllinux_1_1_arm64.whl",
474        python_version = "3.7",
475        glibc_versions = [
476            (2, 16),
477            (2, 17),
478            (2, 18),
479        ],
480        muslc_versions = [
481            (1, 1),
482        ],
483        want = [],
484        want_versions = {
485            ":is_cp3.7_cp3x_cp_manylinux_aarch64": {
486                (2, 17): ":is_cp3.7_cp3x_cp_manylinux_2_17_aarch64",
487                (2, 18): ":is_cp3.7_cp3x_cp_manylinux_2_18_aarch64",
488            },
489            ":is_cp3.7_cp3x_cp_musllinux_aarch64": {
490                (1, 1): ":is_cp3.7_cp3x_cp_musllinux_1_1_aarch64",
491            },
492        },
493    )
494
495_tests.append(_test_cp37_abi3_manylinux_2_17_musllinux_1_1_aarch64)
496
497def render_pkg_aliases_test_suite(name):
498    """Create the test suite.
499
500    Args:
501        name: the name of the test suite
502    """
503    test_suite(name = name, basic_tests = _tests)
504