Bazel: install a python dependency for a genrule

554 views Asked by At

I am writing a Bazel macro for uploading python wheels to PyPI. In order to upload the .whl file to PyPI, I'm calling twine as the last step of my macro. Twine is a python package, and it looks like it should be installed separately. However, I want my build to be hermetic, so I would like it to be installed by the build system, and preferably not into the system python or the current virtual environment that may be activated on the user's machine. Is there a way to do so? I tried specifying it as a dependency for my genrule, but it doesn't have the deps parameter, or as a dependency for my py_wheel stage, but then twine was still not available for the upload stage. Is there a good way to do this?

Here's the call to the genrule in question:

    native.genrule(
        name = name + "_upload",
        srcs = [":" + short_name + "_wheel"],
        outs = [short_name + "_twine_upload.log"],
        cmd = "twine upload --disable-progress-bar --skip-existing $(SRCS) -u ........",
        visibility = ["//visibility:public"],
#        deps = [requirement("twine")]
    )
2

There are 2 answers

0
lummax On BEST ANSWER

What you are missing is twine in an executable form. rules_python has a mechanism for that:

load("@my_pip_install//:requirements.bzl", "entry_point")

alias(
    name = "twine",
    actual = entry_point("twine"),
)

This now generates a "binary" that you can run using bazel run or pass into your genrule().

0
noahgg On

If you would like to upload a wheel with twine, rules_python now supports that as of version 0.19.

Here is the documentation for the py_wheel rule with twine: https://rules-python.readthedocs.io/en/latest/api/packaging.html#py-wheel

Copying the code for reference:

# Use py_package to collect all transitive dependencies of a target,
# selecting just the files within a specific python package.
py_package(
    name = "example_pkg",
    # Only include these Python packages.
    packages = ["examples.wheel"],
    deps = [":main"],
)

py_wheel(
    name = "minimal_with_py_package",
    # Package data. We're building "example_minimal_package-0.0.1-py3-none-any.whl"
    distribution = "example_minimal_package",
    python_tag = "py3",
    version = "0.0.1",
    deps = [":example_pkg"],
)

And you can install twine like so: https://github.com/bazelbuild/rules_python/blob/ee2cc930e33db358c469f3bd53bc3112de8045a2/WORKSPACE#L90C1-L106C15

load("@rules_python//python:pip.bzl", "pip_parse")

pip_parse(
    name = "publish_deps",
    python_interpreter_target = interpreter,
    requirements_darwin = "//tools/publish:requirements_darwin.txt",
    requirements_lock = "//tools/publish:requirements.txt",
    requirements_windows = "//tools/publish:requirements_windows.txt",
)

load("@publish_deps//:requirements.bzl", "install_deps")

install_deps()