Skip to content

[RFC] Module scripts #649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions pysrc/juliacall/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import argparse

from juliacall import Main
from juliacall.repl import run_repl, add_repl_args


def main():
parser = argparse.ArgumentParser("JuliaCall REPL (experimental)")
parser.add_argument('-e', '--eval', type=str, default=None, help='Evaluate <expr>. If specified, all other arguments are ignored.')
parser.add_argument('-E', '--print', type=str, default=None, help='Evaluate <expr> and display the result. If specified, all other arguments are ignored.')

add_repl_args(parser)

args = parser.parse_args()
assert not (args.eval is not None and args.print is not None), "Cannot specify both -e/--eval and -E/--print"

if args.eval is not None:
Main.seval(args.eval)
elif args.print is not None:
result = Main.seval(args.print)
Main.display(result)
else:
run_repl(
banner=args.banner,
quiet=args.quiet,
history_file=args.history_file,
preamble=args.preamble
)

if __name__ == '__main__':
main()
60 changes: 60 additions & 0 deletions pysrc/juliacall/banner.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# https://github.com/JuliaLang/julia/blob/fae0d0ad3e5d9804533435fe81f4eaac819895af/stdlib/REPL/src/REPL.jl#L1727C1-L1795C4

function __PythonCall_banner(banner_opt::Symbol = :yes)
io = stdout

if banner_opt == :no
return
end

short = banner_opt == :short

if get(io, :color, false)::Bool
c = Base.text_colors
tx = c[:normal] # text
jl = c[:normal] # julia
jc = c[:blue] # juliacall text
jb = c[:bold] * jc # bold blue dot
d1 = c[:bold] * c[:blue] # first dot
d2 = c[:bold] * c[:red] # second dot
d3 = c[:bold] * c[:green] # third dot
d4 = c[:bold] * c[:magenta] # fourth dot
d5 = c[:bold] * c[:yellow] # bold yellow dot

if short
print(io,"""
$(jb)o$(tx) | Julia $(VERSION)
$(jb)o$(tx) $(d5)o$(tx) | PythonCall $(PythonCall.VERSION)
""")
else
print(io,""" $(d3)_$(tx)
$(d1)_$(tx) $(jl)_$(tx) $(d2)_$(d3)(_)$(d4)_$(tx)$(jc) _ _ $(tx) | Documentation: https://juliapy.github.io/PythonCall.jl/
$(d1)(_)$(jl) | $(d2)(_)$(tx) $(d4)(_)$(tx)$(jc) | || |$(tx) |
$(jl)_ _ _| |_ __ _$(jc) ___ __ _ | || |$(tx) | Julia: $(VERSION)
$(jl)| | | | | | |/ _` |$(jc)/ __|/ _` || || |$(tx) | PythonCall: $(PythonCall.VERSION)
$(jl)| | |_| | | | (_| |$(jc) |__ (_| || || |$(tx) |
$(jl)_/ |\\__'_|_|_|\\__'_|$(jc)\\___|\\__'_||_||_|$(tx) | The JuliaCall REPL is experimental.
$(jl)|__/$(tx) |

""")
end
else
if short
print(io,"""
o | Julia $(VERSION)
o o | PythonCall $(PythonCall.VERSION)
""")
else
print(io,"""
_
_ _ _(_)_ _ _ | Documentation: https://juliapy.github.io/PythonCall.jl/
(_) | (_) (_) | || | |
_ _ _| |_ __ _ ___ __ _ | || | | Julia: $(VERSION)
| | | | | | |/ _` |/ __|/ _` || || | | PythonCall: $(PythonCall.VERSION)
| | |_| | | | (_| | |__ (_| || || | |
_/ |\\__'_|_|_|\\__'_|\\___|\\__'_||_||_| | The JuliaCall REPL is experimental.
|__/ |
""")
end
end
end
14 changes: 14 additions & 0 deletions pysrc/juliacall/init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import json
import juliapkg
import sys

if __name__ == '__main__':
# invoking python -m juliacall.init automatically imports juliacall which
# calls init() which calls juliapkg.executable() which lazily downloads julia

if "--debug" in sys.argv:
state = juliapkg.state.STATE
state["version"] = str(state["version"])
print(json.dumps(state, indent=2))
else:
print("Initialized successfully. Pass --debug to see the full JuliaPkg state.")
45 changes: 45 additions & 0 deletions pysrc/juliacall/repl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import argparse
import os
from pathlib import Path

from juliacall import Main, Base

def run_repl(banner='yes', quiet=False, history_file='yes', preamble=None):
os.environ.setdefault("PYTHON_JULIACALL_HANDLE_SIGNALS", "yes")
if os.environ.get("PYTHON_JULIACALL_HANDLE_SIGNALS") != "yes":
print("Experimental JuliaCall REPL requires PYTHON_JULIACALL_HANDLE_SIGNALS=yes")
exit(1)

Base.is_interactive = True

if not quiet:
Main.include(os.path.join(os.path.dirname(__file__), 'banner.jl'))
Main.__PythonCall_banner(Base.Symbol(banner))

if Main.seval(r'VERSION > v"v1.11.0-alpha1"'):
no_banner_opt = Base.Symbol("no")
else:
no_banner_opt = False

if preamble:
Main.include(str(preamble.resolve()))

Base.run_main_repl(
Base.is_interactive,
quiet,
no_banner_opt,
history_file == 'yes',
True
)

def add_repl_args(parser):
parser.add_argument('--banner', choices=['yes', 'no', 'short'], default='yes', help='Enable or disable startup banner')
parser.add_argument('--quiet', '-q', action='store_true', help='Quiet startup: no banner, suppress REPL warnings')
parser.add_argument('--history-file', choices=['yes', 'no'], default='yes', help='Load or save history')
parser.add_argument('--preamble', type=Path, help='Code to be included before the REPL starts')

if __name__ == '__main__':
parser = argparse.ArgumentParser("JuliaCall REPL (experimental)")
add_repl_args(parser)
args = parser.parse_args()
run_repl(args.banner, args.quiet, args.history_file, args.preamble)
Loading