Импорт Bazel Genrule Python из скрипта в другом каталоге

у меня есть Базельnative.genruleкоторый вызывает скрипт Python для создания файла. В рабочей конфигурации мои файлы следующие:

Python-скрипт:

      ## test/sub1/test_python_script.py
def test_python_import():
    print("this is a function to test function import")


if __name__=="__main__":
    test_python_import()

файл

      ## test/sub1/BUILD
load(":test.bzl", "test_python_import")

filegroup(
    name = "test_python_import_script",
    srcs = ["test_python_import.py"],
    visibility = ["//visibility:public"],
)

test_python_import(
    name = "test_python_import",
    out_ = "test.txt",
    visibility = ["//visibility:public"],
)

test.bzlфайл:

      # test/sub1/test.bzl
def test_python_import(
        name,
        out_ = "",
        **kwargs):
    native.genrule(
        name = name,
        outs=[out_,],
        cmd = "python3 $(location //project/test/sub1:test_python_import_script) > $(@)",
        tools = ["//project/test/sub1:test_python_import_script:test_python_import_script"],
    )

Из этого рабочего состояния я хочу переместить функциюtest_python_import()в другой файл Python, чтобы его можно было использовать и в других сценариях.

Если я создам новый файл (common.py) в той же подпапкеsub1, я могу импортировать перемещенные функции в скриптtest_python_importс:

      from common import test_python_import

и все работает, ничего менять не надо.

Если новый скрипт, содержащий определение функции, находится в другой папке, т.е./test/sub2/common.py:

      # test/sub2/common.py
def test_python_import():
    print("this is a function to test function import")

и измените исходный скрипт, включив в него эту функцию:

      ## test/sub1/test_python_script.py
from project.test.sub2 import test_python_import

if __name__=="__main__":
    test_python_import()

это не работает. Я попытался добавить файл для использованияfilegroupи добавьте эту цель в атрибуты и/или макроса bazel:

      # test/sub2/BUILD
filegroup(
    name = "common_script",
    srcs = ["common.py"],
    visibility = visibility = ["//visibility:public"],
)

Новое определение макроса

      # test/sub1/test.bzl
def test_python_import(
        name,
        out_ = "",
        **kwargs):
    native.genrule(
        name = name,
        outs=[out_,],
        srcs = ["//app/test/sub2:common_script",],
        cmd = "python3 $(location //app/test/sub1:test_python_import_script) > $(@)",
        tools = [
            "//app/test/sub1:test_python_import_script",
            "//app/test/sub2:common_script",
        ],
    )

но я получаю ошибку

      Traceback (most recent call last):
  File "app/test/sub1/test_python_import.py", line 1, in <module>
    from app.test.sub2 import test_python_import
ModuleNotFoundError: No module named 'app'

Я попытался изменитьtest/sub2/BUILDфайл для определения библиотеки Python, добавив пустой__init__.pyскрипт и модифицируемBUILDфайл на следующее:

      # test/sub2/BUILD
py_library(
    name = "general_script",
    deps = [],
    srcs = ["general_script.py"],
    visibility = ["//visibility:public"],
)

filegroup(
    name = "general_script",
    srcs = ["codegen_utils.py"],
    visibility = ["//visibility:public"],
)
filegroup(
    name = "init",
    srcs = ["__init__.py"],
    visibility = ["//visibility:public"],
)

а также по-разному модифицировать правило, добавляя и то, и другое кsrcsиtoolsполя цели, определенные в новомapp/test/sub2/commonа затем импортируйте вtest_python_import.pyзапишите функцию, но что бы я ни пробовал до сих пор, я продолжаю получать ту же ошибку.

Как импортировать функции, определенные в скрипте, в другой скрипт, находящийся в другом каталоге внутри правила?

1 ответ

Вместо того, чтобы вручную вызыватьpython3 myscript.py, лучше указать двоичный файл вgenrule.toolsи вызвать это. В этом случае используйтеpy_binary. Если вам нужна отдельно используемая библиотека, поместите ее вpy_libraryи сделать так, чтобы двоичный файл зависел от него. Обратите внимание, что вам может потребоваться установитьpy_library.importsатрибут, чтобы получить правильные пути к sys.path и импортировать его под нужным именем.

      genrule(
  cmd = "$(rootpath :mybin) > $(@)"
  tools = [":mybin"]
)
py_binary(
  name = "mybin",
  srcs = ["mybin.py"],
  deps = [":mylib"],
)
py_library(name = "mylib", srcs=["mylib.py"])

Обратите внимание, что это обычно справедливо для любого инструмента, который вы используете в правиле — лучше использовать двоичные правила, специфичные для конкретного языка. Это позволяет им собирать исходники в правильный исполняемый файл. Это также уменьшает источник системных зависимостей. например, для того, чтобыcmd = "python3 bla.py"для работы требуется, чтобы хост-система, на которой выполняется команда, имела совместимую версию python3, доступную по пути в среде оболочки genrule (плюс любые другие зависимости, такие как сторонние библиотеки и т. д.). Например, при использовании py_binary эти зависимости обрабатываются правилом и инфраструктурой Bazel.

Другие вопросы по тегам