Skip to content

Commit a816962

Browse files
Synssaignas
andauthored
feat: Package pyi files in wheel (#2609)
1.1.0 introduced separate attributes for the type definitions (`.pyi` files) and type checking. This patch adds those files to the wheel to ensure that they are distributed and available to users. #2538 introduced `pyi_srcs`. --------- Co-authored-by: Ignas Anikevicius <[email protected]>
1 parent 1226caa commit a816962

11 files changed

+83
-11
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ Unreleased changes template.
5353
{#v0-0-0-changed}
5454
### Changed
5555
* (deps) platforms 0.0.4 -> 0.0.11
56+
* (py_wheel) Package `py_library.pyi_srcs` (`.pyi` files) in the wheel.
57+
* (py_package) Package `py_library.pyi_srcs` (`.pyi` files) in `py_package`.
5658

5759
{#v0-0-0-fixed}
5860
### Fixed

examples/wheel/BUILD.bazel

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ py_library(
3333
deps = [
3434
"//examples/wheel/lib:simple_module",
3535
"//examples/wheel/lib:module_with_data",
36+
"//examples/wheel/lib:module_with_type_annotations",
3637
# Example dependency which is not packaged in the wheel
3738
# due to "packages" filter on py_package rule.
3839
"//tests/load_from_macro:foo",
@@ -67,6 +68,7 @@ py_wheel(
6768
version = "0.0.1",
6869
deps = [
6970
"//examples/wheel/lib:module_with_data",
71+
"//examples/wheel/lib:module_with_type_annotations",
7072
"//examples/wheel/lib:simple_module",
7173
],
7274
)
@@ -90,6 +92,7 @@ py_wheel(
9092
version = "$(VERSION)",
9193
deps = [
9294
"//examples/wheel/lib:module_with_data",
95+
"//examples/wheel/lib:module_with_type_annotations",
9396
"//examples/wheel/lib:simple_module",
9497
],
9598
)
@@ -109,6 +112,7 @@ py_wheel(
109112
version = "0.1.{BUILD_TIMESTAMP}",
110113
deps = [
111114
"//examples/wheel/lib:module_with_data",
115+
"//examples/wheel/lib:module_with_type_annotations",
112116
"//examples/wheel/lib:simple_module",
113117
],
114118
)

examples/wheel/lib/BUILD.bazel

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ py_library(
2323
srcs = ["simple_module.py"],
2424
)
2525

26+
py_library(
27+
name = "module_with_type_annotations",
28+
srcs = ["module_with_type_annotations.py"],
29+
pyi_srcs = ["module_with_type_annotations.pyi"],
30+
)
31+
2632
py_library(
2733
name = "module_with_data",
2834
srcs = ["module_with_data.py"],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2025 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+
def function():
16+
return "qux"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2025 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+
def function() -> str: ...

examples/wheel/main.py

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import examples.wheel.lib.module_with_data as module_with_data
16+
import examples.wheel.lib.module_with_type_annotations as module_with_type_annotations
1617
import examples.wheel.lib.simple_module as simple_module
1718

1819

@@ -23,6 +24,7 @@ def function():
2324
def main():
2425
print(function())
2526
print(module_with_data.function())
27+
print(module_with_type_annotations.function())
2628
print(simple_module.function())
2729

2830

examples/wheel/test_publish.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def test_upload_and_query_simple_api(self):
104104
</head>
105105
<body>
106106
<h1>Links for example-minimal-library</h1>
107-
<a href="/packages/example_minimal_library-0.0.1-py3-none-any.whl#sha256=79a4e9c1838c0631d5d8fa49a26efd6e9a364f6b38d9597c0f6df112271a0e28">example_minimal_library-0.0.1-py3-none-any.whl</a><br>
107+
<a href="/packages/example_minimal_library-0.0.1-py3-none-any.whl#sha256=0cbf4ec574676015af595f570caf4ae2812f994f6338e247b002b4e496b6fbd5">example_minimal_library-0.0.1-py3-none-any.whl</a><br>
108108
</body>
109109
</html>"""
110110
self.assertEqual(

examples/wheel/wheel_test.py

+25-9
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,16 @@ def test_py_library_wheel(self):
7676
zf.namelist(),
7777
[
7878
"examples/wheel/lib/module_with_data.py",
79+
"examples/wheel/lib/module_with_type_annotations.py",
80+
"examples/wheel/lib/module_with_type_annotations.pyi",
7981
"examples/wheel/lib/simple_module.py",
8082
"example_minimal_library-0.0.1.dist-info/WHEEL",
8183
"example_minimal_library-0.0.1.dist-info/METADATA",
8284
"example_minimal_library-0.0.1.dist-info/RECORD",
8385
],
8486
)
8587
self.assertFileSha256Equal(
86-
filename, "79a4e9c1838c0631d5d8fa49a26efd6e9a364f6b38d9597c0f6df112271a0e28"
88+
filename, "0cbf4ec574676015af595f570caf4ae2812f994f6338e247b002b4e496b6fbd5"
8789
)
8890

8991
def test_py_package_wheel(self):
@@ -98,6 +100,8 @@ def test_py_package_wheel(self):
98100
"examples/wheel/lib/data,with,commas.txt",
99101
"examples/wheel/lib/data.txt",
100102
"examples/wheel/lib/module_with_data.py",
103+
"examples/wheel/lib/module_with_type_annotations.py",
104+
"examples/wheel/lib/module_with_type_annotations.pyi",
101105
"examples/wheel/lib/simple_module.py",
102106
"examples/wheel/main.py",
103107
"example_minimal_package-0.0.1.dist-info/WHEEL",
@@ -106,7 +110,7 @@ def test_py_package_wheel(self):
106110
],
107111
)
108112
self.assertFileSha256Equal(
109-
filename, "82370bf61310e2d3c7b1218368457dc7e161bf5dc1a280d7d45102b5e56acf43"
113+
filename, "22aff90dd3c8c30c3ce2b729bb793cab0bd2668a6810de232677a0354ce79cae"
110114
)
111115

112116
def test_customized_wheel(self):
@@ -121,6 +125,8 @@ def test_customized_wheel(self):
121125
"examples/wheel/lib/data,with,commas.txt",
122126
"examples/wheel/lib/data.txt",
123127
"examples/wheel/lib/module_with_data.py",
128+
"examples/wheel/lib/module_with_type_annotations.py",
129+
"examples/wheel/lib/module_with_type_annotations.pyi",
124130
"examples/wheel/lib/simple_module.py",
125131
"examples/wheel/main.py",
126132
"example_customized-0.0.1.dist-info/WHEEL",
@@ -145,8 +151,10 @@ def test_customized_wheel(self):
145151
"examples/wheel/lib/data,with,commas.txt",sha256=9vJKEdfLu8bZRArKLroPZJh1XKkK3qFMXiM79MBL2Sg,12
146152
examples/wheel/lib/data.txt,sha256=9vJKEdfLu8bZRArKLroPZJh1XKkK3qFMXiM79MBL2Sg,12
147153
examples/wheel/lib/module_with_data.py,sha256=8s0Khhcqz3yVsBKv2IB5u4l4TMKh7-c_V6p65WVHPms,637
154+
examples/wheel/lib/module_with_type_annotations.py,sha256=MM2cFQsCBaUnzGiEGT5r07jhKSaCVRh5Paw_YLyrS-w,636
155+
examples/wheel/lib/module_with_type_annotations.pyi,sha256=fja3ql_WRJ1qO8jyZjWWrTTMcg1J7EpOQivOHY_8vI4,630
148156
examples/wheel/lib/simple_module.py,sha256=z2hwciab_XPNIBNH8B1Q5fYgnJvQTeYf0ZQJpY8yLLY,637
149-
examples/wheel/main.py,sha256=sgg5iWN_9inYBjm6_Zw27hYdmo-l24fA-2rfphT-IlY,909
157+
examples/wheel/main.py,sha256=mFiRfzQEDwCHr-WVNQhOH26M42bw1UMF6IoqvtuDTrw,1047
150158
example_customized-0.0.1.dist-info/WHEEL,sha256=sobxWSyDDkdg_rinUth-jxhXHqoNqlmNMJY3aTZn2Us,91
151159
example_customized-0.0.1.dist-info/METADATA,sha256=QYQcDJFQSIqan8eiXqL67bqsUfgEAwf2hoK_Lgi1S-0,559
152160
example_customized-0.0.1.dist-info/entry_points.txt,sha256=pqzpbQ8MMorrJ3Jp0ntmpZcuvfByyqzMXXi2UujuXD0,137
@@ -197,7 +205,7 @@ def test_customized_wheel(self):
197205
second = second.main:s""",
198206
)
199207
self.assertFileSha256Equal(
200-
filename, "706e8dd45884d8cb26e92869f7d29ab7ed9f683b4e2d08f06c03dbdaa12191b8"
208+
filename, "657a938a6fdd6f38bf73d1d91016ffff85d68cf29ca390692a3e9d923dd0e39e"
201209
)
202210

203211
def test_filename_escaping(self):
@@ -211,6 +219,8 @@ def test_filename_escaping(self):
211219
"examples/wheel/lib/data,with,commas.txt",
212220
"examples/wheel/lib/data.txt",
213221
"examples/wheel/lib/module_with_data.py",
222+
"examples/wheel/lib/module_with_type_annotations.py",
223+
"examples/wheel/lib/module_with_type_annotations.pyi",
214224
"examples/wheel/lib/simple_module.py",
215225
"examples/wheel/main.py",
216226
# PEP calls for replacing only in the archive filename.
@@ -248,6 +258,8 @@ def test_custom_package_root_wheel(self):
248258
"wheel/lib/data,with,commas.txt",
249259
"wheel/lib/data.txt",
250260
"wheel/lib/module_with_data.py",
261+
"wheel/lib/module_with_type_annotations.py",
262+
"wheel/lib/module_with_type_annotations.pyi",
251263
"wheel/lib/simple_module.py",
252264
"wheel/main.py",
253265
"examples_custom_package_root-0.0.1.dist-info/WHEEL",
@@ -265,7 +277,7 @@ def test_custom_package_root_wheel(self):
265277
for line in record_contents.splitlines():
266278
self.assertFalse(line.startswith("/"))
267279
self.assertFileSha256Equal(
268-
filename, "568922541703f6edf4b090a8413991f9fa625df2844e644dd30bdbe9deb660be"
280+
filename, "d415edbf8f326161674c1fa260e364dd44f2a0311e2f596284320ea52d2a8bdb"
269281
)
270282

271283
def test_custom_package_root_multi_prefix_wheel(self):
@@ -281,6 +293,8 @@ def test_custom_package_root_multi_prefix_wheel(self):
281293
"data,with,commas.txt",
282294
"data.txt",
283295
"module_with_data.py",
296+
"module_with_type_annotations.py",
297+
"module_with_type_annotations.pyi",
284298
"simple_module.py",
285299
"main.py",
286300
"example_custom_package_root_multi_prefix-0.0.1.dist-info/WHEEL",
@@ -297,7 +311,7 @@ def test_custom_package_root_multi_prefix_wheel(self):
297311
for line in record_contents.splitlines():
298312
self.assertFalse(line.startswith("/"))
299313
self.assertFileSha256Equal(
300-
filename, "a8b91ce9d6f570e97b40a357a292a6f595d3470f07c479cb08550257cc9c8306"
314+
filename, "6b76a1178c90996feaf3f9417f350c4a67f90f4247647fd4fd552858dc372d4b"
301315
)
302316

303317
def test_custom_package_root_multi_prefix_reverse_order_wheel(self):
@@ -313,6 +327,8 @@ def test_custom_package_root_multi_prefix_reverse_order_wheel(self):
313327
"lib/data,with,commas.txt",
314328
"lib/data.txt",
315329
"lib/module_with_data.py",
330+
"lib/module_with_type_annotations.py",
331+
"lib/module_with_type_annotations.pyi",
316332
"lib/simple_module.py",
317333
"main.py",
318334
"example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/WHEEL",
@@ -329,7 +345,7 @@ def test_custom_package_root_multi_prefix_reverse_order_wheel(self):
329345
for line in record_contents.splitlines():
330346
self.assertFalse(line.startswith("/"))
331347
self.assertFileSha256Equal(
332-
filename, "8f44e940731757c186079a42cfe7ea3d43cd96b526e3fb2ca2a3ea3048a9d489"
348+
filename, "f976f0bb1c7d753e8c41629d6b79fb09908c6ecd2fec006816879fc86b664f3f"
333349
)
334350

335351
def test_python_requires_wheel(self):
@@ -354,7 +370,7 @@ def test_python_requires_wheel(self):
354370
""",
355371
)
356372
self.assertFileSha256Equal(
357-
filename, "ba32493f5e43e481346384aaab9e8fa09c23884276ad057c5f432096a0350101"
373+
filename, "f3b74ce429c3324b87f8d1cc7dc33be1493f54bb88d546a7d53be7587b82c1a7"
358374
)
359375

360376
def test_python_abi3_binary_wheel(self):
@@ -419,7 +435,7 @@ def test_rule_creates_directory_and_is_included_in_wheel(self):
419435
],
420436
)
421437
self.assertFileSha256Equal(
422-
filename, "ac9216bd54dcae1a6270c35fccf8a73b0be87c1b026c28e963b7c76b2f9b722b"
438+
filename, "d8e874b807e5574bd11a9312c58ce7fe7055afb80412d0d0e7ed21fc9223cd53"
423439
)
424440

425441
def test_rule_expands_workspace_status_keys_in_wheel_metadata(self):

python/private/py_package.bzl

+3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ def _py_package_impl(ctx):
4646
if hasattr(py_info, "transitive_pyc_files"):
4747
inputs.add(py_info.transitive_pyc_files)
4848

49+
if hasattr(py_info, "transitive_pyi_files"):
50+
inputs.add(py_info.transitive_pyi_files)
51+
4952
inputs = inputs.build()
5053

5154
# TODO: '/' is wrong on windows, but the path separator is not available in starlark.

python/private/py_wheel.bzl

+7-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"Implementation of py_wheel rule"
1616

17+
load(":py_info.bzl", "PyInfo")
1718
load(":py_package.bzl", "py_package_lib")
1819
load(":py_wheel_normalize_pep440.bzl", "normalize_pep440")
1920
load(":stamp.bzl", "is_stamping_enabled")
@@ -319,8 +320,13 @@ def _py_wheel_impl(ctx):
319320

320321
name_file = ctx.actions.declare_file(ctx.label.name + ".name")
321322

323+
direct_pyi_files = []
324+
for dep in ctx.attr.deps:
325+
if PyInfo in dep:
326+
direct_pyi_files.extend(dep[PyInfo].direct_pyi_files.to_list())
327+
322328
inputs_to_package = depset(
323-
direct = ctx.files.deps,
329+
direct = ctx.files.deps + direct_pyi_files,
324330
)
325331

326332
# Inputs to this rule which are not to be packaged.

tests/whl_filegroup/extract_wheel_files_test.py

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ def test_get_wheel_record(self) -> None:
1414
"examples/wheel/lib/data,with,commas.txt",
1515
"examples/wheel/lib/data.txt",
1616
"examples/wheel/lib/module_with_data.py",
17+
"examples/wheel/lib/module_with_type_annotations.py",
18+
"examples/wheel/lib/module_with_type_annotations.pyi",
1719
"examples/wheel/lib/simple_module.py",
1820
"examples/wheel/main.py",
1921
"example_minimal_package-0.0.1.dist-info/WHEEL",

0 commit comments

Comments
 (0)