| # Copyright 2022 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. |
| """Providers for Python rules.""" |
| |
| load(":common/python/semantics.bzl", "TOOLS_REPO") |
| |
| _CcInfo = _builtins.toplevel.CcInfo |
| |
| # NOTE: This is copied to PyRuntimeInfo.java |
| DEFAULT_STUB_SHEBANG = "#!/usr/bin/env python3" |
| |
| # NOTE: This is copied to PyRuntimeInfo.java |
| DEFAULT_BOOTSTRAP_TEMPLATE = "@" + TOOLS_REPO + "//tools/python:python_bootstrap_template.txt" |
| _PYTHON_VERSION_VALUES = ["PY2", "PY3"] |
| |
| def _PyRuntimeInfo_init( |
| *, |
| interpreter_path = None, |
| interpreter = None, |
| files = None, |
| coverage_tool = None, |
| coverage_files = None, |
| python_version, |
| stub_shebang = None, |
| bootstrap_template = None): |
| if (interpreter_path and interpreter) or (not interpreter_path and not interpreter): |
| fail("exactly one of interpreter or interpreter_path must be specified") |
| |
| if interpreter_path and files != None: |
| fail("cannot specify 'files' if 'interpreter_path' is given") |
| |
| if (coverage_tool and not coverage_files) or (not coverage_tool and coverage_files): |
| fail( |
| "coverage_tool and coverage_files must both be set or neither must be set, " + |
| "got coverage_tool={}, coverage_files={}".format( |
| coverage_tool, |
| coverage_files, |
| ), |
| ) |
| |
| if python_version not in _PYTHON_VERSION_VALUES: |
| fail("invalid python_version: '{}'; must be one of {}".format( |
| python_version, |
| _PYTHON_VERSION_VALUES, |
| )) |
| |
| if files != None and type(files) != type(depset()): |
| fail("invalid files: got value of type {}, want depset".format(type(files))) |
| |
| if interpreter: |
| if files == None: |
| files = depset() |
| else: |
| files = None |
| |
| if coverage_files == None: |
| coverage_files = depset() |
| |
| if not stub_shebang: |
| stub_shebang = DEFAULT_STUB_SHEBANG |
| |
| return { |
| "interpreter_path": interpreter_path, |
| "interpreter": interpreter, |
| "files": files, |
| "coverage_tool": coverage_tool, |
| "coverage_files": coverage_files, |
| "python_version": python_version, |
| "stub_shebang": stub_shebang, |
| "bootstrap_template": bootstrap_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 = provider( |
| doc = """Contains information about a Python runtime, as returned by the `py_runtime` |
| rule. |
| |
| A Python runtime describes either a *platform runtime* or an *in-build runtime*. |
| A platform runtime accesses a system-installed interpreter at a known path, |
| whereas an in-build runtime points to a `File` that acts as the interpreter. In |
| both cases, an "interpreter" is really any executable binary or wrapper script |
| that is capable of running a Python script passed on the command line, following |
| the same conventions as the standard CPython interpreter. |
| """, |
| init = _PyRuntimeInfo_init, |
| fields = { |
| "interpreter_path": ( |
| "If this is a platform runtime, this field is the absolute " + |
| "filesystem path to the interpreter on the target platform. " + |
| "Otherwise, this is `None`." |
| ), |
| "interpreter": ( |
| "If this is an in-build runtime, this field is a `File` representing " + |
| "the interpreter. Otherwise, this is `None`. Note that an in-build " + |
| "runtime can use either a prebuilt, checked-in interpreter or an " + |
| "interpreter built from source." |
| ), |
| "files": ( |
| "If this is an in-build runtime, this field is a `depset` of `File`s" + |
| "that need to be added to the runfiles of an executable target that " + |
| "uses this runtime (in particular, files needed by `interpreter`). " + |
| "The value of `interpreter` need not be included in this field. If " + |
| "this is a platform runtime then this field is `None`." |
| ), |
| "coverage_tool": ( |
| "If set, this field is a `File` representing tool used for collecting code coverage information from python tests. Otherwise, this is `None`." |
| ), |
| "coverage_files": ( |
| "The files required at runtime for using `coverage_tool`. " + |
| "Will be `None` if no `coverage_tool` was provided." |
| ), |
| "python_version": ( |
| "Indicates whether this runtime uses Python major version 2 or 3. " + |
| "Valid values are (only) `\"PY2\"` and " + |
| "`\"PY3\"`." |
| ), |
| "stub_shebang": ( |
| "\"Shebang\" expression prepended to the bootstrapping Python stub " + |
| "script used when executing `py_binary` targets. Does not " + |
| "apply to Windows." |
| ), |
| "bootstrap_template": ( |
| "See py_runtime_rule.bzl%py_runtime.bootstrap_template for docs." |
| ), |
| }, |
| ) |
| |
| 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): |
| _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) |
| return { |
| "transitive_sources": transitive_sources, |
| "imports": imports, |
| "uses_shared_libraries": uses_shared_libraries, |
| "has_py2_only_sources": has_py2_only_sources, |
| "has_py3_only_sources": has_py2_only_sources, |
| } |
| |
| PyInfo, _unused_raw_py_info_ctor = provider( |
| "Encapsulates information provided by the Python rules.", |
| init = _PyInfo_init, |
| fields = { |
| "transitive_sources": """\ |
| 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": """ |
| 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. |
| """, |
| "imports": """\ |
| 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). |
| """, |
| "has_py2_only_sources": "Whether any of this target's transitive sources requires a Python 2 runtime.", |
| "has_py3_only_sources": "Whether any of this target's transitive sources requires a Python 3 runtime.", |
| }, |
| ) |
| |
| 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 = provider( |
| doc = ("Python-wrapper to forward 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"), |
| init = _PyCcLinkParamsProvider_init, |
| fields = { |
| "cc_info": "A CcInfo instance; it has only linking_context set", |
| }, |
| ) |