Skip to content

Commit 18a64db

Browse files
committed
feat: add pyi_srcs, pyi_deps attributes
1 parent d4fcb41 commit 18a64db

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

python/private/attributes.bzl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,35 @@ in the resulting output or not. Valid values are:
395395
# Force enabling auto exec groups, see
396396
# https://bazel.build/extending/auto-exec-groups#how-enable-particular-rule
397397
"_use_auto_exec_groups": attr.bool(default = True),
398+
"pyi_srcs": attr.label_list(
399+
doc = """
400+
Type definition files for the library.
401+
402+
These are typically `.pyi` files, but other file types for type-checker specific
403+
formats are allowed. These files are build-time only dependencies and not included
404+
as part of a runnable program (packaging rules may include them, however).
405+
406+
:::{versionadded} VERSION_NEXT_FEATURE
407+
:::
408+
""",
409+
allow_files = True,
410+
),
411+
"pyi_deps": attr.label_list(
412+
doc = """
413+
Dependencies providing type definitions the library needs.
414+
415+
These are dependencies that satisfy imports guarded by `typing.TYPE_CHECKING`.
416+
These are build-time only dependencies and not included as part of a runnable
417+
program (packaging rules may include them, however).
418+
419+
:::{versionadded} VERSION_NEXT_FEATURE
420+
:::
421+
""",
422+
providers = [
423+
[PyInfo],
424+
[CcInfo],
425+
] + _MaybeBuiltinPyInfo,
426+
),
398427
},
399428
allow_none = True,
400429
)

python/private/common.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,9 @@ def create_py_info(
442442
py_info.direct_original_sources.add(original_sources)
443443
py_info.transitive_original_sources.add(original_sources)
444444
py_info.direct_pyc_files.add(required_pyc_files)
445+
py_info.direct_pyi_files.add(ctx.files.pyi_srcs)
445446
py_info.transitive_pyc_files.add(required_pyc_files)
447+
py_info.transitive_pyi_files.add(ctx.files.pyi_srcs)
446448
py_info.transitive_implicit_pyc_files.add(implicit_pyc_files)
447449
py_info.transitive_implicit_pyc_source_files.add(implicit_pyc_source_files)
448450
py_info.imports.add(imports)
@@ -461,6 +463,10 @@ def create_py_info(
461463
if f.extension == "py":
462464
py_info.transitive_sources.add(f)
463465
py_info.merge_uses_shared_libraries(cc_helper.is_valid_shared_library_artifact(f))
466+
for target in ctx.attr.pyi_deps:
467+
# PyInfo may not be present e.g. cc_library rules.
468+
if PyInfo in target or (BuiltinPyInfo != None and BuiltinPyInfo in target):
469+
py_info.merge(_get_py_info(target))
464470

465471
deps_transitive_sources = py_info.transitive_sources.build()
466472
py_info.transitive_sources.add(required_py_files)

tests/base_rules/base_tests.bzl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
1717
load("@rules_testing//lib:truth.bzl", "matching")
1818
load("@rules_testing//lib:util.bzl", "PREVENT_IMPLICIT_BUILDING_TAGS", rt_util = "util")
1919
load("//python:py_info.bzl", "PyInfo")
20+
load("//python:py_library.bzl", "py_library")
2021
load("//python/private:reexports.bzl", "BuiltinPyInfo") # buildifier: disable=bzl-visibility
2122
load("//tests/base_rules:util.bzl", pt_util = "util")
2223
load("//tests/support:py_info_subject.bzl", "py_info_subject")
@@ -58,6 +59,49 @@ _not_produces_py_info = rule(
5859
implementation = _not_produces_py_info_impl,
5960
)
6061

62+
def _test_py_info_populated(name, config):
63+
rt_util.helper_target(
64+
config.base_test_rule,
65+
name = name + "_subject",
66+
pyi_srcs = ["subject.pyi"],
67+
pyi_deps = [name + "_lib2"],
68+
)
69+
rt_util.helper_target(
70+
py_library,
71+
name = name + "_lib2",
72+
srcs = ["lib2.py"],
73+
pyi_srcs = ["lib2.pyi"],
74+
)
75+
76+
analysis_test(
77+
name = name,
78+
target = name + "_subject",
79+
impl = _test_py_info_populated_impl,
80+
)
81+
82+
def _test_py_info_populated_impl(env, target):
83+
info = env.expect.that_target(target).provider(
84+
PyInfo,
85+
factory = py_info_subject,
86+
)
87+
info.direct_original_sources().contains_exactly([
88+
"{package}/test_py_info_populated_subject.py",
89+
])
90+
info.transitive_original_sources().contains_exactly([
91+
"{package}/test_py_info_populated_subject.py",
92+
"{package}/lib2.py",
93+
])
94+
95+
info.direct_pyi_files().contains_exactly([
96+
"{package}/subject.pyi",
97+
])
98+
info.transitive_pyi_files().contains_exactly([
99+
"{package}/lib2.pyi",
100+
"{package}/subject.pyi",
101+
])
102+
103+
_tests.append(_test_py_info_populated)
104+
61105
def _py_info_propagation_setup(name, config, produce_py_info_rule, test_impl):
62106
rt_util.helper_target(
63107
config.base_test_rule,

0 commit comments

Comments
 (0)