8000 feat: add aliases for entry_points · bazel-contrib/rules_python@04584d4 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 04584d4

Browse files
committed
feat: add aliases for entry_points
1 parent a15a6e8 commit 04584d4

File tree

6 files changed

+120
-19
lines changed

6 files changed

+120
-19
lines changed

python/extensions/pip.bzl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ load(
2525
)
2626
load("@rules_python//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
2727
load("//python:versions.bzl", "MINOR_MAPPING")
28+
load("//python/private:version_label.bzl", "version_label")
2829

2930
def _create_versioned_pip_and_whl_repos(module_ctx, pip_attr, whl_map):
3031
python_interpreter_target = pip_attr.python_interpreter_target
@@ -33,7 +34,7 @@ def _create_versioned_pip_and_whl_repos(module_ctx, pip_attr, whl_map):
3334
# we programtically find it.
3435
hub_name = pip_attr.hub_name
3536
if python_interpreter_target == None:
36-
python_name = "python_{}".format(pip_attr.python_version.replace(".", "_"))
37+
python_name = "python_" + version_label(pip_attr.python_version, sep = "_")
3738
if python_name not in INTERPRETER_LABELS.keys():
3839
fail((
3940
"Unable to find interpreter for pip hub '{hub_name}' for " +
@@ -45,7 +46,10 @@ def _create_versioned_pip_and_whl_repos(module_ctx, pip_attr, whl_map):
4546
))
4647
python_interpreter_target = INTERPRETER_LABELS[python_name]
4748

48-
pip_name = hub_name + "_{}".format(pip_attr.python_version.replace(".", ""))
49+
pip_name = "{}_{}".format(
50+
hub_name,
51+
version_label(pip_attr.python_version),
52+
)
4953
requrements_lock = locked_requirements_label(module_ctx, pip_attr)
5054

5155
# Parse the requirements file directly in starlark to get the information

python/extensions/private/hub_repository.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def _impl(rctx):
4949
# a string and the resolution of the label happens at the call-site of the
5050
# `requirement`, et al. macros.
5151
macro_tmpl = "@@{name}//{{}}:{{}}".format(name = rctx.attr.name)
52-
entrypoint_tmpl = "@@{name}_{{version_label}}_{{pkg}}//:rules_python_wheel_entry_point_{{script}}".format(name = rctx.attr.name)
52+
entrypoint_tmpl = "@@{name}//{{pkg}}/bin_py{{version_label}}:{{script}}".format(name = rctx.attr.name)
5353

5454
rctx.file("BUILD.bazel", build_contents)
5555
rctx.template("requirements.bzl", rctx.attr._template, substitutions = {

python/pip_install/entrypoint.bzl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414

1515
"entry_point macro implementation for bzlmod. PRIVATE ONLY."
1616

17+
load("//python/private:version_label.bzl", "version_label")
18+
1719
def entry_point(*, pkg, packages, default_version, tmpl, script = None):
18-
"""Return an entry_point script.
20+
"""Return an entry_point script dictionary for a select statement.
1921
2022
Args:
2123
pkg: the package name.
@@ -42,7 +44,7 @@ def entry_point(*, pkg, packages, default_version, tmpl, script = None):
4244
condition = str(Label("//python/config_settings:is_python_{}".format(full_version)))
4345

4446
entry_point = tmpl.format(
45-
version_label = full_version.rpartition(".")[0].replace(".", ""),
47+
version_label = version_label(full_version),
4648
pkg = pkg,
4749
script = script,
4850
)

python/pip_install/tools/wheel_installer/wheel_installer.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import json
1919
import os
2020
import re
21-
import shutil
2221
import subprocess
2322
import sys
2423
import textwrap
@@ -226,7 +225,7 @@ def _generate_build_file_contents(
226225
"**/* *",
227226
"**/*.py",
228227
"**/*.pyc",
229-
"**/*.pyc.*", # During pyc creation, temp files named *.pyc.NNNN are created
228+
"**/*.pyc.*", # During pyc creation, temp files named *.pyc.NNNN are created
230229
# RECORD is known to contain sha256 checksums of files which might include the checksums
231230
# of generated files produced when wheels are installed. The file is ignored to avoid
232231
# Bazel caching issues.
@@ -329,7 +328,7 @@ def _extract_wheel(
329328
bazel.sanitised_repo_file_label(d, repo_prefix=repo_prefix) for d in whl_deps
330329
]
331330

332-
entry_points = []
331+
entry_points = {}
333332
for name, (module, attribute) in sorted(whl.entry_points().items()):
334333
# There is an extreme edge-case with entry_points that end with `.py`
335334
# See: https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/test/java/com/google/devtools/build/lib/rules/python/PyBinaryConfiguredTargetTest.java#L174
@@ -341,16 +340,14 @@ def _extract_wheel(
341340
(installation_dir / entry_point_script_name).write_text(
342341
_generate_entry_point_contents(module, attribute)
343342
)
344-
entry_points.append(
345-
_generate_entry_point_rule(
346-
entry_point_target_name,
347-
entry_point_script_name,
348-
bazel.PY_LIBRARY_LABEL,
349-
)
343+
entry_points[entry_point_without_py] = _generate_entry_point_rule(
344+
entry_point_target_name,
345+
entry_point_script_name,
346+
bazel.PY_LIBRARY_LABEL,
350347
)
351348

352349
with open(os.path.join(installation_dir, "BUILD.bazel"), "w") as build_file:
353-
additional_content = entry_points
350+
additional_content = list(entry_points.values())
354351
data = []
355352
data_exclude = pip_data_exclude
356353
srcs_exclude = []
@@ -381,6 +378,34 @@ def _extract_wheel(
381378
)
382379
build_file.write(contents)
383380

381+
with open(
382+
os.path.join(installation_dir, "entrypoints.bzl"), "w"
383+
) as entry_point_file:
384+
entrypoints_str = ""
385+
if entry_points:
386+
entrypoints_str = "\n" + "".join(
387+
[
388+
f' "{script}": "{bazel.WHEEL_ENTRY_POINT_PREFIX}_{script}",\n'
389+
for script in sorted(entry_points.keys())
390+
]
391+
)
392+
393+
contents = textwrap.dedent(
394+
"""\
395+
\"\"\"
396+
This file contains the entrypoint script names as a dict, where the keys
397+
are the script names and the values are the target names.
398+
399+
generated by @rules_python//python/pip_install/tools/wheel_installer/wheel_installer.py
400+
\"\"\"
401+
402+
entrypoints = {{{}}}
403+
"""
404+
).format(entrypoints_str)
405+
406+
print(contents)
407+
entry_point_file.write(contents)
408+
384409

385410
def main() -> None:
386411
parser = argparse.ArgumentParser(

python/private/create_pkg_aliases.bzl

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"A repository rule to write BUILD.bazel files with aliases to packages."
1616

1717
load("//python:versions.bzl", "MINOR_MAPPING")
18+
load(":version_label.bzl", "version_label")
1819

1920
_DEFAULT = """\
2021
alias(
@@ -25,7 +26,7 @@ alias(
2526
_SELECT = """\
2627
alias(
2728
name = "{name}",
28-
actual = select({selects}),
29+
actual = select({{{selects}}}),
2930
)"""
3031

3132
def _render(
@@ -55,23 +56,45 @@ def _render(
5556
)
5657
actual = "@{repo_name}_{version}_{dep}//:{target}".format(
5758
repo_name = repo_name,
58-
version = version.rpartition(".")[0].replace(".", ""),
59+
version = version_label(version),
5960
dep = dep,
6061
target = target,
6162
)
6263
selects[condition] = actual
6364

6465
default_actual = "@{repo_name}_{version}_{dep}//:{target}".format(
6566
repo_name = repo_name,
66-
version = versions[-1].replace(".", ""),
67+
version = version_label(versions[-1]),
6768
dep = dep,
6869
target = target,
6970
)
7071
selects["//conditions:default"] = default_actual
7172

7273
return _SELECT.format(
7374
name = name,
74-
selects = repr(selects),
75+
selects = "\n{} ".format(
76+
"".join([
77+
" {}: {},\n".format(repr(k), repr(v))
78+
for k, v in selects.items()
79+
]),
80+
),
81+
)
82+
83+
def _render_entrypoints(repo_name, dep):
84+
return """\
85+
load("@{repo_name}_{dep}//:entrypoints.bzl", "entrypoints")
86+
87+
[
88+
alias(
89+
name = script,
90+
actual = "@{repo_name}_{dep}//:" + target,
91+
visibility = ["//visibility:public"],
92+
)
93+
for script, target in entrypoints.items()
94+
]
95+
""".format(
96+
repo_name = repo_name,
97+
dep = dep,
7598
)
7699

77100
def create_pkg_aliases(rctx, repo_name, bzl_packages, whl_map = None, rules_python = None):
@@ -102,3 +125,15 @@ def create_pkg_aliases(rctx, repo_name, bzl_packages, whl_map = None, rules_pyth
102125
])
103126

104127
rctx.file("{}/BUILD.bazel".format(name), build_content)
128+
129+
if versions == None:
130+
build_content = _render_entrypoints(repo_name = repo_name, dep = name)
131+
rctx.file("{}/bin/BUILD.bazel".format(name), build_content)
132+
return
133+
134+
# NOTE @aignas 2023-07-07: we are not creating aliases using a select
135+
# and the version specific aliases because we would need to fetch the
136+
# package for all versions in order to construct the said select.
137+
for version in versions:
138+
build_content = _render_entrypoints(repo_name = "{}_{}".format(repo_name, version_label(version)), dep = name)
139+
rctx.file("{}/bin_py{}/BUILD.bazel".format(name, version_label(version)), build_content)

python/private/version_label.bzl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
""
16+
17+
load("//python:versions.bzl", "MINOR_MAPPING")
18+
19+
def version_label(version, *, sep = ""):
20+
"""A version fragment derived from python minor version
21+
22+
Examples:
23+
version_label("3.9") == "39"
24+
version_label("3.9.12", sep="_") == "3_9"
25+
version_label("3.11") == "311"
26+
27+
Args:
28+
version: Python version.
29+
sep: The separator between major and minor version numbers, defaults
30+
to an empty string.
31+
32+
Returns:
33+
The fragment of the version.
34+
"""
35+
return MINOR_MAPPING.get(version, version).rpartition(".")[0].replace(".", sep)

0 commit comments

Comments
 (0)
0