| # Copyright 2025 The Pigweed Authors |
| # |
| # 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 |
| # |
| # https://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. |
| """This library contains helpers for running Python from a repository rule.""" |
| |
| load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION") |
| load("@pythons_hub//:interpreters.bzl", "INTERPRETER_LABELS") |
| load("@zephyr_bazel_pip_deps//:requirements.bzl", _PIP_REQUIREMENTS = "all_requirements") |
| |
| # This is private to zephyr-bazel. |
| visibility(["//..."]) |
| |
| _DEFAULT_HOST_PYTHON_VERSION = "python_{}_host".format(DEFAULT_PYTHON_VERSION.replace(".", "_")) |
| _DEFAULT_PYTHON_INTERPRETER_LABEL=INTERPRETER_LABELS.get(_DEFAULT_HOST_PYTHON_VERSION) |
| |
| def _requirement_to_py_repo(requirement): |
| """Constructs the actual label to the repository containing the pip package. |
| |
| NOTE: Ideally rules_python provides a reliable API for this. |
| |
| """ |
| requirement = Label(requirement) |
| py_version = DEFAULT_PYTHON_VERSION.replace(".", "") |
| repo_name = "{}_{}_{}".format( |
| requirement.repo_name, |
| py_version, |
| requirement.package, |
| ) |
| return "@@" + repo_name + "//:BUILD.bazel" |
| |
| COMMON_PY_REPO_RULE_ATTRS = { |
| "_python_interpreter": attr.label( |
| default = _DEFAULT_PYTHON_INTERPRETER_LABEL, |
| ), |
| "_pip_deps": attr.label_list( |
| default = [_requirement_to_py_repo(req) for req in _PIP_REQUIREMENTS], |
| ), |
| } |
| |
| def get_python(rctx, extra_import_paths=[]): |
| """Returns a struct with an `execute()` method for running Python scripts/modules. |
| |
| Usage: |
| python = get_python(rctx) |
| python.execute(["path/to/script.py", "--arg1=foo", "--arg2"]) |
| |
| Args: |
| rctx: Repository context. |
| extra_import_paths: Extra directories to add to the Python include path |
| (PYTHONPATH). |
| |
| Returns: |
| A struct with an `execute()` function to run Python scripts. |
| """ |
| pip_dep_dirs = [ |
| str(rctx.path(dep).dirname) + '/site-packages' |
| for dep in rctx.attr._pip_deps |
| ] |
| pythonpath = ":".join(extra_import_paths + pip_dep_dirs) |
| |
| py_env = { |
| "PYTHONPATH": pythonpath, |
| } |
| |
| python_interpreter = str(rctx.path(rctx.attr._python_interpreter)) |
| |
| def _execute(args, **kwargs): |
| environment = kwargs.pop('environment', {}) |
| environment.update(**py_env) |
| |
| return rctx.execute( |
| [python_interpreter] + args, |
| environment=environment, |
| **kwargs, |
| ) |
| |
| return struct( |
| execute = _execute, |
| ) |