Skip to content

Commit fc9cdeb

Browse files
committed
Generate main.py so we can get independent of ipython
1 parent 6c2dd35 commit fc9cdeb

File tree

6 files changed

+108
-26
lines changed

6 files changed

+108
-26
lines changed

python/bin/BUILD.bazel

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
load("//python/private:interpreter.bzl", _interpreter_binary = "interpreter_binary")
2+
load("//python/private:repl.bzl", "generate_repl_main")
23
load("//python:py_binary.bzl", "py_binary")
34

45
filegroup(
@@ -24,27 +25,38 @@ label_flag(
2425
build_setting_default = "//python:none",
2526
)
2627

28+
generate_repl_main(
29+
name = "repl_py",
30+
out = "repl.py",
31+
src = "repl_stub.py",
32+
)
33+
34+
label_flag(
35+
name = "repl_stub",
36+
build_setting_default = "repl_stub.py",
37+
)
38+
39+
# The user can modify this flag to make an interpreter shell library available
40+
# for the stub. E.g. if they switch the stub for an ipython-based on, then they
41+
# can point this at their version of ipython.
42+
label_flag(
43+
name = "repl_stub_dep",
44+
build_setting_default = "//python/private:empty",
45+
)
46+
2747
py_binary(
2848
name = "repl",
29-
srcs = ["repl.py"],
49+
srcs = [":repl.py"],
3050
deps = [
51+
":repl_stub_dep",
3152
":repl_dep",
32-
":repl_lib_dep",
3353
],
3454
visibility = ["//visibility:public"],
3555
)
3656

37-
# The user can modify this flag to make arbitrary libraries available for import
38-
# on the REPL. Anything that exposes PyInfo can be used here.
57+
# The user can modify this flag to make arbitrary PyInfo targets available for
58+
# import on the REPL.
3959
label_flag(
4060
name = "repl_dep",
41-
build_setting_default = "//python:none",
42-
)
43-
44-
# The user can modify this flag to make additional libraries available
45-
# specifically for the purpose of interacting with the REPL. For example, point
46-
# this at ipython in your .bazelrc file.
47-
label_flag(
48-
name = "repl_lib_dep",
49-
build_setting_default = "//python:none",
61+
build_setting_default = "//python/private:empty",
5062
)

python/bin/repl_stub.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import code
2+
code.interact(local=dict(globals(), **locals()))

python/private/BUILD.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,13 @@ py_library(
789789
],
790790
)
791791

792+
py_binary(
793+
name = "repl_main_generator",
794+
srcs = [
795+
"repl_main_generator.py",
796+
],
797+
)
798+
792799
# The current toolchain's interpreter as an excutable, usable with
793800
# executable=True attributes.
794801
current_interpreter_executable(
@@ -798,6 +805,10 @@ current_interpreter_executable(
798805
visibility = ["//visibility:public"],
799806
)
800807

808+
py_library(
809+
name = "empty",
810+
)
811+
801812
sentinel(
802813
name = "sentinel",
803814
)

python/private/repl.bzl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
def _generate_repl_main_impl(ctx):
2+
args = ctx.actions.args()
3+
args.add_all([
4+
ctx.file._template,
5+
ctx.file.src,
6+
ctx.outputs.out,
7+
])
8+
9+
ctx.actions.run(
10+
executable = ctx.executable._generator,
11+
inputs = [
12+
ctx.file._template,
13+
ctx.file.src,
14+
],
15+
outputs = [ctx.outputs.out],
16+
arguments = [args],
17+
)
18+
19+
generate_repl_main = rule(
20+
implementation = _generate_repl_main_impl,
21+
attrs = {
22+
"out": attr.output(
23+
mandatory = True,
24+
),
25+
"src": attr.label(
26+
mandatory = True,
27+
allow_single_file = True,
28+
),
29+
"_template": attr.label(
30+
default = "//python/private:repl_template.py",
31+
allow_single_file = True,
32+
),
33+
"_generator": attr.label(
34+
default = "//python/private:repl_main_generator",
35+
executable = True,
36+
cfg = "exec",
37+
),
38+
},
39+
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import sys
2+
import textwrap
3+
from pathlib import Path
4+
5+
LINE_TO_REPLACE = """\
6+
pass # %REPLACE_WHOLE_LINE_WITH_STUB%
7+
"""
8+
9+
def main(argv):
10+
template = Path(sys.argv[1])
11+
stub = Path(sys.argv[2])
12+
output = Path(sys.argv[3])
13+
14+
template_text = template.read_text()
15+
stub_text = stub.read_text()
16+
17+
indented_stub_text = textwrap.indent(stub_text, " " * 4)
18+
19+
output_text = template_text.replace(LINE_TO_REPLACE, indented_stub_text)
20+
if template_text == output_text:
21+
raise ValueError("Failed to find the following in the template: {LINE_TO_REPLACE}")
22+
23+
output.write_text(output_text)
24+
25+
26+
if __name__ == "__main__":
27+
sys.exit(main(sys.argv))
Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import os
22
from pathlib import Path
33

4-
def start_repl():
5-
# Point libedit/readline at the correct terminfo databases.
6-
# https://github.com/astral-sh/python-build-standalone/blob/f0abfc9cb1f6a985fc5561cf5435f7f6e8a64e5b/docs/quirks.rst#backspace-key-doesnt-work-in-python-repl
7-
os.environ["TERMINFO_DIRS"] = "/etc/terminfo:/lib/terminfo:/usr/share/terminfo"
4+
def repl_stub():
5+
pass # %REPLACE_WHOLE_LINE_WITH_STUB%
86

7+
def start_repl():
98
# Simulate Python's behavior when a valid startup script is defined by the
109
# PYTHONSTARTUP variable. If this file path fails to load, print the error
1110
# and revert to the default behavior.
@@ -18,15 +17,7 @@ def start_repl():
1817
compiled_code = compile(source_code, filename=startup_file, mode="exec")
1918
eval(compiled_code, {})
2019

21-
try:
22-
# If the user has made ipython available somehow (e.g. via
23-
# `repl_lib_dep`), then use it.
24-
import IPython
25-
IPython.start_ipython()
26-
except ModuleNotFoundError:
27-
# Fall back to the default shell.
28-
import code
29-
code.interact(local=dict(globals(), **locals()))
20+
repl_stub()
3021

3122
if __name__ == "__main__":
3223
start_repl()

0 commit comments

Comments
 (0)