Bazel: Allow custom stub template for py_binary's

Created on 17 Apr 2015  路  16Comments  路  Source: bazelbuild/bazel

Feature request: My team would like to use a custom stub template for our py_binary executables (setting up a customization points, etc). Is there any way to do this with Bazel, or should we write a "custom_py_binary" rule?

P4 team-Rules-Python feature request

Most helpful comment

I'm aware of two common use cases that require changes to the
Python stub.

  1. Developers want an executable that has the PYTHON_PATH of a
    given py_binary or py_library but behaves just like the standard
    Python interpreter. This executable would be used for
    experimenting in the REPL or for deploying an interpreter with
    pre-loaded libraries.

  2. Augmenting LD_LIBRARY_PATH.

All 16 comments

My two cents: in this case I think updating the existing py_binary rules is better than implementing a custom one. The feature sounds reasonable and could be useful to others too.

My team could use this as well - we have been wanting to tweak the python stub to exclude local system site-packages by adding -S to the python commandline args. Unless there's a better way of accomplishing that...?

I took @damienmg's suggestions and added a stub_template attribute and a test. Hopefully that solves your (and my) problem!

Thanks a lot for the PR Fahrzin!

It doesn't surprise me that people would want to customize the stub script, but I do wonder what all the use cases are and whether they can be achieved with a more narrow parameterization. For instance, we could add a place to insert custom PYTHONPATHs and custom interpreter flags.

I have two main concerns with this proposal. First, it seems to me that stub customization should be per-interpreter, rather than per-binary. For example, if the same binary is built on different developer machines that have different system interpreters (which is possible in the future via a py_toolchain rule), the stub scripts might need to differ. (Since currently all py_binarys in a build use --python_top as their interpreter, this means they'd all share the same stub, but that restriction will go away in the future.)

This could be implemented by adding the attribute to py_runtime, adding an Artifact field to BazelPyRuntimeProvider, and consuming that in BazelPythonSemantics#createExecutable.

My second concern is that if we expose the template, it becomes an API that we have to worry about breaking. In particular, we need to worry about the availability and meaning of the substitution placeholders. One way around this might be to guard the feature with an experimental flag.

In any case, I think this raises enough questions that I should put the above points into a design doc.

Please consider also that py_* rules on Windows do not use a stub script but a pre-built binary preamble. I suggest pointing out this difference in documentation, i.e. customizing the stub script would have no effect on Windows.

@kwatts, @benley, @fahhem: What are the exact kinds of customization people want for the stub template? It's hard for me to imagine that users should be able to manipulate the runfiles logic for instance. I understand -S for excluding site packages, but that can also be done by adding a one-off boolean attribute, or a list of strings for additional flags to pass to the interpreter before the script name.

@laszlocsomor: Does that mean the windows-specific logic in python_stub_template.txt is dead code and can be removed?

Sorry, forget almost everything I said, I got confused.
The Python stub is used on Windows, it's not dead code, so customizing it would also have an effect on Windows. It's also true that we use a launcher, which ultimately executes this stub script. Calling @meteorcloudy to verify what I said.

I got confused over the fact that for Java we also have a stub script, which is a Bash script, and its logic is fully implemented in the launcher. (We use the same launcher preamble for Python and Java binaries, but with different launch parameters, so one starts python, the other starts the JVM.)

Thanks for the clarification. So if we go ahead with this, I won't distinguish the case of windows vs unix.

Please see design doc posted here, and in particular the open questions.

Yes, I can confirm what @laszlocsomor said, we do use the stub template on Windows. The native python launcher is just used to run the stub template.

My current use case is that I'd like to insert code that runs in the stub for a certain subset of rules, such as enabling (and extracting) coverage instrumentation for py_test() rules (the stub_template attribute is available in py_test() rules too).

Other use cases in the past that would have been easier with this:

  • subpar parses the current post-substitution stub for a py_binary() rule to extract the data it needs. If it was a custom stub_template, then subpar could have created a custom stub_template that exposed the python imports as needed.
  • I also needed -S-equivalent behavior in the past, I ended up with re-doing what the stub does (execute Python with new args) at the beginning of a Python binary's lifetime. So now the stub template runs some Python, then executes Python, then we run some Python and then exec Python again. Not great. I actually needed -B as well as a mechanism to control LD_LIBRARY_PATH before Python is executed. All things that _should_ be done in the stub, but since I don't have control over that, I do it in the equivalent to google's import google3 setup.

I'm aware of two common use cases that require changes to the
Python stub.

  1. Developers want an executable that has the PYTHON_PATH of a
    given py_binary or py_library but behaves just like the standard
    Python interpreter. This executable would be used for
    experimenting in the REPL or for deploying an interpreter with
    pre-loaded libraries.

  2. Augmenting LD_LIBRARY_PATH.

Any update here @brandjon? I can update my PR again if we're okay allowing custom stubs on the py_binary rules itself. Otherwise, we will have to continue using a fork of bazel with the custom stub enabled.

If you want to pull the stub from the toolchain, then I'm happy to switch to that tactic if I have a chance of actually getting it merged in.

I merged b01c85962d88661ec9f6c6704c47d8ce67ca4d2a, with which I was able to get coverage from python using a patched pycoverage. I filed https://github.com/bazelbuild/bazel/issues/10660 as a standalone issue about coverage, and also provided instructions for how to make it work with a Bazel binary containing said patch.

Was this page helpful?
0 / 5 - 0 ratings