Skip to content

Commit 098cb29

Browse files
ouillieaignas
andauthored
feat(pypi): support isolated pip.parse (#3669)
Adds a fallback at the end of `build_config`: when `defaults["platforms"]` is empty, it detects the host OS and CPU and injects a single platform entry. This allows users to use the `--experimental_isolated_extension_usages` flag. Fixes #3668 Related #2094 --------- Co-authored-by: Ignas Anikevicius <240938+aignas@users.noreply.github.com>
1 parent 2e8aa91 commit 098cb29

12 files changed

Lines changed: 299 additions & 190 deletions

File tree

.bazelrc.deleted_packages

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ common --deleted_packages=tests/integration/custom_commands
3535
common --deleted_packages=tests/integration/local_toolchains
3636
common --deleted_packages=tests/integration/pip_parse
3737
common --deleted_packages=tests/integration/pip_parse/empty
38+
common --deleted_packages=tests/integration/pip_parse_isolated
3839
common --deleted_packages=tests/integration/py_cc_toolchain_registered
3940
common --deleted_packages=tests/integration/toolchain_target_settings
4041
common --deleted_packages=tests/modules/another_module

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ END_UNRELEASED_TEMPLATE
6969
targets ([#3729](https://github.com/bazel-contrib/rules_python/issues/3729)).
7070
* (entry_point) From now on `mypy` type checking will be skipped on the generated
7171
files ([#3126](https://github.com/bazel-contrib/rules_python/issues/3126)).
72+
* (pypi) Support `--experimental_isolated_extension_usages`
73+
([#3668](https://github.com/bazel-contrib/rules_python/issues/3668)).
7274

7375
{#v0-0-0-added}
7476
### Added

MODULE.bazel

Lines changed: 0 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -64,141 +64,6 @@ register_toolchains("@pythons_hub//:all")
6464
# Install twine for our own runfiles wheel publishing and allow bzlmod users to use it.
6565

6666
pip = use_extension("//python/extensions:pip.bzl", "pip")
67-
68-
# NOTE @aignas 2025-07-06: we define these platforms to keep backwards compatibility. Whilst we
69-
# stabilize the API this list may be updated with a mention in the CHANGELOG.
70-
[
71-
pip.default(
72-
arch_name = cpu,
73-
config_settings = [
74-
"@platforms//cpu:{}".format(cpu),
75-
"@platforms//os:linux",
76-
"//python/config_settings:_is_py_freethreaded_{}".format(
77-
"yes" if freethreaded else "no",
78-
),
79-
],
80-
env = {"platform_version": "0"},
81-
marker = "python_version >= '3.13'" if freethreaded else "",
82-
os_name = "linux",
83-
platform = "linux_{}{}".format(cpu, freethreaded),
84-
whl_abi_tags = ["cp{major}{minor}t"] if freethreaded else [
85-
"abi3",
86-
"cp{major}{minor}",
87-
],
88-
whl_platform_tags = [
89-
"linux_{}".format(cpu),
90-
"manylinux_*_{}".format(cpu),
91-
],
92-
)
93-
for cpu in [
94-
"x86_64",
95-
"aarch64",
96-
]
97-
for freethreaded in [
98-
"",
99-
"_freethreaded",
100-
]
101-
]
102-
103-
[
104-
pip.default(
105-
arch_name = cpu,
106-
config_settings = [
107-
"@platforms//cpu:{}".format(cpu),
108-
"@platforms//os:osx",
109-
"//python/config_settings:_is_py_freethreaded_{}".format(
110-
"yes" if freethreaded else "no",
111-
),
112-
],
113-
# We choose the oldest non-EOL version at the time when we release `rules_python`.
114-
# See https://endoflife.date/macos
115-
env = {"platform_version": "14.0"},
116-
marker = "python_version >= '3.13'" if freethreaded else "",
117-
os_name = "osx",
118-
platform = "osx_{}{}".format(cpu, freethreaded),
119-
whl_abi_tags = ["cp{major}{minor}t"] if freethreaded else [
120-
"abi3",
121-
"cp{major}{minor}",
122-
],
123-
whl_platform_tags = [
124-
"macosx_*_{}".format(suffix)
125-
for suffix in platform_tag_cpus
126-
],
127-
)
128-
for cpu, platform_tag_cpus in {
129-
"aarch64": [
130-
"universal2",
131-
"arm64",
132-
],
133-
"x86_64": [
134-
"universal2",
135-
"x86_64",
136-
],
137-
}.items()
138-
for freethreaded in [
139-
"",
140-
"_freethreaded",
141-
]
142-
]
143-
144-
[
145-
pip.default(
146-
arch_name = cpu,
147-
config_settings = [
148-
"@platforms//cpu:{}".format(cpu),
149-
"@platforms//os:windows",
150-
"//python/config_settings:_is_py_freethreaded_{}".format(
151-
"yes" if freethreaded else "no",
152-
),
153-
],
154-
env = {"platform_version": "0"},
155-
marker = "python_version >= '3.13'" if freethreaded else "",
156-
os_name = "windows",
157-
platform = "windows_{}{}".format(cpu, freethreaded),
158-
whl_abi_tags = ["cp{major}{minor}t"] if freethreaded else [
159-
"abi3",
160-
"cp{major}{minor}",
161-
],
162-
whl_platform_tags = whl_platform_tags,
163-
)
164-
for cpu, whl_platform_tags in {
165-
"x86_64": ["win_amd64"],
166-
}.items()
167-
for freethreaded in [
168-
"",
169-
"_freethreaded",
170-
]
171-
]
172-
173-
[
174-
pip.default(
175-
arch_name = cpu,
176-
config_settings = [
177-
"@platforms//cpu:{}".format(cpu),
178-
"@platforms//os:windows",
179-
"//python/config_settings:_is_py_freethreaded_{}".format(
180-
"yes" if freethreaded else "no",
181-
),
182-
],
183-
env = {"platform_version": "0"},
184-
marker = "python_version >= '3.13'" if freethreaded else "python_version >= '3.11'",
185-
os_name = "windows",
186-
platform = "windows_{}{}".format(cpu, freethreaded),
187-
whl_abi_tags = ["cp{major}{minor}t"] if freethreaded else [
188-
"abi3",
189-
"cp{major}{minor}",
190-
],
191-
whl_platform_tags = whl_platform_tags,
192-
)
193-
for cpu, whl_platform_tags in {
194-
"aarch64": ["win_arm64"],
195-
}.items()
196-
for freethreaded in [
197-
"",
198-
"_freethreaded",
199-
]
200-
]
201-
20267
pip.parse(
20368
hub_name = "rules_python_publish_deps",
20469
python_version = "3.11",

python/private/pypi/extension.bzl

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,128 @@ def _whl_mods_impl(whl_mods_dict):
5555
whl_mods = whl_mods,
5656
)
5757

58+
def default_platforms():
59+
"""Return the built-in default platform definitions.
60+
61+
These provide the platform metadata needed for pip wheel resolution
62+
(whl_abi_tags, whl_platform_tags, config_settings, etc.) across all
63+
common OS/arch combinations. They are always used as the starting point
64+
for build_config; root modules can override individual platforms via
65+
pip.default tags.
66+
67+
Returns:
68+
A dict of platform name to platform config dicts.
69+
"""
70+
# NOTE @aignas 2025-07-06: we define these platforms to keep backwards compatibility. Whilst we
71+
# stabilize the API this list may be updated with a mention in the CHANGELOG.
72+
73+
platforms = {}
74+
75+
# Linux platforms
76+
for cpu in ["x86_64", "aarch64"]:
77+
for freethreaded in ["", "_freethreaded"]:
78+
platform_name = "linux_{}{}".format(cpu, freethreaded)
79+
platforms[platform_name] = {
80+
"arch_name": cpu,
81+
"config_settings": [
82+
"@platforms//cpu:{}".format(cpu),
83+
"@platforms//os:linux",
84+
"//python/config_settings:_is_py_freethreaded_{}".format(
85+
"yes" if freethreaded else "no",
86+
),
87+
],
88+
"env": {"platform_version": "0"},
89+
"marker": "python_version >= '3.13'" if freethreaded else "",
90+
"name": platform_name,
91+
"os_name": "linux",
92+
"whl_abi_tags": ["cp{major}{minor}t"] if freethreaded else [
93+
"abi3",
94+
"cp{major}{minor}",
95+
],
96+
"whl_platform_tags": [
97+
"linux_{}".format(cpu),
98+
"manylinux_*_{}".format(cpu),
99+
],
100+
}
101+
102+
# macOS platforms
103+
for cpu, platform_tag_cpus in {
104+
"aarch64": ["universal2", "arm64"],
105+
"x86_64": ["universal2", "x86_64"],
106+
}.items():
107+
for freethreaded in ["", "_freethreaded"]:
108+
platform_name = "osx_{}{}".format(cpu, freethreaded)
109+
platforms[platform_name] = {
110+
"arch_name": cpu,
111+
"config_settings": [
112+
"@platforms//cpu:{}".format(cpu),
113+
"@platforms//os:osx",
114+
"//python/config_settings:_is_py_freethreaded_{}".format(
115+
"yes" if freethreaded else "no",
116+
),
117+
],
118+
"env": {"platform_version": "14.0"},
119+
"marker": "python_version >= '3.13'" if freethreaded else "",
120+
"name": platform_name,
121+
"os_name": "osx",
122+
"whl_abi_tags": ["cp{major}{minor}t"] if freethreaded else [
123+
"abi3",
124+
"cp{major}{minor}",
125+
],
126+
"whl_platform_tags": [
127+
"macosx_*_{}".format(suffix)
128+
for suffix in platform_tag_cpus
129+
],
130+
}
131+
132+
# Windows x86_64 platforms
133+
for freethreaded in ["", "_freethreaded"]:
134+
platform_name = "windows_x86_64{}".format(freethreaded)
135+
platforms[platform_name] = {
136+
"arch_name": "x86_64",
137+
"config_settings": [
138+
"@platforms//cpu:x86_64",
139+
"@platforms//os:windows",
140+
"//python/config_settings:_is_py_freethreaded_{}".format(
141+
"yes" if freethreaded else "no",
142+
),
143+
],
144+
"env": {"platform_version": "0"},
145+
"marker": "python_version >= '3.13'" if freethreaded else "",
146+
"name": platform_name,
147+
"os_name": "windows",
148+
"whl_abi_tags": ["cp{major}{minor}t"] if freethreaded else [
149+
"abi3",
150+
"cp{major}{minor}",
151+
],
152+
"whl_platform_tags": ["win_amd64"],
153+
}
154+
155+
# Windows aarch64 platforms
156+
for freethreaded in ["", "_freethreaded"]:
157+
platform_name = "windows_aarch64{}".format(freethreaded)
158+
platforms[platform_name] = {
159+
"arch_name": "aarch64",
160+
"config_settings": [
161+
"@platforms//cpu:aarch64",
162+
"@platforms//os:windows",
163+
"//python/config_settings:_is_py_freethreaded_{}".format(
164+
"yes" if freethreaded else "no",
165+
),
166+
],
167+
"env": {"platform_version": "0"},
168+
"marker": "python_version >= '3.13'" if freethreaded else "python_version >= '3.11'",
169+
"name": platform_name,
170+
"os_name": "windows",
171+
"whl_abi_tags": ["cp{major}{minor}t"] if freethreaded else [
172+
"abi3",
173+
"cp{major}{minor}",
174+
],
175+
"whl_platform_tags": ["win_arm64"],
176+
}
177+
178+
return platforms
179+
58180
def _configure(config, *, override = False, **kwargs):
59181
"""Set the value in the config if the value is provided"""
60182
env = kwargs.get("env")
@@ -82,7 +204,7 @@ def build_config(
82204
A struct with the configuration.
83205
"""
84206
defaults = {
85-
"platforms": {},
207+
"platforms": default_platforms(),
86208
}
87209
for mod in module_ctx.modules:
88210
if not (mod.is_root or mod.name == "rules_python"):

tests/integration/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ rules_python_integration_test(
6767
name = "pip_parse_test",
6868
)
6969

70+
rules_python_integration_test(
71+
name = "pip_parse_isolated_test",
72+
)
73+
7074
rules_python_integration_test(
7175
name = "pip_parse_workspace_test",
7276
bzlmod = False,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Bazel configuration flags
2+
3+
build --enable_runfiles
4+
5+
common --experimental_isolated_extension_usages
6+
7+
# https://docs.bazel.build/versions/main/best-practices.html#using-the-bazelrc-file
8+
try-import %workspace%/user.bazelrc
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
load("@rules_python//python:py_test.bzl", "py_test")
2+
3+
py_test(
4+
name = "test_isolated",
5+
srcs = ["test_isolated.py"],
6+
deps = ["@pypi//six"],
7+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module(name = "pip_parse_isolated")
2+
3+
bazel_dep(name = "rules_python")
4+
local_path_override(
5+
module_name = "rules_python",
6+
path = "../../..",
7+
)
8+
9+
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
10+
python.toolchain(python_version = "3.13")
11+
12+
# This test module verifies that dependencies can be used with `isolate = True`.
13+
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", isolate = True)
14+
pip.parse(
15+
hub_name = "pypi",
16+
python_version = "3.13",
17+
requirements_lock = "//:requirements_lock.txt",
18+
)
19+
use_repo(pip, "pypi")

tests/integration/pip_parse_isolated/WORKSPACE

Whitespace-only changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
six==1.17.0 \
2+
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274

0 commit comments

Comments
 (0)