From dc14fc80dba9eebf55fe574400c07bfd73780302 Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius <240938+aignas@users.noreply.github.com> Date: Mon, 24 Nov 2025 16:08:10 +0900 Subject: [PATCH] refactor(pypi): use py_console_script_binary in whl_library_targets TODO: - [ ] Fix tests Work towards #2948 --- .../pypi/generate_whl_library_build_bazel.bzl | 2 +- python/private/pypi/whl_library.bzl | 81 +------------------ python/private/pypi/whl_library_targets.bzl | 44 ++++++---- 3 files changed, 33 insertions(+), 94 deletions(-) diff --git a/python/private/pypi/generate_whl_library_build_bazel.bzl b/python/private/pypi/generate_whl_library_build_bazel.bzl index e207f6d2f5..bfdc4b45e2 100644 --- a/python/private/pypi/generate_whl_library_build_bazel.bzl +++ b/python/private/pypi/generate_whl_library_build_bazel.bzl @@ -23,7 +23,7 @@ _RENDER = { "data_exclude": render.list, "dependencies": render.list, "dependencies_by_platform": lambda x: render.dict(x, value_repr = render.list), - "entry_points": render.dict, + "entry_points": render.list, "extras": render.list, "group_deps": render.list, "include": str, diff --git a/python/private/pypi/whl_library.bzl b/python/private/pypi/whl_library.bzl index 5db7bc49a1..708ff294ee 100644 --- a/python/private/pypi/whl_library.bzl +++ b/python/private/pypi/whl_library.bzl @@ -30,7 +30,6 @@ load(":whl_target_platforms.bzl", "whl_target_platforms") _CPPFLAGS = "CPPFLAGS" _COMMAND_LINE_TOOLS_PATH_SLUG = "commandlinetools" -_WHEEL_ENTRY_POINT_PREFIX = "rules_python_wheel_entry_point" def _get_xcode_location_cflags(rctx, logger = None): """Query the xcode sdk location to update cflags @@ -399,30 +398,6 @@ def _whl_library_impl(rctx): logger = logger, ) - # NOTE @aignas 2024-06-22: this has to live on until we stop supporting - # passing `twine` as a `:pkg` library via the `WORKSPACE` builds. - # - # See ../../packaging.bzl line 190 - entry_points = {} - for item in metadata.entry_points: - name = item.name - module = item.module - attribute = item.attribute - - # There is an extreme edge-case with entry_points that end with `.py` - # See: https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/test/java/com/google/devtools/build/lib/rules/python/PyBinaryConfiguredTargetTest.java#L174 - entry_point_without_py = name[:-3] + "_py" if name.endswith(".py") else name - entry_point_target_name = ( - _WHEEL_ENTRY_POINT_PREFIX + "_" + entry_point_without_py - ) - entry_point_script_name = entry_point_target_name + ".py" - - rctx.file( - entry_point_script_name, - _generate_entry_point_contents(module, attribute), - ) - entry_points[entry_point_without_py] = entry_point_script_name - build_file_contents = generate_whl_library_build_bazel( name = whl_path.basename, sdist_filename = sdist_filename, @@ -430,7 +405,7 @@ def _whl_library_impl(rctx): rctx.attr.repo_prefix, ), config_load = rctx.attr.config_load, - entry_points = entry_points, + entry_points = [e.name for e in metadata.entry_points], metadata_name = metadata.name, metadata_version = metadata.version, requires_dist = metadata.requires_dist, @@ -476,35 +451,11 @@ def _whl_library_impl(rctx): metadata = json.decode(rctx.read("metadata.json")) rctx.delete("metadata.json") - # NOTE @aignas 2024-06-22: this has to live on until we stop supporting - # passing `twine` as a `:pkg` library via the `WORKSPACE` builds. - # - # See ../../packaging.bzl line 190 - entry_points = {} - for item in metadata["entry_points"]: - name = item["name"] - module = item["module"] - attribute = item["attribute"] - - # There is an extreme edge-case with entry_points that end with `.py` - # See: https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/test/java/com/google/devtools/build/lib/rules/python/PyBinaryConfiguredTargetTest.java#L174 - entry_point_without_py = name[:-3] + "_py" if name.endswith(".py") else name - entry_point_target_name = ( - _WHEEL_ENTRY_POINT_PREFIX + "_" + entry_point_without_py - ) - entry_point_script_name = entry_point_target_name + ".py" - - rctx.file( - entry_point_script_name, - _generate_entry_point_contents(module, attribute), - ) - entry_points[entry_point_without_py] = entry_point_script_name - build_file_contents = generate_whl_library_build_bazel( name = whl_path.basename, sdist_filename = sdist_filename, dep_template = rctx.attr.dep_template or "@{}{{name}}//:{{target}}".format(rctx.attr.repo_prefix), - entry_points = entry_points, + entry_points = [e["name"] for e in metadata["entry_points"]], # TODO @aignas 2025-05-17: maybe have a build flag for this instead enable_implicit_namespace_pkgs = rctx.attr.enable_implicit_namespace_pkgs, # TODO @aignas 2025-04-14: load through the hub: @@ -542,34 +493,6 @@ def _whl_library_impl(rctx): rctx.file("BUILD.bazel", build_file_contents) return -def _generate_entry_point_contents( - module, - attribute, - shebang = "#!/usr/bin/env python3"): - """Generate the contents of an entry point script. - - Args: - module (str): The name of the module to use. - attribute (str): The name of the attribute to call. - shebang (str, optional): The shebang to use for the entry point python - file. - - Returns: - str: A string of python code. - """ - contents = """\ -{shebang} -import sys -from {module} import {attribute} -if __name__ == "__main__": - sys.exit({attribute}()) -""".format( - shebang = shebang, - module = module, - attribute = attribute, - ) - return contents - # NOTE @aignas 2024-03-21: The usage of dict({}, **common) ensures that all args to `dict` are unique whl_library_attrs = dict({ "annotation": attr.label( diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl index a2d77daf4c..9b537b6631 100644 --- a/python/private/pypi/whl_library_targets.bzl +++ b/python/private/pypi/whl_library_targets.bzl @@ -17,6 +17,7 @@ load("@bazel_skylib//rules:copy_file.bzl", "copy_file") load("//python:py_binary.bzl", "py_binary") load("//python:py_library.bzl", "py_library") +load("//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary") load("//python/private:normalize_name.bzl", "normalize_name") load(":env_marker_setting.bzl", "env_marker_setting") load( @@ -42,6 +43,7 @@ _BAZEL_REPO_FILE_GLOBS = [ "WORKSPACE", "WORKSPACE.bazel", ] +_WHEEL_ENTRY_POINT_PREFIX = "rules_python_wheel_entry_point" def whl_library_targets_from_requires( *, @@ -126,6 +128,7 @@ def whl_library_targets( rules = struct( copy_file = copy_file, py_binary = py_binary, + py_console_script_binary = py_console_script_binary, py_library = py_library, env_marker_setting = env_marker_setting, create_inits = _create_inits, @@ -234,20 +237,6 @@ def whl_library_targets( for d in dependencies_with_markers } - # TODO @aignas 2024-10-25: remove the entry_point generation once - # `py_console_script_binary` is the only way to use entry points. - for entry_point, entry_point_script_name in entry_points.items(): - rules.py_binary( - name = "{}_{}".format(WHEEL_ENTRY_POINT_PREFIX, entry_point), - # Ensure that this works on Windows as well - script may have Windows path separators. - srcs = [entry_point_script_name.replace("\\", "/")], - # This makes this directory a top-level in the python import - # search path for anything that depends on this. - imports = ["."], - deps = [":" + PY_LIBRARY_PUBLIC_LABEL], - visibility = ["//visibility:public"], - ) - # Ensure this list is normalized # Note: mapping used as set group_deps = { @@ -315,6 +304,33 @@ def whl_library_targets( whl_file_label = WHEEL_FILE_PUBLIC_LABEL impl_vis = ["//visibility:public"] + for entry_point in entry_points: + # NOTE @aignas 2024-06-22: this has to live on until we stop supporting + # passing `twine` as a `:pkg` library via the `WORKSPACE` builds. + # + # See ../../packaging.bzl line 190 + + # There is an extreme edge-case with entry_points that end with `.py` + # See: https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/test/java/com/google/devtools/build/lib/rules/python/PyBinaryConfiguredTargetTest.java#L174 + entry_point_without_py = entry_point[:-3] + "_py" if entry_point.endswith(".py") else entry_point + entry_point_target_name = ( + _WHEEL_ENTRY_POINT_PREFIX + "_" + entry_point_without_py + ) + entry_point_script_name = entry_point_target_name + ".py" + + rules.py_console_script_binary( + name = "{}_{}".format(WHEEL_ENTRY_POINT_PREFIX, entry_point), + pkg = PY_LIBRARY_PUBLIC_LABEL, + entry_points_txt = DIST_INFO_LABEL, + script = entry_point, + main = entry_point_script_name, + shebang = "#!/usr/bin/env python3", + # This makes this directory a top-level in the python import + # search path for anything that depends on this. + imports = ["."], + visibility = ["//visibility:public"], + ) + if hasattr(native, "filegroup"): native.filegroup( name = whl_file_label,