refactor: move PyInfo into separate file (#2249)
Both PyInfo and providers.bzl are fairly large, and some upcoming PRs
will be adding
more PyInfo-specific code. To keep them manageable, move PyInfo into its
own file.
diff --git a/python/BUILD.bazel b/python/BUILD.bazel
index b7a2172..53fb812 100644
--- a/python/BUILD.bazel
+++ b/python/BUILD.bazel
@@ -167,8 +167,8 @@
name = "py_info_bzl",
srcs = ["py_info.bzl"],
deps = [
+ "//python/private:py_info_bzl",
"//python/private:reexports_bzl",
- "//python/private/common:providers_bzl",
"@rules_python_internal//:rules_python_config_bzl",
],
)
diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel
index bfe3764..8479f67 100644
--- a/python/private/BUILD.bazel
+++ b/python/private/BUILD.bazel
@@ -267,6 +267,15 @@
)
bzl_library(
+ name = "py_info_bzl",
+ srcs = ["py_info.bzl"],
+ deps = [
+ ":reexports_bzl",
+ ":util_bzl",
+ ],
+)
+
+bzl_library(
name = "py_interpreter_program_bzl",
srcs = ["py_interpreter_program.bzl"],
deps = ["@bazel_skylib//rules:common_settings"],
diff --git a/python/private/common/BUILD.bazel b/python/private/common/BUILD.bazel
index 805c002..6fef8e8 100644
--- a/python/private/common/BUILD.bazel
+++ b/python/private/common/BUILD.bazel
@@ -29,11 +29,11 @@
srcs = ["attributes.bzl"],
deps = [
":common_bzl",
- ":providers_bzl",
":py_internal_bzl",
":semantics_bzl",
"//python/private:enum_bzl",
"//python/private:flags_bzl",
+ "//python/private:py_info_bzl",
"//python/private:reexports_bzl",
"//python/private:rules_cc_srcs_bzl",
"@bazel_skylib//rules:common_settings",
@@ -68,6 +68,7 @@
":providers_bzl",
":py_internal_bzl",
":semantics_bzl",
+ "//python/private:py_info_bzl",
"//python/private:reexports_bzl",
"//python/private:rules_cc_srcs_bzl",
],
@@ -133,6 +134,7 @@
":py_internal_bzl",
"//python/private:flags_bzl",
"//python/private:py_executable_info_bzl",
+ "//python/private:py_info_bzl",
"//python/private:rules_cc_srcs_bzl",
"//python/private:toolchain_types_bzl",
"@bazel_skylib//lib:dicts",
diff --git a/python/private/common/attributes.bzl b/python/private/common/attributes.bzl
index 90a5332..5e81f46 100644
--- a/python/private/common/attributes.bzl
+++ b/python/private/common/attributes.bzl
@@ -17,9 +17,9 @@
load("@rules_cc//cc:defs.bzl", "CcInfo")
load("//python/private:enum.bzl", "enum")
load("//python/private:flags.bzl", "PrecompileFlag", "PrecompileSourceRetentionFlag")
+load("//python/private:py_info.bzl", "PyInfo")
load("//python/private:reexports.bzl", "BuiltinPyInfo")
load(":common.bzl", "union_attrs")
-load(":providers.bzl", "PyInfo")
load(":py_internal.bzl", "py_internal")
load(
":semantics.bzl",
diff --git a/python/private/common/common.bzl b/python/private/common/common.bzl
index 5559ccd..bbda712 100644
--- a/python/private/common/common.bzl
+++ b/python/private/common/common.bzl
@@ -13,9 +13,9 @@
# limitations under the License.
"""Various things common to Bazel and Google rule implementations."""
+load("//python/private:py_info.bzl", "PyInfo")
load("//python/private:reexports.bzl", "BuiltinPyInfo")
load(":cc_helper.bzl", "cc_helper")
-load(":providers.bzl", "PyInfo")
load(":py_internal.bzl", "py_internal")
load(
":semantics.bzl",
diff --git a/python/private/common/providers.bzl b/python/private/common/providers.bzl
index eb8b910..b704ce0 100644
--- a/python/private/common/providers.bzl
+++ b/python/private/common/providers.bzl
@@ -14,7 +14,7 @@
"""Providers for Python rules."""
load("@rules_cc//cc:defs.bzl", "CcInfo")
-load("//python/private:util.bzl", "IS_BAZEL_6_OR_HIGHER")
+load("//python/private:util.bzl", "define_bazel_6_provider")
DEFAULT_STUB_SHEBANG = "#!/usr/bin/env python3"
@@ -22,18 +22,6 @@
_PYTHON_VERSION_VALUES = ["PY2", "PY3"]
-# Helper to make the provider definitions not crash under Bazel 5.4:
-# Bazel 5.4 doesn't support the `init` arg of `provider()`, so we have to
-# not pass that when using Bazel 5.4. But, not passing the `init` arg
-# changes the return value from a two-tuple to a single value, which then
-# breaks Bazel 6+ code.
-# This isn't actually used under Bazel 5.4, so just stub out the values
-# to get past the loading phase.
-def _define_provider(doc, fields, **kwargs):
- if not IS_BAZEL_6_OR_HIGHER:
- return provider("Stub, not used", fields = []), None
- return provider(doc = doc, fields = fields, **kwargs)
-
def _optional_int(value):
return int(value) if value != None else None
@@ -133,9 +121,7 @@
"zip_main_template": zip_main_template,
}
-# TODO(#15897): Rename this to PyRuntimeInfo when we're ready to replace the Java
-# implemented provider with the Starlark one.
-PyRuntimeInfo, _unused_raw_py_runtime_info_ctor = _define_provider(
+PyRuntimeInfo, _unused_raw_py_runtime_info_ctor = define_bazel_6_provider(
doc = """Contains information about a Python runtime, as returned by the `py_runtime`
rule.
@@ -314,102 +300,13 @@
},
)
-def _check_arg_type(name, required_type, value):
- value_type = type(value)
- if value_type != required_type:
- fail("parameter '{}' got value of type '{}', want '{}'".format(
- name,
- value_type,
- required_type,
- ))
-
-def _PyInfo_init(
- *,
- transitive_sources,
- uses_shared_libraries = False,
- imports = depset(),
- has_py2_only_sources = False,
- has_py3_only_sources = False,
- direct_pyc_files = depset(),
- transitive_pyc_files = depset()):
- _check_arg_type("transitive_sources", "depset", transitive_sources)
-
- # Verify it's postorder compatible, but retain is original ordering.
- depset(transitive = [transitive_sources], order = "postorder")
-
- _check_arg_type("uses_shared_libraries", "bool", uses_shared_libraries)
- _check_arg_type("imports", "depset", imports)
- _check_arg_type("has_py2_only_sources", "bool", has_py2_only_sources)
- _check_arg_type("has_py3_only_sources", "bool", has_py3_only_sources)
- _check_arg_type("direct_pyc_files", "depset", direct_pyc_files)
- _check_arg_type("transitive_pyc_files", "depset", transitive_pyc_files)
- return {
- "direct_pyc_files": direct_pyc_files,
- "has_py2_only_sources": has_py2_only_sources,
- "has_py3_only_sources": has_py2_only_sources,
- "imports": imports,
- "transitive_pyc_files": transitive_pyc_files,
- "transitive_sources": transitive_sources,
- "uses_shared_libraries": uses_shared_libraries,
- }
-
-PyInfo, _unused_raw_py_info_ctor = _define_provider(
- doc = "Encapsulates information provided by the Python rules.",
- init = _PyInfo_init,
- fields = {
- "direct_pyc_files": """
-:type: depset[File]
-
-Precompiled Python files that are considered directly provided
-by the target.
-""",
- "has_py2_only_sources": """
-:type: bool
-
-Whether any of this target's transitive sources requires a Python 2 runtime.
-""",
- "has_py3_only_sources": """
-:type: bool
-
-Whether any of this target's transitive sources requires a Python 3 runtime.
-""",
- "imports": """\
-:type: depset[str]
-
-A depset of import path strings to be added to the `PYTHONPATH` of executable
-Python targets. These are accumulated from the transitive `deps`.
-The order of the depset is not guaranteed and may be changed in the future. It
-is recommended to use `default` order (the default).
-""",
- "transitive_pyc_files": """
-:type: depset[File]
-
-Direct and transitive precompiled Python files that are provided by the target.
-""",
- "transitive_sources": """\
-:type: depset[File]
-
-A (`postorder`-compatible) depset of `.py` files appearing in the target's
-`srcs` and the `srcs` of the target's transitive `deps`.
-""",
- "uses_shared_libraries": """
-:type: bool
-
-Whether any of this target's transitive `deps` has a shared library file (such
-as a `.so` file).
-
-This field is currently unused in Bazel and may go away in the future.
-""",
- },
-)
-
def _PyCcLinkParamsProvider_init(cc_info):
return {
"cc_info": CcInfo(linking_context = cc_info.linking_context),
}
# buildifier: disable=name-conventions
-PyCcLinkParamsProvider, _unused_raw_py_cc_link_params_provider_ctor = _define_provider(
+PyCcLinkParamsProvider, _unused_raw_py_cc_link_params_provider_ctor = define_bazel_6_provider(
doc = ("Python-wrapper to forward {obj}`CcInfo.linking_context`. This is to " +
"allow Python targets to propagate C++ linking information, but " +
"without the Python target appearing to be a valid C++ rule dependency"),
diff --git a/python/private/common/py_executable.bzl b/python/private/common/py_executable.bzl
index 80418ac..37ca313 100644
--- a/python/private/common/py_executable.bzl
+++ b/python/private/common/py_executable.bzl
@@ -19,6 +19,7 @@
load("@rules_cc//cc:defs.bzl", "cc_common")
load("//python/private:flags.bzl", "PrecompileAddToRunfilesFlag")
load("//python/private:py_executable_info.bzl", "PyExecutableInfo")
+load("//python/private:py_info.bzl", "PyInfo")
load("//python/private:reexports.bzl", "BuiltinPyRuntimeInfo")
load(
"//python/private:toolchain_types.bzl",
@@ -52,7 +53,6 @@
load(
":providers.bzl",
"PyCcLinkParamsProvider",
- "PyInfo",
"PyRuntimeInfo",
)
load(":py_internal.bzl", "py_internal")
diff --git a/python/private/py_info.bzl b/python/private/py_info.bzl
new file mode 100644
index 0000000..7945775
--- /dev/null
+++ b/python/private/py_info.bzl
@@ -0,0 +1,115 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Implementation of PyInfo provider and PyInfo-specific utilities."""
+
+load(":util.bzl", "define_bazel_6_provider")
+
+def _check_arg_type(name, required_type, value):
+ """Check that a value is of an expected type."""
+ value_type = type(value)
+ if value_type != required_type:
+ fail("parameter '{}' got value of type '{}', want '{}'".format(
+ name,
+ value_type,
+ required_type,
+ ))
+
+def _PyInfo_init(
+ *,
+ transitive_sources,
+ uses_shared_libraries = False,
+ imports = depset(),
+ has_py2_only_sources = False,
+ has_py3_only_sources = False,
+ direct_pyc_files = depset(),
+ transitive_pyc_files = depset()):
+ _check_arg_type("transitive_sources", "depset", transitive_sources)
+
+ # Verify it's postorder compatible, but retain is original ordering.
+ depset(transitive = [transitive_sources], order = "postorder")
+
+ _check_arg_type("uses_shared_libraries", "bool", uses_shared_libraries)
+ _check_arg_type("imports", "depset", imports)
+ _check_arg_type("has_py2_only_sources", "bool", has_py2_only_sources)
+ _check_arg_type("has_py3_only_sources", "bool", has_py3_only_sources)
+ _check_arg_type("direct_pyc_files", "depset", direct_pyc_files)
+ _check_arg_type("transitive_pyc_files", "depset", transitive_pyc_files)
+
+ return {
+ "direct_pyc_files": direct_pyc_files,
+ "has_py2_only_sources": has_py2_only_sources,
+ "has_py3_only_sources": has_py2_only_sources,
+ "imports": imports,
+ "transitive_pyc_files": transitive_pyc_files,
+ "transitive_sources": transitive_sources,
+ "uses_shared_libraries": uses_shared_libraries,
+ }
+
+PyInfo, _unused_raw_py_info_ctor = define_bazel_6_provider(
+ doc = "Encapsulates information provided by the Python rules.",
+ init = _PyInfo_init,
+ fields = {
+ "direct_pyc_files": """
+:type: depset[File]
+
+Precompiled Python files that are considered directly provided
+by the target and **must be included**.
+
+These files usually come from, e.g., a library setting {attr}`precompile=enabled`
+to forcibly enable precompiling for itself. Downstream binaries are expected
+to always include these files, as the originating target expects them to exist.
+""",
+ "has_py2_only_sources": """
+:type: bool
+
+Whether any of this target's transitive sources requires a Python 2 runtime.
+""",
+ "has_py3_only_sources": """
+:type: bool
+
+Whether any of this target's transitive sources requires a Python 3 runtime.
+""",
+ "imports": """\
+:type: depset[str]
+
+A depset of import path strings to be added to the `PYTHONPATH` of executable
+Python targets. These are accumulated from the transitive `deps`.
+The order of the depset is not guaranteed and may be changed in the future. It
+is recommended to use `default` order (the default).
+""",
+ "transitive_pyc_files": """
+:type: depset[File]
+
+The transitive set of precompiled files that must be included.
+
+These files usually come from, e.g., a library setting {attr}`precompile=enabled`
+to forcibly enable precompiling for itself. Downstream binaries are expected
+to always include these files, as the originating target expects them to exist.
+""",
+ "transitive_sources": """\
+:type: depset[File]
+
+A (`postorder`-compatible) depset of `.py` files appearing in the target's
+`srcs` and the `srcs` of the target's transitive `deps`.
+""",
+ "uses_shared_libraries": """
+:type: bool
+
+Whether any of this target's transitive `deps` has a shared library file (such
+as a `.so` file).
+
+This field is currently unused in Bazel and may go away in the future.
+""",
+ },
+)
diff --git a/python/private/util.bzl b/python/private/util.bzl
index 16b8ff8..3c32adc 100644
--- a/python/private/util.bzl
+++ b/python/private/util.bzl
@@ -84,6 +84,19 @@
else:
attrs["tags"] = [tag]
+# Helper to make the provider definitions not crash under Bazel 5.4:
+# Bazel 5.4 doesn't support the `init` arg of `provider()`, so we have to
+# not pass that when using Bazel 5.4. But, not passing the `init` arg
+# changes the return value from a two-tuple to a single value, which then
+# breaks Bazel 6+ code.
+# This isn't actually used under Bazel 5.4, so just stub out the values
+# to get past the loading phase.
+def define_bazel_6_provider(doc, fields, **kwargs):
+ """Define a provider, or a stub for pre-Bazel 7."""
+ if not IS_BAZEL_6_OR_HIGHER:
+ return provider("Stub, not used", fields = []), None
+ return provider(doc = doc, fields = fields, **kwargs)
+
IS_BAZEL_7_OR_HIGHER = hasattr(native, "starlark_doc_extract")
# Bazel 5.4 has a bug where every access of testing.ExecutionInfo is a
diff --git a/python/py_info.bzl b/python/py_info.bzl
index 0af35ac..52a66a8 100644
--- a/python/py_info.bzl
+++ b/python/py_info.bzl
@@ -15,7 +15,7 @@
"""Public entry point for PyInfo."""
load("@rules_python_internal//:rules_python_config.bzl", "config")
+load("//python/private:py_info.bzl", _starlark_PyInfo = "PyInfo")
load("//python/private:reexports.bzl", "BuiltinPyInfo")
-load("//python/private/common:providers.bzl", _starlark_PyInfo = "PyInfo")
PyInfo = _starlark_PyInfo if config.enable_pystar else BuiltinPyInfo