Would a py_interactive rule be useful to include?
🚀 feature request
This is a request to get thoughts on contributing https://github.com/jpwoodbu/rules_python_interactive to rules_python.
Relevant Rules
Perhaps py_binary and py_library?
Description
I have made https://github.com/jpwoodbu/rules_python_interactive, which adds a py_interactive macro, and I wonder if it's worth including within rules_python itself. I see there's a relatively new REPL feature that does nearly the same thing. But there are some important ergonomic differences.
py_interactivetargets are set up withinBUILD.bazelfiles just like apy_binary.py_interactiveshells have tab completion.py_interactivehas an optionalpushesargument for initial setup (e.g. importing a module).
Having the setup within the BUILD.bazel file is really the key difference. If you often need to debug inside an interactive shell, it's nice to have the configuration in place and just a simple bazel run :my_library_interactive away. The setup is also very easy to understand. In most cases, it's identical to setting up a py_binary.
Describe the solution you'd like
My preferred solution would be to add py_interactive from https://github.com/jpwoodbu/rules_python_interactive to rules_python, should it makes sense to do so. This is not a proposal to remove the REPL feature. It could be worth having both: one that requires setup but is easier to use and one that only requires the right command line.
Describe alternatives you've considered
I had considered having a virtual rule for py_library where you could run a py_library target, perhaps with a .i suffix to get an interactive shell. But I suspect there would be many efficiency downsides for Bazel itself. And it lacks the configurability of a whole new rule/macro (e.g. adding a specific collection of deps unlike any existing py_library targets).
Thank you for this suggestion.
I think REPL improvements would be more welcome at this point. Are there things that are not possible to do in the current implementation?
py_interactivetargets are set up withinBUILD.bazelfiles just like apy_binary.py_interactiveshells have tab completion.py_interactivehas an optionalpushesargument for initial setup (e.g. importing a module).
- If I remember correctly user can use the
REPLfunctionality in this way. We would need to expose thepy_repl_binary. We can discuss this. - Is it possible to change the current REPL to have tab completion? That sounds like a bug in the current implementation.
- The initial setup script sounds like a useful feature. We have a REPL stub template that the user can modify. If that does not work I would be in general +1 for adding extra features to the current REPL rule. @philsc, what do you think?
I had considered having a virtual rule...
We had a discussion about making py_library a macro and it was not something we would like to facilitate because in big monorepos with large trees of py_library the explosion of number of targets would not be welcome. Let me know if I am misunderstanding.
Thanks for the quick reply! It does seem likely that the REPL feature can be expanded to have feature parity with py_interactive.
- If I remember correctly user can use the
REPLfunctionality in this way. We would need to expose thepy_repl_binary. We can discuss this.
That would be great! Do I understand correctly that this is not currently possible with rules_python 1.5.1?
- Is it possible to change the current REPL to have tab completion? That sounds like a bug in the current implementation.
I recall when I started working on rules_python_interactive I tried using REPL and it didn't have tab completion. I'm trying to reproduce that now and I'm getting consistent errors, even just running the REPL target with no flags. This is with rules_python at 1.5.1 and Bazel at 8.3.1.
$ bazel run @rules_python//python/bin:repl
INFO: Analyzed target @@rules_python+//python/bin:repl (80 packages loaded, 3591 targets configured).
INFO: Found 1 target...
Target @@rules_python+//python/bin:repl up-to-date:
bazel-bin/external/rules_python+/python/bin/repl
bazel-bin/external/rules_python+/python/bin/repl_py.py
INFO: Elapsed time: 0.411s, Critical Path: 0.01s
INFO: 1 process: 6 action cache hit, 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Running command line: bazel-bin/external/rules_python+/python/bin/repl
Python 3.11.13 (main, Jun 9 2025, 18:12:55) [Clang 20.1.4 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
Traceback (most recent call last):
File "/home/jpwoodbu/.cache/bazel/_bazel_jpwoodbu/8397f2dfb504462de4c34c835e54a0bf/execroot/_main/bazel-out/k8-fastbuild/bin/external/rules_python+/python/bin/repl.runfiles/rules_python+/python/bin/repl_py.py", line 45, in <module>
start_repl()
File "/home/jpwoodbu/.cache/bazel/_bazel_jpwoodbu/8397f2dfb504462de4c34c835e54a0bf/execroot/_main/bazel-out/k8-fastbuild/bin/external/rules_python+/python/bin/repl.runfiles/rules_python+/python/bin/repl_py.py", line 38, in start_repl
bazel_runfiles.Rlocation(STUB_PATH),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jpwoodbu/.cache/bazel/_bazel_jpwoodbu/8397f2dfb504462de4c34c835e54a0bf/execroot/_main/bazel-out/k8-fastbuild/bin/external/rules_python+/python/bin/repl.runfiles/rules_python+/python/runfiles/runfiles.py", line 176, in Rlocation
raise ValueError('path is not normalized: "%s"' % path)
ValueError: path is not normalized: "rules_python+/../rules_python+/python/bin/repl_stub.py"
- The initial setup script sounds like a useful feature. We have a REPL stub template that the user can modify. If that does not work I would be in general +1 for adding extra features to the current REPL rule. @philsc, what do you think?
The stub template, at least based on the docs, looks like it would be good at setting a global config, but something analogous to the pushes arg for py_interactive would need to be configurable per py_repl_binary target, for example. Especially if the main use case are statements importing one or more specific dependencies listed in the deps for a particular py_repl_binary target.
I consider the pushes feature a "would be nice". I personally wouldn't likely use py_interactive if I could use py_repl_binary and it had tab completion.
- That would be great! Do I understand correctly that this is not currently possible with rules_python 1.5.1?
It is possible to use it but the symbol needs to be imported from //python/private, which means that it has no guarantees of having docs and/or maintaining backwards compatibility. I would be willing to accept a PR that creates a //python:py_repl_binary.bzl that re-exports the symbol with the docs that are exposed in //docs on how to use it.
- ...
For me the following works:
bazel run @rules_python//python/bin:repl --@rules_python//python/bin:repl_dep=@rules_python//tools:wheelmaker
But as you say, it does not have tab completion.
Thanks for confirming the tab completion behavior. I am willing to work on a PR, but I'm blocked with persistent trouble getting the REPL feature to work on my machines. Even with a clean Bazel module on two different machines, it's giving me the same error. I've filed https://github.com/bazel-contrib/rules_python/issues/3101.
My inexperience with github might be making a mess of things, but I have a fix for the tab completion in another commit from the same branch for my PR for #3101. https://github.com/bazel-contrib/rules_python/commit/48222f1781238cc0935a75eaeba4d31e61e8932a
I neglected to cite this issue in that commit.
The lack of tab completion comes from the code module not implementing it. The ipython implementation does have code completion which is the one we use at work.
I think everyone would benefit from a better implementation that does have tab completion. If you're interested in enhancing the stub, that would be phenomenal. (EDIT: I see #3114 takes care of this 🙌 )
Sorry for not noticing the default setup not working. I finally managed a rules_python upgrade at work so I can start migrating the REPL stuff. Astral decided to start statically linking libpython into the binaries and it was causing unexpected disk usage issues.
The initial setup script sounds like a useful feature. We have a REPL stub template that the user can modify. If that does not work I would be in general +1 for adding extra features to the current REPL rule. @philsc, what do you think?
Exposing the "pushes" via command line arguments could work. It's been a while since I've played with string command line arguments. It's not obvious to me why that wouldn't work.
At some point though I do think there's value in having a separate macro for this. So that users can do something like this:
def custom_py_library(name, ...):
py_library(
name = name,
)
py_interactive(
name = "%s.repl" % name,
deps = [":%s" % name],
)
And then they can use that everywhere. At least that's what we do.
Or at the very least document how to create such a macro.
Thank you for this suggestion.
I think REPL improvements would be more welcome at this point. Are there things that are not possible to do in the current implementation?
py_interactivetargets are set up withinBUILD.bazelfiles just like apy_binary.py_interactiveshells have tab completion.py_interactivehas an optionalpushesargument for initial setup (e.g. importing a module).
- If I remember correctly user can use the
REPLfunctionality in this way. We would need to expose thepy_repl_binary. We can discuss this.- Is it possible to change the current REPL to have tab completion? That sounds like a bug in the current implementation.
- The initial setup script sounds like a useful feature. We have a REPL stub template that the user can modify. If that does not work I would be in general +1 for adding extra features to the current REPL rule. @philsc, what do you think?
I had considered having a virtual rule...
We had a discussion about making
py_librarya macro and it was not something we would like to facilitate because in big monorepos with large trees ofpy_librarythe explosion of number of targets would not be welcome. Let me know if I am misunderstanding.
With tab completion working and the general idea being to bring the features of py_interactive to the REPL feature of rules_python, should we change the name of this issue to something like "Expose py_repl_binary"?
I think being able to configure a target with the deps you want ahead of time, which when run, starts a REPL, has value. Having the "pushes" feature is a nice-to-have, IMO.
It's OK to keep the existing name and we can close the issue when a PR exposing the rule is done. This should involve some sort of extra documentation teaching the users how to use it and when to use the rule version when to set the label flag.
To be clear, I'm not well enough versed in this codebase to create such a PR.