Skip to content

Commit 0ef12a1

Browse files
committed
Merge branch 'main' of https://github.com/bazel-contrib/rules_python into feat.default.bootstrap.script
2 parents fcb8435 + 8fc25de commit 0ef12a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1525
-1377
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,15 @@ Unreleased changes template.
7676
* (pypi) The PyPI extension will no longer write the lock file entries as the
7777
extension has been marked reproducible.
7878
Fixes [#2434](https://github.com/bazel-contrib/rules_python/issues/2434).
79+
* (rules) {attr}`py_binary.srcs` and {attr}`py_test.srcs` is no longer mandatory when
80+
`main_module` is specified (for `--bootstrap_impl=script`)
7981

8082
[20250317]: https://github.com/astral-sh/python-build-standalone/releases/tag/20250317
8183

8284
{#v0-0-0-fixed}
8385
### Fixed
86+
* (pypi) Platform specific extras are now correctly handled when using
87+
universal lock files with environment markers. Fixes [#2690](https://github.com/bazel-contrib/rules_python/pull/2690).
8488
* (runfiles) ({obj}`--bootstrap_impl=script`) Follow symlinks when searching for runfiles.
8589
* (toolchains) Do not try to run `chmod` when downloading non-windows hermetic toolchain
8690
repositories on Windows. Fixes
@@ -92,6 +96,7 @@ Unreleased changes template.
9296
* (toolchains) Run the check on the Python interpreter in isolated mode, to ensure it's not affected by userland environment variables, such as `PYTHONPATH`.
9397
* (toolchains) Ensure temporary `.pyc` and `.pyo` files are also excluded from the interpreters repository files.
9498
* (pypi) Run interpreter version call in isolated mode, to ensure it's not affected by userland environment variables, such as `PYTHONPATH`.
99+
* (packaging) An empty `requires_file` is treated as if it were omitted, resulting in a valid `METADATA` file.
95100

96101
{#v0-0-0-added}
97102
### Added
@@ -120,6 +125,8 @@ Unreleased changes template.
120125
* (toolchains) Local Python installs can be used to create a toolchain
121126
equivalent to the standard toolchains. See [Local toolchains] docs for how to
122127
configure them.
128+
* (toolchains) Expose `$(PYTHON2_ROOTPATH)` and `$(PYTHON3_ROOTPATH)` which are runfiles
129+
locations equivalents of `$(PYTHON2)` and `$(PYTHON3) respectively.
123130

124131

125132
{#v0-0-0-removed}

docs/requirements.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -351,13 +351,13 @@ sphinxcontrib-serializinghtml==2.0.0 \
351351
--hash=sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331 \
352352
--hash=sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d
353353
# via sphinx
354-
typing-extensions==4.12.2 \
355-
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
356-
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
354+
typing-extensions==4.13.2 \
355+
--hash=sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c \
356+
--hash=sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef
357357
# via
358358
# rules-python-docs (docs/pyproject.toml)
359359
# sphinx-autodoc2
360-
urllib3==2.3.0 \
361-
--hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \
362-
--hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d
360+
urllib3==2.4.0 \
361+
--hash=sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466 \
362+
--hash=sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813
363363
# via requests

docs/toolchains.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,11 @@ attribute. You can obtain the path to the Python interpreter using the
215215
`$(PYTHON2)` and `$(PYTHON3)` ["Make"
216216
Variables](https://bazel.build/reference/be/make-variables). See the
217217
{gh-path}`test_current_py_toolchain <tests/load_from_macro/BUILD.bazel>` target
218-
for an example.
218+
for an example. We also make available `$(PYTHON2_ROOTPATH)` and `$(PYTHON3_ROOTPATH)`
219+
which are Make Variable equivalents of `$(PYTHON2)` and `$(PYTHON3)` but for runfiles
220+
locations. These will be helpful if you need to set env vars of binary/test rules
221+
while using [`--nolegacy_external_runfiles`](https://bazel.build/reference/command-line-reference#flag--legacy_external_runfiles).
222+
The original make variables still work in exec contexts such as genrules.
219223

220224
### Overriding toolchain defaults and adding more versions
221225

examples/wheel/BUILD.bazel

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,12 @@ starlark # Example comment
294294
""".splitlines(),
295295
)
296296

297+
write_file(
298+
name = "empty_requires_file",
299+
out = "empty_requires.txt",
300+
content = [""],
301+
)
302+
297303
write_file(
298304
name = "extra_requires_file",
299305
out = "extra_requires.txt",
@@ -324,6 +330,15 @@ py_wheel(
324330
deps = [":example_pkg"],
325331
)
326332

333+
py_wheel(
334+
name = "empty_requires_files",
335+
distribution = "empty_requires_files",
336+
python_tag = "py3",
337+
requires_file = ":empty_requires.txt",
338+
version = "0.0.1",
339+
deps = [":example_pkg"],
340+
)
341+
327342
# Package just a specific py_libraries, without their dependencies
328343
py_wheel(
329344
name = "minimal_data_files",
@@ -367,6 +382,7 @@ py_test(
367382
":custom_package_root_multi_prefix",
368383
":custom_package_root_multi_prefix_reverse_order",
369384
":customized",
385+
":empty_requires_files",
370386
":extra_requires",
371387
":filename_escaping",
372388
":minimal_data_files",

examples/wheel/wheel_test.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,6 @@ def test_requires_file_and_extra_requires_files(self):
483483
if line.startswith(b"Requires-Dist:"):
484484
requires.append(line.decode("utf-8").strip())
485485

486-
print(requires)
487486
self.assertEqual(
488487
[
489488
"Requires-Dist: tomli>=2.0.0",
@@ -495,6 +494,29 @@ def test_requires_file_and_extra_requires_files(self):
495494
requires,
496495
)
497496

497+
def test_empty_requires_file(self):
498+
filename = self._get_path("empty_requires_files-0.0.1-py3-none-any.whl")
499+
500+
with zipfile.ZipFile(filename) as zf:
501+
self.assertAllEntriesHasReproducibleMetadata(zf)
502+
metadata_file = None
503+
for f in zf.namelist():
504+
if os.path.basename(f) == "METADATA":
505+
metadata_file = f
506+
self.assertIsNotNone(metadata_file)
507+
508+
metadata = zf.read(metadata_file).decode("utf-8")
509+
metadata_lines = metadata.splitlines()
510+
511+
requires = []
512+
for i, line in enumerate(metadata_lines):
513+
if line.startswith("Name:"):
514+
self.assertTrue(metadata_lines[i + 1].startswith("Version:"))
515+
if line.startswith("Requires-Dist:"):
516+
requires.append(line.strip())
517+
518+
self.assertEqual([], requires)
519+
498520
def test_minimal_data_files(self):
499521
filename = self._get_path("minimal_data_files-0.0.1-py3-none-any.whl")
500522

python/current_py_toolchain.bzl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ def _current_py_toolchain_impl(ctx):
2727
direct.append(toolchain.py3_runtime.interpreter)
2828
transitive.append(toolchain.py3_runtime.files)
2929
vars["PYTHON3"] = toolchain.py3_runtime.interpreter.path
30+
vars["PYTHON3_ROOTPATH"] = toolchain.py3_runtime.interpreter.short_path
3031

3132
if toolchain.py2_runtime and toolchain.py2_runtime.interpreter:
3233
direct.append(toolchain.py2_runtime.interpreter)
3334
transitive.append(toolchain.py2_runtime.files)
3435
vars["PYTHON2"] = toolchain.py2_runtime.interpreter.path
36+
vars["PYTHON2_ROOTPATH"] = toolchain.py2_runtime.interpreter.short_path
3537

3638
files = depset(direct, transitive = transitive)
3739
return [
@@ -49,6 +51,11 @@ current_py_toolchain = rule(
4951
other rules, such as genrule. It allows exposing a python toolchain after toolchain resolution has
5052
happened, to a rule which expects a concrete implementation of a toolchain, rather than a
5153
toolchain_type which could be resolved to that toolchain.
54+
55+
:::{versionchanged} VERSION_NEXT_FEATURE
56+
From now on, we also expose `$(PYTHON2_ROOTPATH)` and `$(PYTHON3_ROOTPATH)` which are runfiles
57+
locations equivalents of `$(PYTHON2)` and `$(PYTHON3) respectively.
58+
:::
5259
""",
5360
implementation = _current_py_toolchain_impl,
5461
attrs = {

python/packaging.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ def py_wheel(
101101
102102
Currently only pure-python wheels are supported.
103103
104+
:::{versionchanged} VERSION_NEXT_FEATURE
105+
From now on, an empty `requires_file` is treated as if it were omitted, resulting in a valid
106+
`METADATA` file.
107+
:::
108+
104109
Examples:
105110
106111
```python

python/private/py_executable.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,8 @@ def _create_stage1_bootstrap(
802802
)
803803
template = runtime.bootstrap_template
804804
subs["%shebang%"] = runtime.stub_shebang
805+
elif not ctx.files.srcs:
806+
fail("mandatory 'srcs' files have not been provided")
805807
else:
806808
if (ctx.configuration.coverage_enabled and
807809
runtime and
@@ -1904,7 +1906,6 @@ def create_executable_rule_builder(implementation, **kwargs):
19041906
),
19051907
**kwargs
19061908
)
1907-
builder.attrs.get("srcs").set_mandatory(True)
19081909
return builder
19091910

19101911
def cc_configure_features(

python/private/pypi/BUILD.bazel

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ bzl_library(
7777
deps = [
7878
":pep508_env_bzl",
7979
":pep508_evaluate_bzl",
80-
":pep508_req_bzl",
80+
":pep508_platform_bzl",
81+
":pep508_requirement_bzl",
8182
],
8283
)
8384

@@ -220,9 +221,24 @@ bzl_library(
220221
],
221222
)
222223

224+
bzl_library(
225+
name = "pep508_deps_bzl",
226+
srcs = ["pep508_deps.bzl"],
227+
deps = [
228+
":pep508_env_bzl",
229+
":pep508_evaluate_bzl",
230+
":pep508_platform_bzl",
231+
":pep508_requirement_bzl",
232+
"//python/private:normalize_name_bzl",
233+
],
234+
)
235+
223236
bzl_library(
224237
name = "pep508_env_bzl",
225238
srcs = ["pep508_env.bzl"],
239+
deps = [
240+
":pep508_platform_bzl",
241+
],
226242
)
227243

228244
bzl_library(
@@ -235,8 +251,13 @@ bzl_library(
235251
)
236252

237253
bzl_library(
238-
name = "pep508_req_bzl",
239-
srcs = ["pep508_req.bzl"],
254+
name = "pep508_platform_bzl",
255+
srcs = ["pep508_platform.bzl"],
256+
)
257+
258+
bzl_library(
259+
name = "pep508_requirement_bzl",
260+
srcs = ["pep508_requirement.bzl"],
240261
deps = [
241262
"//python/private:normalize_name_bzl",
242263
],
@@ -359,7 +380,9 @@ bzl_library(
359380
":generate_whl_library_build_bazel_bzl",
360381
":parse_whl_name_bzl",
361382
":patch_whl_bzl",
383+
":pep508_deps_bzl",
362384
":pypi_repo_utils_bzl",
385+
":whl_metadata_bzl",
363386
":whl_target_platforms_bzl",
364387
"//python/private:auth_bzl",
365388
"//python/private:envsubst_bzl",
@@ -368,6 +391,11 @@ bzl_library(
368391
],
369392
)
370393

394+
bzl_library(
395+
name = "whl_metadata_bzl",
396+
srcs = ["whl_metadata.bzl"],
397+
)
398+
371399
bzl_library(
372400
name = "whl_repo_name_bzl",
373401
srcs = ["whl_repo_name.bzl"],

python/private/pypi/evaluate_markers.bzl

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

1515
"""A simple function that evaluates markers using a python interpreter."""
1616

17-
load(":pep508_env.bzl", "env", _platform_from_str = "platform_from_str")
17+
load(":pep508_env.bzl", "env")
1818
load(":pep508_evaluate.bzl", "evaluate")
19-
load(":pep508_req.bzl", _req = "requirement")
19+
load(":pep508_platform.bzl", "platform_from_str")
20+
load(":pep508_requirement.bzl", "requirement")
2021

2122
def evaluate_markers(requirements):
2223
"""Return the list of supported platforms per requirements line.
@@ -29,9 +30,9 @@ def evaluate_markers(requirements):
2930
"""
3031
ret = {}
3132
for req_string, platforms in requirements.items():
32-
req = _req(req_string)
33+
req = requirement(req_string)
3334
for platform in platforms:
34-
if evaluate(req.marker, env = env(_platform_from_str(platform, None))):
35+
if evaluate(req.marker, env = env(platform_from_str(platform, None))):
3536
ret.setdefault(req_string, []).append(platform)
3637

3738
return ret

0 commit comments

Comments
 (0)