Skip to content

Commit 513c8bb

Browse files
committed
Merge branch 'main' into aignas.exp.bzlmod.enable.pipstar
2 parents 4b18416 + 79f6546 commit 513c8bb

Some content is hidden

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

53 files changed

+1051
-441
lines changed

CHANGELOG.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ END_UNRELEASED_TEMPLATE
6969
* (bootstrap) For {obj}`--bootstrap_impl=system_python`, the sys.path order has
7070
changed from `[app paths, stdlib, runtime site-packages]` to `[stdlib, app
7171
paths, runtime site-packages]`.
72+
* (pip) Publishing deps are no longer pulled via `experimental_index_url`.
73+
([#2937](https://github.com/bazel-contrib/rules_python/issues/2937)).
74+
* (toolchains) `py_runtime` and `PyRuntimeInfo` reject Python 2 settings.
75+
Setting `py_runtime.python_version = "PY2"` or non-None
76+
`PyRuntimeInfo.py2_runtime` is an error.
7277
* (pypi) `pipstar` flag has been flipped to be enabled by default, to turn it
7378
off use `RULES_PYTHON_ENABLE_PIPSTAR=0` environment variable. If you do, please
7479
add a comment to
@@ -78,16 +83,24 @@ END_UNRELEASED_TEMPLATE
7883

7984
{#v0-0-0-fixed}
8085
### Fixed
86+
* (rules) The `PyInfo` constructor was setting the wrong value for
87+
`has_py3_only_sources` - this is now fixed.
8188
* (bootstrap) The stage1 bootstrap script now correctly handles nested `RUNFILES_DIR`
8289
environments, fixing issues where a `py_binary` calls another `py_binary`
8390
([#3187](https://github.com/bazel-contrib/rules_python/issues/3187)).
8491
* (bootstrap) For Windows, having many dependencies no longer results in max
8592
length errors due to too long environment variables.
8693
* (bootstrap) {obj}`--bootstrap_impl=script` now supports the `-S` interpreter
8794
setting.
88-
* (venvs) {obj}`--vens_site_packages=yes` no longer errors when packages with
95+
* (venvs) {obj}`--venvs_site_packages=yes` no longer errors when packages with
8996
overlapping files or directories are used together.
9097
([#3204](https://github.com/bazel-contrib/rules_python/issues/3204)).
98+
* (uv) {obj}`//python/uv:lock.bzl%lock` now works with a local platform
99+
runtime.
100+
* (toolchains) WORKSPACE builds now correctly register musl and freethreaded
101+
variants. Setting {obj}`--py_linux_libc=musl` and `--py_freethreaded=yes` now
102+
activate them, respectively.
103+
([#3262](https://github.com/bazel-contrib/rules_python/issues/3262)).
91104

92105
{#v0-0-0-added}
93106
### Added
@@ -113,6 +126,7 @@ END_UNRELEASED_TEMPLATE
113126
{obj}`py_cc_toolchain.headers_abi3`, and {obj}`PyCcToolchainInfo.headers_abi3`.
114127
* {obj}`//python:features.bzl%features.headers_abi3` can be used to
115128
feature-detect the presense of the above.
129+
* (toolchains) Local toolchains can use a label for the interpreter to use.
116130

117131
{#v1-6-3}
118132
## [1.6.3] - 2025-09-21

MODULE.bazel

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,12 @@ python = use_extension("//python/extensions:python.bzl", "python")
4242
# NOTE: This is not a stable version. It is provided for convenience, but will
4343
# change frequently to track the most recent Python version.
4444
# NOTE: The root module can override this.
45+
# NOTE: There must be a corresponding `python.toolchain()` call for the version
46+
# specified here.
47+
python.defaults(
48+
python_version = "3.11",
49+
)
4550
python.toolchain(
46-
is_default = True,
4751
python_version = "3.11",
4852
)
4953
use_repo(
@@ -168,12 +172,6 @@ pip = use_extension("//python/extensions:pip.bzl", "pip")
168172
]
169173

170174
pip.parse(
171-
# NOTE @aignas 2024-10-26: We have an integration test that depends on us
172-
# being able to build sdists for this hub, so explicitly set this to False.
173-
#
174-
# how do we test sdists? Maybe just worth adding a single sdist somewhere?
175-
download_only = False,
176-
experimental_index_url = "https://pypi.org/simple",
177175
hub_name = "rules_python_publish_deps",
178176
python_version = "3.11",
179177
requirements_by_platform = {

docs/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ sphinx_stardocs(
106106
"//python/cc:py_cc_toolchain_bzl",
107107
"//python/cc:py_cc_toolchain_info_bzl",
108108
"//python/entry_points:py_console_script_binary_bzl",
109+
"//python/extensions:config_bzl",
109110
"//python/extensions:python_bzl",
110111
"//python/local_toolchains:repos_bzl",
111112
"//python/private:attr_builders_bzl",

docs/requirements.txt

Lines changed: 164 additions & 116 deletions
Large diffs are not rendered by default.

docs/toolchains.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ local_runtime_toolchains_repo(
460460
register_toolchains("@local_toolchains//:all", dev_dependency = True)
461461
```
462462

463+
In the example above, `interpreter_path` is used to find Python via `PATH`
464+
lookups. Alternatively, {obj}`interpreter_target` can be set, which can
465+
refer to a Python in an arbitrary Bazel repository.
466+
463467
:::{important}
464468
Be sure to set `dev_dependency = True`. Using a local toolchain only makes sense
465469
for the root module.

python/BUILD.bazel

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ bzl_library(
126126
srcs = ["py_binary.bzl"],
127127
deps = [
128128
"//python/private:py_binary_macro_bzl",
129-
"//python/private:register_extension_info_bzl",
130129
],
131130
)
132131

@@ -175,7 +174,6 @@ bzl_library(
175174
srcs = ["py_library.bzl"],
176175
deps = [
177176
"//python/private:py_library_macro_bzl",
178-
"//python/private:register_extension_info_bzl",
179177
],
180178
)
181179

@@ -208,7 +206,6 @@ bzl_library(
208206
srcs = ["py_test.bzl"],
209207
deps = [
210208
"//python/private:py_test_macro_bzl",
211-
"//python/private:register_extension_info_bzl",
212209
],
213210
)
214211

python/private/BUILD.bazel

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,10 @@ bzl_library(
197197
bzl_library(
198198
name = "internal_config_repo_bzl",
199199
srcs = ["internal_config_repo.bzl"],
200-
deps = [":bzlmod_enabled_bzl"],
200+
deps = [
201+
":repo_utils_bzl",
202+
":text_util_bzl",
203+
],
201204
)
202205

203206
bzl_library(
@@ -528,6 +531,7 @@ bzl_library(
528531
":py_runtime_info_bzl",
529532
":reexports_bzl",
530533
":rule_builders_bzl",
534+
":version_bzl",
531535
"@bazel_skylib//lib:dicts",
532536
"@bazel_skylib//lib:paths",
533537
"@bazel_skylib//rules:common_settings",
@@ -608,11 +612,6 @@ bzl_library(
608612
],
609613
)
610614

611-
bzl_library(
612-
name = "register_extension_info_bzl",
613-
srcs = ["register_extension_info.bzl"],
614-
)
615-
616615
bzl_library(
617616
name = "repo_utils_bzl",
618617
srcs = ["repo_utils.bzl"],

python/private/attributes.bzl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,6 @@ REQUIRED_EXEC_GROUP_BUILDERS = {
4444
"py_precompile": lambda: ruleb.ExecGroup(),
4545
}
4646

47-
# Backwards compatibility symbol for Google.
48-
REQUIRED_EXEC_GROUPS = {
49-
k: v().build()
50-
for k, v in REQUIRED_EXEC_GROUP_BUILDERS.items()
51-
}
52-
5347
_STAMP_VALUES = [-1, 0, 1]
5448

5549
def _precompile_attr_get_effective_value(ctx):

python/private/flags.bzl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ load(":enum.bzl", "FlagEnum", "enum")
3939
_POSSIBLY_NATIVE_FLAGS = {
4040
"build_python_zip": (lambda ctx: ctx.fragments.py.build_python_zip, "native"),
4141
"default_to_explicit_init_py": (lambda ctx: ctx.fragments.py.default_to_explicit_init_py, "native"),
42-
"disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native"),
4342
"python_import_all_repositories": (lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories, "native"),
4443
"python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"),
4544
}

python/private/local_runtime_repo.bzl

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,37 @@ a system having the necessary Python installed.
200200
doc = """
201201
An absolute path or program name on the `PATH` env var.
202202
203+
*Mutually exclusive with `interpreter_target`.*
204+
203205
Values with slashes are assumed to be the path to a program. Otherwise, it is
204206
treated as something to search for on `PATH`
205207
206208
Note that, when a plain program name is used, the path to the interpreter is
207209
resolved at repository evalution time, not runtime of any resulting binaries.
210+
211+
If not set, defaults to `python3`.
212+
213+
:::{seealso}
214+
The {obj}`interpreter_target` attribute for getting the interpreter from
215+
a label
216+
:::
217+
""",
218+
default = "",
219+
),
220+
"interpreter_target": attr.label(
221+
doc = """
222+
A label to a Python interpreter executable.
223+
224+
*Mutually exclusive with `interpreter_path`.*
225+
226+
On Windows, if the path doesn't exist, various suffixes will be tried to
227+
find a usable path.
228+
229+
:::{seealso}
230+
The {obj}`interpreter_path` attribute for getting the interpreter from
231+
a path or PATH environment lookup.
232+
:::
208233
""",
209-
default = "python3",
210234
),
211235
"on_failure": attr.string(
212236
default = _OnFailure.SKIP,
@@ -247,6 +271,37 @@ def _expand_incompatible_template():
247271
os = "@platforms//:incompatible",
248272
)
249273

274+
def _find_python_exe_from_target(rctx):
275+
base_path = rctx.path(rctx.attr.interpreter_target)
276+
if base_path.exists:
277+
return base_path, None
278+
attempted_paths = [base_path]
279+
280+
# Try to convert a unix-y path to a Windows path. On Linux/Mac,
281+
# the path is usually `bin/python3`. On Windows, it's simply
282+
# `python.exe`.
283+
basename = base_path.basename.rstrip("3")
284+
path = base_path.dirname.dirname.get_child(basename)
285+
path = rctx.path("{}.exe".format(path))
286+
if path.exists:
287+
return path, None
288+
attempted_paths.append(path)
289+
290+
# Try adding .exe to the base path
291+
path = rctx.path("{}.exe".format(base_path))
292+
if path.exists:
293+
return path, None
294+
attempted_paths.append(path)
295+
296+
describe_failure = lambda: (
297+
"Target '{target}' could not be resolved to a valid path. " +
298+
"Attempted paths: {paths}"
299+
).format(
300+
target = rctx.attr.interpreter_target,
301+
paths = "\n".join([str(p) for p in attempted_paths]),
302+
)
303+
return None, describe_failure
304+
250305
def _resolve_interpreter_path(rctx):
251306
"""Find the absolute path for an interpreter.
252307
@@ -260,20 +315,27 @@ def _resolve_interpreter_path(rctx):
260315
returns a description of why it couldn't be resolved
261316
A path object or None. The path may not exist.
262317
"""
263-
if "/" not in rctx.attr.interpreter_path and "\\" not in rctx.attr.interpreter_path:
264-
# Provide a bit nicer integration with pyenv: recalculate the runtime if the
265-
# user changes the python version using e.g. `pyenv shell`
266-
repo_utils.getenv(rctx, "PYENV_VERSION")
267-
result = repo_utils.which_unchecked(rctx, rctx.attr.interpreter_path)
268-
resolved_path = result.binary
269-
describe_failure = result.describe_failure
318+
if rctx.attr.interpreter_path and rctx.attr.interpreter_target:
319+
fail("interpreter_path and interpreter_target are mutually exclusive")
320+
321+
if rctx.attr.interpreter_target:
322+
resolved_path, describe_failure = _find_python_exe_from_target(rctx)
270323
else:
271-
rctx.watch(rctx.attr.interpreter_path)
272-
resolved_path = rctx.path(rctx.attr.interpreter_path)
273-
if not resolved_path.exists:
274-
describe_failure = lambda: "Path not found: {}".format(repr(rctx.attr.interpreter_path))
324+
interpreter_path = rctx.attr.interpreter_path or "python3"
325+
if "/" not in interpreter_path and "\\" not in interpreter_path:
326+
# Provide a bit nicer integration with pyenv: recalculate the runtime if the
327+
# user changes the python version using e.g. `pyenv shell`
328+
repo_utils.getenv(rctx, "PYENV_VERSION")
329+
result = repo_utils.which_unchecked(rctx, interpreter_path)
330+
resolved_path = result.binary
331+
describe_failure = result.describe_failure
275332
else:
276-
describe_failure = None
333+
rctx.watch(interpreter_path)
334+
resolved_path = rctx.path(interpreter_path)
335+
if not resolved_path.exists:
336+
describe_failure = lambda: "Path not found: {}".format(repr(interpreter_path))
337+
else:
338+
describe_failure = None
277339

278340
return struct(
279341
resolved_path = resolved_path,

0 commit comments

Comments
 (0)