diff --git a/.travis.yml b/.travis.yml index 4905bd7..86c9317 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ os: # - osx julia: - 0.6 + - 0.7 + - 1.0 # - nightly env: - CONDA_JL_VERSION="2" @@ -31,7 +33,7 @@ before_script: # - if [ $TRAVIS_OS_NAME = osx ]; then brew install gcc; fi script: - - julia --color=yes -e 'Pkg.test("IPython"; coverage=true)' + - julia --color=yes -e 'VERSION >= v"0.7-" && using Pkg; Pkg.test("IPython"; coverage=true)' after_success: # push coverage results to Coveralls - julia --color=yes -e 'cd(Pkg.dir("IPython")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())' diff --git a/README.md b/README.md index 3296af3..f190230 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,9 @@ Run `using IPython` and then type `.` in empty `julia>` prompt or run `IPython.start_ipython()`. Exiting IPython as usual (e.g., `Ctrl-D`) -brings you back to Julia REPL. Re-entering IPython keeps the previous -state. In IPython, two variables are pre-defined: `Main` for -accessing top-level namespace of the Julia REPL and `julia` for -accessing an instance of `julia.Julia` object. +brings you back to the Julia REPL. Re-entering IPython keeps the +previous state. Use pre-defined `Main` object to access Julia +namespace from IPython. **Note:** First launch of IPython may be slow. @@ -29,8 +28,7 @@ First launch of IPython may be slow. ### Python -* pyjulia -* IPython +* IPython (7.0 or above is recommended) [travis-img]: https://travis-ci.org/tkf/IPython.jl.svg?branch=master diff --git a/REQUIRE b/REQUIRE index bc2f4b7..afdd061 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1,4 @@ julia 0.6 +Compat +Conda PyCall 1.16 diff --git a/ci/before_script.jl b/ci/before_script.jl index 009b100..fb41f7f 100644 --- a/ci/before_script.jl +++ b/ci/before_script.jl @@ -1,17 +1,24 @@ +@static if VERSION >= v"0.7.0-" + using Pkg +else + macro info(x) + :(info($(esc(x)))) + end +end + # Let PyCall.jl use Python interpreter from Conda.jl # See: https://github.com/JuliaPy/PyCall.jl ENV["PYTHON"] = "" -info("Pkg.clone(pwd())") +@info "Pkg.clone(pwd())" Pkg.clone(pwd()) -info("Pkg.build(IPython)") +@info "Pkg.build(IPython)" Pkg.build("IPython") using IPython IPython.install_dependency("ipython"; force=true) -IPython.install_dependency("julia"; force=true) IPython.install_dependency("pytest"; force=true) -info("show_versions.jl") +@info "show_versions.jl" include("show_versions.jl") diff --git a/ci/show_versions.jl b/ci/show_versions.jl index 7a03d05..9288941 100644 --- a/ci/show_versions.jl +++ b/ci/show_versions.jl @@ -1,4 +1,10 @@ -for line in split(strip(readstring("REQUIRE")), '\n')[2:end] - name = split(line)[1] - println(name, "\t", Pkg.installed(name)) +if VERSION >= v"0.7.0-" + using Pkg + show(stdout, "text/plain", Pkg.installed()) + println() +else + for line in split(strip(readstring("REQUIRE")), '\n')[2:end] + name = split(line)[1] + println(name, "\t", Pkg.installed(name)) + end end diff --git a/src/IPython.jl b/src/IPython.jl index cf19aa0..66dbb35 100644 --- a/src/IPython.jl +++ b/src/IPython.jl @@ -1,5 +1,7 @@ module IPython +using Compat +using Compat: @warn, @info include("core.jl") include("convenience.jl") include("julia_repl.jl") diff --git a/src/convenience.jl b/src/convenience.jl index 4cb6dc3..e667fe2 100644 --- a/src/convenience.jl +++ b/src/convenience.jl @@ -1,6 +1,12 @@ -function envinfo(io::IO = STDOUT; verbosity::Int = 1) +@static if VERSION >= v"0.7.0-" + using InteractiveUtils: versioninfo +else + versioninfo(io; verbose=false) = Base.versioninfo(io, verbose) +end + +function envinfo(io::IO = stdout; verbosity::Int = 1) if verbosity > 0 - versioninfo(io, verbosity > 1) + versioninfo(io; verbose = verbosity > 1) println(io) end for ex in [:(PyCall.pyprogramname), @@ -11,7 +17,9 @@ function envinfo(io::IO = STDOUT; verbosity::Int = 1) :(pyversion("julia")), ] Base.show_unquoted(io, ex) - println(io, " = ", eval(ex)) + print(io, " = ") + show(io, eval(ex)) + println(io) end nothing end @@ -56,8 +64,8 @@ end function yes_or_no(prompt = string("Type \"yes\" and press enter if ", "you want to run this command."); - input = STDIN, - output = STDOUT) + input = stdin, + output = stdout) print(output, prompt, " [yes/no]: ") answer = readline(input) if answer == "yes" @@ -65,13 +73,13 @@ function yes_or_no(prompt = string("Type \"yes\" and press enter if ", elseif answer == "no" return false end - warn("Please enter \"yes\" or \"no\". Got: $answer") + @warn "Please enter \"yes\" or \"no\". Got: $answer" return false end conda_packages = ("ipython", "pytest") -NOT_INSTALLABLE = (false, "", Void) +NOT_INSTALLABLE = (false, "", Nothing) function condajl_installation(package) if PyCall.conda && package in conda_packages @@ -122,20 +130,20 @@ function install_dependency(package; force=false, dry_run=false) pip_installation] found, message, install = check_installer(package) if found - info(message) + @info message if !dry_run && (force || yes_or_no()) install() end return end end - warn("Installing $package not supported.") + @warn "Installing $package not supported." end function test_replhelper() command = `$(PyCall.pyprogramname) -m pytest` - info(command) + @info command cd(@__DIR__) do run(command) end diff --git a/src/core.jl b/src/core.jl index bbced30..969dea0 100644 --- a/src/core.jl +++ b/src/core.jl @@ -1,16 +1,33 @@ using PyCall import Conda +julia_exepath() = + joinpath(VERSION < v"0.7.0-DEV.3073" ? JULIA_HOME : Base.Sys.BINDIR, + Base.julia_exename()) + +function eval_str(code::String) + Base.eval(Main, Meta.parse(strip(code))) +end + +set_var(name::String, value) = set_var(Symbol(name), value) + +function set_var(name::Symbol, value) + Base.eval(Main, :($name = $value)) + nothing +end + function _start_ipython(name; kwargs...) pyimport("replhelper")[name](; - init_julia = false, - jl_runtime_path = joinpath(JULIA_HOME, Base.julia_exename()), + eval_str = eval_str, + set_var = set_var, kwargs...) end -start_ipython(; kwargs...) = _start_ipython(:customized_ipython; kwargs...) +function start_ipython(; kwargs...) + _start_ipython(:customized_ipython; kwargs...) +end function __init__() - unshift!(PyVector(pyimport("sys")["path"]), @__DIR__) + pushfirst!(PyVector(pyimport("sys")["path"]), @__DIR__) init_repl_if_not() end diff --git a/src/julia_repl.jl b/src/julia_repl.jl index 333da11..790f6dd 100644 --- a/src/julia_repl.jl +++ b/src/julia_repl.jl @@ -1,4 +1,9 @@ -using Base: LineEdit +@static if VERSION >= v"0.7.0-" + using REPL + using REPL: LineEdit +else + using Base: REPL, LineEdit +end # Register keybind '.' in Julia REPL: @@ -10,7 +15,7 @@ function init_repl_if_not(; _init_repl=init_repl) return end - if isinteractive() && typeof(active_repl) != Base.REPL.BasicREPL + if isinteractive() && typeof(active_repl) != REPL.BasicREPL _init_repl(active_repl) end end @@ -20,7 +25,7 @@ function init_repl(repl) start = function(s, _...) if isempty(s) || position(LineEdit.buffer(s)) == 0 # Force current_module() inside IPython to be Main: - eval(Main, :($start_ipython())) + Base.eval(Main, :($start_ipython())) println() LineEdit.edit_clear(s) else diff --git a/src/replhelper.py b/src/replhelper.py index 9c5f5b3..7493d60 100644 --- a/src/replhelper.py +++ b/src/replhelper.py @@ -11,26 +11,23 @@ def jl_name(name): class JuliaNameSpace(object): - def __init__(self, julia): - self.__julia = julia + def __init__(self, eval_str, set_var): + self.__eval = eval_str + self.__set = set_var + + eval = property(lambda self: self.__eval) def __setattr__(self, name, value): if name.startswith('_'): super(JuliaNameSpace, self).__setattr__(name, value) else: - setter = ''' - Main.PyCall.pyfunctionret( - (x) -> eval(:({} = $x)), - Any, - PyCall.PyAny) - '''.format(jl_name(name)) - self.__julia.eval(setter)(value) + self.__set(name, value) def __getattr__(self, name): if name.startswith('_'): return super(JuliaNameSpace, self).__getattr__(name) else: - return self.__julia.eval(jl_name(name)) + return self.__eval(jl_name(name)) instruction_template = """ @@ -109,12 +106,9 @@ def wrapped(*args, **kwargs): def ipython_options(**kwargs): from traitlets.config import Config - from julia import Julia - julia = Julia(**kwargs) - Main = JuliaNameSpace(julia) + Main = JuliaNameSpace(**kwargs) user_ns = dict( - julia=julia, Main=Main, ) diff --git a/test/preamble.jl b/test/preamble.jl index dafd4ff..d56aab6 100644 --- a/test/preamble.jl +++ b/test/preamble.jl @@ -14,3 +14,4 @@ macro test_nothrow(ex) end using IPython +using Compat diff --git a/test/test_convenience.jl b/test/test_convenience.jl index 1e8deed..bbaecba 100644 --- a/test/test_convenience.jl +++ b/test/test_convenience.jl @@ -3,21 +3,19 @@ module TestConvenience include("preamble.jl") @testset "Convenience" begin - @test_nothrow IPython.envinfo(DevNull) - @test IPython.pyversion("julia") isa String + @test_nothrow IPython.envinfo(devnull) @test IPython.pyversion("IPython") isa String @test IPython.pyversion("IPython") == IPython._pyversion("IPython") - @test IPython.pyversion("__NON_EXISTING__") isa Void + @test IPython.pyversion("__NON_EXISTING__") isa Nothing println("vvv DRY RUN vvv") @test_nothrow IPython.install_dependency("ipython"; dry_run=true) - @test_nothrow IPython.install_dependency("julia"; dry_run=true) @test_nothrow IPython.install_dependency("spam"; dry_run=true) println("^^^ DRY RUN ^^^") - @test IPython.yes_or_no(input=IOBuffer("yes\n"), output=DevNull) - @test IPython.yes_or_no(input=IOBuffer("no\n"), output=DevNull) == false - @test IPython.yes_or_no(input=IOBuffer("spam\n"), output=DevNull) == false + @test IPython.yes_or_no(input=IOBuffer("yes\n"), output=devnull) + @test IPython.yes_or_no(input=IOBuffer("no\n"), output=devnull) == false + @test IPython.yes_or_no(input=IOBuffer("spam\n"), output=devnull) == false @test IPython.condajl_installation("IPython") isa Tuple @test IPython.conda_installation("IPython") isa Tuple diff --git a/test/test_julia_repl.jl b/test/test_julia_repl.jl index a444285..ccd97a9 100644 --- a/test/test_julia_repl.jl +++ b/test/test_julia_repl.jl @@ -1,8 +1,13 @@ module TestJuliaREPL include("preamble.jl") -using IPython: init_repl, init_repl_if_not -using Base.Terminals: TextTerminal +using IPython: init_repl, init_repl_if_not, REPL + +@static if VERSION >= v"0.7.0-" + using REPL: TextTerminal +else + using Base.Terminals: TextTerminal +end @testset "init_repl_if_not" begin @@ -19,8 +24,13 @@ struct DummyTerminal <: TextTerminal end function dummy_repl() - repl = Base.REPL.LineEditREPL(DummyTerminal()) - repl.interface = Base.REPL.setup_interface(repl) + if VERSION >= v"0.7.0-" + hascolor = false + repl = REPL.LineEditREPL(DummyTerminal(), hascolor) + else + repl = REPL.LineEditREPL(DummyTerminal()) + end + repl.interface = REPL.setup_interface(repl) return repl end