Skip to content

Commit

Permalink
refactor: move PyInfo into separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
rickeylev committed Sep 25, 2024
1 parent b92927d commit 7e176a1
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 112 deletions.
2 changes: 1 addition & 1 deletion python/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ bzl_library(
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",
],
)
Expand Down
9 changes: 9 additions & 0 deletions python/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,15 @@ bzl_library(
srcs = ["py_executable_info.bzl"],
)

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"],
Expand Down
4 changes: 3 additions & 1 deletion python/private/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ bzl_library(
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",
Expand Down Expand Up @@ -68,6 +68,7 @@ bzl_library(
":providers_bzl",
":py_internal_bzl",
":semantics_bzl",
"//python/private:py_info_bzl",
"//python/private:reexports_bzl",
"//python/private:rules_cc_srcs_bzl",
],
Expand Down Expand Up @@ -133,6 +134,7 @@ bzl_library(
":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",
Expand Down
2 changes: 1 addition & 1 deletion python/private/common/attributes.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
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",
Expand Down
2 changes: 1 addition & 1 deletion python/private/common/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
109 changes: 3 additions & 106 deletions python/private/common/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,14 @@
"""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"

DEFAULT_BOOTSTRAP_TEMPLATE = Label("//python/private:bootstrap_template")

_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

Expand Down Expand Up @@ -133,9 +121,7 @@ def _PyRuntimeInfo_init(
"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.
Expand Down Expand Up @@ -314,102 +300,13 @@ The following substitutions are made during template expansion:
},
)

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"),
Expand Down
2 changes: 1 addition & 1 deletion python/private/common/py_executable.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
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",
Expand Down Expand Up @@ -52,7 +53,6 @@ load(
load(
":providers.bzl",
"PyCcLinkParamsProvider",
"PyInfo",
"PyRuntimeInfo",
)
load(":py_internal.bzl", "py_internal")
Expand Down
115 changes: 115 additions & 0 deletions python/private/py_info.bzl
Original file line number Diff line number Diff line change
@@ -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.
""",
},
)
13 changes: 13 additions & 0 deletions python/private/util.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ def add_tag(attrs, tag):
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
Expand Down
2 changes: 1 addition & 1 deletion python/py_info.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 7e176a1

Please sign in to comment.