From 507db292bd8ad425babab024c952ce5206341e18 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Feb 2018 23:45:58 -0500 Subject: [PATCH 01/19] 0.7 compatibility (mostly) --- .travis.yml | 3 --- REQUIRE | 2 +- deps/build.jl | 10 +++++----- deps/kspec.jl | 8 ++++---- src/IJulia.jl | 13 +++++++++++- src/comm_manager.jl | 6 +++--- src/execute_request.jl | 44 +++++++++++++++++++---------------------- src/handlers.jl | 31 ++++------------------------- src/heartbeat.jl | 12 +++++++---- src/hmac.jl | 2 +- src/init.jl | 13 +++++++----- src/inline.jl | 5 ++++- src/kernel.jl | 4 ++-- src/magics.jl | 10 +++++++--- src/msg.jl | 2 +- src/stdio.jl | 17 +++++++++++----- test/comm.jl | 2 +- test/execute_request.jl | 13 ++++-------- test/msg.jl | 3 ++- 19 files changed, 99 insertions(+), 101 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f1c8a03..7680e758 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,6 @@ os: julia: - 0.6 - nightly -matrix: - allow_failures: - - julia: nightly notifications: email: false script: diff --git a/REQUIRE b/REQUIRE index 53e8fc58..f728650c 100644 --- a/REQUIRE +++ b/REQUIRE @@ -2,5 +2,5 @@ julia 0.6 MbedTLS 0.4.3 JSON 0.17 ZMQ 0.6.0 -Compat 0.41.0 +Compat 0.47.0 Conda 0.1.5 diff --git a/deps/build.jl b/deps/build.jl index 39aa789f..cc4116a0 100644 --- a/deps/build.jl +++ b/deps/build.jl @@ -19,7 +19,7 @@ function prog_version(prog) return nothing end try - return convert(VersionNumber, v) + return VersionNumber(v) catch warn("`$jupyter --version` returned an unrecognized version number $v") return v"0.0" @@ -40,8 +40,8 @@ else end isconda = dirname(jupyter) == abspath(Conda.SCRIPTDIR) if Sys.ARCH in (:i686, :x86_64) && (jupyter_vers === nothing || jupyter_vers < v"3.0" || isconda) - isconda || jupyter_vers === nothing || info("$jupyter was too old: got $jupyter_vers, required ≥ 3.0") - info("Installing Jupyter via the Conda package.") + isconda || jupyter_vers === nothing || Compat.@info("$jupyter was too old: got $jupyter_vers, required ≥ 3.0") + Compat.@info("Installing Jupyter via the Conda package.") Conda.add("jupyter") jupyter = abspath(Conda.SCRIPTDIR, "jupyter") jupyter_vers = prog_version(jupyter) @@ -49,7 +49,7 @@ end if jupyter_vers === nothing || jupyter_vers < v"3.0" error("Failed to find or install Jupyter 3.0 or later. Please install Jupyter manually, set `ENV[\"JUPYTER\"]=\"/path/to/jupyter\", and rerun `Pkg.build(\"IJulia\")`.") end -info("Found Jupyter version $jupyter_vers: $jupyter") +Compat.@info("Found Jupyter version $jupyter_vers: $jupyter") ####################################################################### # Get the latest syntax highlighter file. @@ -91,7 +91,7 @@ kspec_cmd, = installkernel("Julia") # "kernelspec" with "notebook": notebook = kspec_cmd.exec n = notebook[end] -ki = rsearch(n, "kernelspec") +ki = VERSION < v"0.7.0-DEV.3252" ? rsearch(n, "kernelspec") : findlast("kernelspec", n) notebook[end] = n[1:prevind(n,first(ki))] * "notebook" * n[nextind(n,last(ki)):end] ####################################################################### diff --git a/deps/kspec.jl b/deps/kspec.jl index 685d2505..dba91229 100644 --- a/deps/kspec.jl +++ b/deps/kspec.jl @@ -4,7 +4,7 @@ copy_config(src, dest) = cp(src, joinpath(dest, basename(src)), remove_destination=true) """ - installkernel(name, options...; specname=replace(lowercase(name), " ", "-") + installkernel(name, options...; specname=replace(lowercase(name), " "=>"-") Install a new Julia kernel, where the given `options` are passed to the `julia` executable, and the user-visible kernel name is given by `name` followed by the @@ -31,7 +31,7 @@ run(`\$kernelspec remove -f \$kernelname`) ``` """ function installkernel(name::AbstractString, julia_options::AbstractString...; - specname::AbstractString = replace(lowercase(name), " ", "-")) + specname::AbstractString = replace(lowercase(name), " "=>"-")) # Is IJulia being built from a debug build? If so, add "debug" to the description. debugdesc = ccall(:jl_is_debugbuild,Cint,())==1 ? "-debug" : "" @@ -41,7 +41,7 @@ function installkernel(name::AbstractString, julia_options::AbstractString...; juliakspec = joinpath(tempdir(), spec_name) try binary_name = Compat.Sys.iswindows() ? "julia.exe" : "julia" - kernelcmd_array = String[joinpath(JULIA_HOME,"$binary_name"), "-i", + kernelcmd_array = String[joinpath(Compat.Sys.BINDIR,"$binary_name"), "-i", "--startup-file=yes", "--color=yes"] append!(kernelcmd_array, julia_options) ijulia_dir = get(ENV, "IJULIA_DIR", dirname(@__DIR__)) # support non-Pkg IJulia installs @@ -65,7 +65,7 @@ function installkernel(name::AbstractString, julia_options::AbstractString...; copy_config(joinpath(ijulia_dir,"deps","logo-32x32.png"), juliakspec) copy_config(joinpath(ijulia_dir,"deps","logo-64x64.png"), juliakspec) - info("Installing $name kernelspec $spec_name") + Compat.@info("Installing $name kernelspec $spec_name") # remove these hacks when # https://github.com/jupyter/notebook/issues/448 is closed and the fix diff --git a/src/IJulia.jl b/src/IJulia.jl index dc086560..3015a1b9 100644 --- a/src/IJulia.jl +++ b/src/IJulia.jl @@ -38,7 +38,18 @@ export notebook, installkernel using ZMQ, JSON, Compat import Compat.invokelatest using Compat.Unicode: uppercase, lowercase +import Compat.Dates using Compat.Dates: now +import Compat.Random + +if VERSION ≥ v"0.7.0-DEV.2338" # julia#24361 + using Base64: Base64EncodePipe +end +if isdefined(Base, :REPL) && !Base.isdeprecated(Base, :REPL) + import Base.REPL +else + import REPL +end ####################################################################### # Debugging IJulia @@ -198,7 +209,7 @@ function clear_history(indices) end # since a range could be huge, intersect it with 1:n first -clear_history{T<:Integer}(r::AbstractRange{T}) = +clear_history(r::AbstractRange{T}) where {T<:Integer} = invoke(clear_history, Tuple{Any}, intersect(r, 1:n)) function clear_history() diff --git a/src/comm_manager.jl b/src/comm_manager.jl index 2d38f9d3..264c1815 100644 --- a/src/comm_manager.jl +++ b/src/comm_manager.jl @@ -7,12 +7,12 @@ import IJulia: Msg, uuid4, send_ipython, msg_pub export Comm, comm_target, msg_comm, send_comm, close_comm, register_comm, comm_msg, comm_open, comm_close, comm_info_request -type Comm{target} +mutable struct Comm{target} id::String primary::Bool on_msg::Function on_close::Function - function (::Type{Comm{target}}){target}(id, primary, on_msg, on_close) + function (::Type{Comm{target}})(id, primary, on_msg, on_close) where {target} comm = new{target}(id, primary, on_msg, on_close) comms[id] = comm return comm @@ -42,7 +42,7 @@ function Comm(target, return comm end -comm_target{target}(comm :: Comm{target}) = target +comm_target(comm :: Comm{target}) where {target} = target function comm_info_request(sock, msg) reply = if haskey(msg.content, "target_name") diff --git a/src/execute_request.jl b/src/execute_request.jl index 437af99a..b72d2f28 100644 --- a/src/execute_request.jl +++ b/src/execute_request.jl @@ -4,8 +4,6 @@ import Base.Libc: flush_cstdio -using Compat - const text_plain = MIME("text/plain") const image_svg = MIME("image/svg+xml") const image_png = MIME("image/png") @@ -59,7 +57,7 @@ const displayqueue = Any[] # remove x from the display queue function undisplay(x) i = findfirst(equalto(x), displayqueue) - if i > 0 + if i !== nothing && i > 0 splice!(displayqueue, i) end return x @@ -67,8 +65,8 @@ end function show_bt(io::IO, top_func::Symbol, t, set) # follow PR #17570 code in removing top_func from backtrace - eval_ind = findlast(addr->Base.REPL.ip_matches_func(addr, top_func), t) - eval_ind != 0 && (t = t[1:eval_ind-1]) + eval_ind = findlast(addr->REPL.ip_matches_func(addr, top_func), t) + eval_ind !== nothing && eval_ind != 0 && (t = t[1:eval_ind-1]) Base.show_backtrace(io, t) end @@ -90,9 +88,9 @@ function error_content(e, bt=catch_backtrace(); backtrace_top::Symbol=:include_s catch "SYSTEM: show(lasterr) caused an error" end - unshift!(tb, evalue) # fperez says this needs to be in traceback too + pushfirst!(tb, evalue) # fperez says this needs to be in traceback too if !isempty(msg) - unshift!(tb, msg) + pushfirst!(tb, msg) end Dict("ename" => ename, "evalue" => evalue, "traceback" => tb) @@ -106,14 +104,10 @@ execute_msg = Msg(["julia"], Dict("username"=>"jlkernel", "session"=>uuid4()), D # request const stdio_bytes = Ref(0) -function helpcode(code::AbstractString) - code_ = strip(code) - # as in base/REPL.jl, special-case keywords so that they parse - if !haskey(Docs.keywords, Symbol(code_)) - return "Base.Docs.@repl $code_" - else - return "eval(:(Base.Docs.@repl \$(Symbol(\"$code_\"))))" - end +if VERSION < v"0.7.0-DEV.3589" # julia #25738 + import Base.Docs: helpmode # added in 0.6, see julia #19858 +else + import REPL: helpmode end # use a global array to accumulate "payloads" for the execute_reply message @@ -137,30 +131,32 @@ function execute_request(socket, msg) "code" => code))) end - silent = silent || Base.REPL.ends_with_semicolon(code) + silent = silent || REPL.ends_with_semicolon(code) if store_history In[n] = code end # "; ..." cells are interpreted as shell commands for run - code = replace(code, r"^\s*;.*$", + code = replace(code, r"^\s*;.*$" => m -> string(replace(m, r"^\s*;", "Base.repl_cmd(`"), "`, STDOUT)")) # a cell beginning with "? ..." is interpreted as a help request - hcode = replace(code, r"^\s*\?", "") - if hcode != code - code = helpcode(hcode) - end + hcode = replace(code, r"^\s*\?" => "") try for hook in preexecute_hooks invokelatest(hook) end - #run the code! - ans = result = ismatch(magics_regex, code) ? magics_help(code) : - include_string(current_module[], code, "In[$n]") + + if hcode != code # help request + eval(Main, helpmode(hcode)) + else + #run the code! + ans = result = contains(code, magics_regex) ? magics_help(code) : + include_string(current_module[], code, "In[$n]") + end if silent result = nothing diff --git a/src/handlers.jl b/src/handlers.jl index d57264cb..4c6c546a 100644 --- a/src/handlers.jl +++ b/src/handlers.jl @@ -7,7 +7,7 @@ using .CommManager # due to issue #380. Find the start of the first line # (if any) where the expression is parseable. Replace # with find_parsestart(c,p) = start(c) once julia#9467 is merged. -parseok(s) = !Meta.isexpr(parse(s, raise=false), :error) +parseok(s) = !Meta.isexpr(Meta.parse(s, raise=false), :error) function find_parsestart(code, cursorpos) s = start(code) while s < cursorpos @@ -197,31 +197,8 @@ function shutdown_request(socket, msg) exit() end -stripdots(ex) = :_ -stripdots(ex::Symbol) = ex -stripdots(ex::Expr) = Meta.isexpr(ex, :.) ? stripdots(ex.args[2]) : :_ -stripdots(ex::QuoteNode) = ex.value -stripdots(ex::GlobalRef) = ex.name -rm_sideeffects(ex) = ex -function rm_sideeffects(ex::Expr) - if Meta.isexpr(ex, :call) - name = stripdots(ex.args[1]) - if name == :repl_search || name == :repl_corrections - return nothing - else - return ex - end - else - return Expr(ex.head, map(rm_sideeffects, ex.args)...) - end -end -function docdict(s::AbstractString) - ex = macroexpand(Main, parse(helpcode(s))) - # unfortunately, the REPL help macros sometimes have - # expressions with side effects (I/O), so we need to - # remove these. - display_dict(eval(Main, rm_sideeffects(ex))) -end +docdict(s::AbstractString) = display_dict(eval(Main, helpmode(DevNull, s))) + import Base: is_id_char, is_id_start_char function get_token(code, pos) # given a string and a cursor position, find substring to request @@ -287,7 +264,7 @@ function history_request(socket, msg) end function is_complete_request(socket, msg) - ex = parse(msg.content["code"], raise=false) + ex = Meta.parse(msg.content["code"], raise=false) status = Meta.isexpr(ex, :incomplete) ? "incomplete" : Meta.isexpr(ex, :error) ? "invalid" : "complete" send_ipython(requests[], msg_reply(msg, "is_complete_reply", diff --git a/src/heartbeat.jl b/src/heartbeat.jl index 157db04e..7e7996b9 100644 --- a/src/heartbeat.jl +++ b/src/heartbeat.jl @@ -4,15 +4,19 @@ # call in libzmq, which simply blocks forever, so the usual lack of # thread safety in Julia should not be an issue here. + +const threadid = zeros(Int, 128) # sizeof(uv_thread_t) <= 8 on Linux, OSX, Win +const libzmq = ZMQ.zmq + # entry point for new thread -function heartbeat_thread(sock::Ptr{Void}) - ccall((:zmq_proxy,ZMQ.libzmq), Cint, (Ptr{Void}, Ptr{Void}, Ptr{Void}), +function heartbeat_thread(sock::Ptr{Cvoid}) + ccall((:zmq_proxy,ZMQ.libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), sock, sock, C_NULL) nothing end function start_heartbeat(sock) - heartbeat_c = cfunction(heartbeat_thread, Void, Tuple{Ptr{Void}}) - ccall(:uv_thread_create, Cint, (Ptr{Int}, Ptr{Void}, Ptr{Void}), + heartbeat_c = cfunction(heartbeat_thread, Cvoid, Tuple{Ptr{Cvoid}}) + ccall(:uv_thread_create, Cint, (Ptr{Int}, Ptr{Cvoid}, Ptr{Cvoid}), threadid, heartbeat_c, sock.data) end diff --git a/src/hmac.jl b/src/hmac.jl index 783dc239..8e49a6ff 100644 --- a/src/hmac.jl +++ b/src/hmac.jl @@ -11,7 +11,7 @@ function hmac(s1,s2,s3,s4) end # Take the digest (returned as a byte array) and convert it to hex string representation digest = MbedTLS.finish!(hmacstate[]) - hexdigest = Vector{UInt8}(length(digest)*2) + hexdigest = Vector{UInt8}(uninitialized, length(digest)*2) for i = 1:length(digest) b = digest[i] d = b >> 4 diff --git a/src/init.jl b/src/init.jl index 74b499da..119f32e4 100644 --- a/src/init.jl +++ b/src/init.jl @@ -5,21 +5,24 @@ include(joinpath("..","deps","kspec.jl")) # use our own random seed for msg_id so that we # don't alter the user-visible random state (issue #336) -const IJulia_RNG = srand(MersenneTwister(0)) -uuid4() = repr(Base.Random.uuid4(IJulia_RNG)) +const IJulia_RNG = Random.srand(Random.MersenneTwister(0)) +@static if VERSION < v"0.7.0-DEV.3666" # julia#25819 + uuid4() = repr(Random.uuid4(IJulia_RNG)) +else + import UUIDs + uuid4() = repr(UUIDs.uuid4(IJulia_RNG)) +end const orig_STDIN = Ref{IO}() const orig_STDOUT = Ref{IO}() const orig_STDERR = Ref{IO}() function __init__() - srand(IJulia_RNG) + Random.srand(IJulia_RNG) orig_STDIN[] = STDIN orig_STDOUT[] = STDOUT orig_STDERR[] = STDERR end -const threadid = Vector{Int}(128) # sizeof(uv_thread_t) <= 8 on Linux, OSX, Win - # the following constants need to be initialized in init(). const ctx = Ref{Context}() const publish = Ref{Socket}() diff --git a/src/inline.jl b/src/inline.jl index 31f45ffe..85f0d463 100644 --- a/src/inline.jl +++ b/src/inline.jl @@ -1,6 +1,9 @@ import Base: display, redisplay -immutable InlineDisplay <: Display end +@static if !isdefined(Base, :AbstractDisplay) # remove when Compat.jl#482 is merged and tagged + const AbstractDisplay = Display +end +struct InlineDisplay <: AbstractDisplay end # supported MIME types for inline display in IPython, in descending order # of preference (descending "richness") diff --git a/src/kernel.jl b/src/kernel.jl index 7d096888..c28a9729 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -2,7 +2,7 @@ import IJulia # workaround #60: if IJulia.Compat.Sys.isapple() - ENV["PATH"] = JULIA_HOME*":"*ENV["PATH"] + ENV["PATH"] = IJulia.Compat.Sys.BINDIR*":"*ENV["PATH"] end IJulia.init(ARGS) @@ -12,7 +12,7 @@ import IJulia: ans, In, Out, clear_history pushdisplay(IJulia.InlineDisplay()) -ccall(:jl_exit_on_sigint, Void, (Cint,), 0) +ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0) # the size of truncated output to show should not depend on the terminal # where the kernel is launched, since the display is elsewhere diff --git a/src/magics.jl b/src/magics.jl index 084169c1..b9bc2821 100644 --- a/src/magics.jl +++ b/src/magics.jl @@ -23,7 +23,11 @@ function magics_help(code::AbstractString) end end -using Base.Markdown +@static if VERSION < v"0.7.0-DEV.3589" # julia#25738 + using Base.Markdown +else + using Markdown +end const magic_help_string = """ Julia does not use the IPython `%magic` syntax. To interact @@ -55,7 +59,7 @@ alias_magic_help(magic::AbstractString, args::AbstractString) = md""" which you can then run with e.g. `bracket("hello world")`.""" function cd_magic_help(magic::AbstractString, args::AbstractString) - if magic == "%cd" && !ismatch(r"\s*-", args) + if magic == "%cd" && !contains(args, r"\s*-") return md"""The equivalent of `%cd 'dir'` in IPython is `cd("dir")` in Julia.""" else return md""" @@ -213,7 +217,7 @@ prun_magic_help(magic::AbstractString, args::AbstractString) = md""" psearch_magic_help(magic::AbstractString, args::AbstractString) = md""" A rough analogue of IPython's `%psearch PATTERN` in Julia might be - `filter(s -> ismatch(r"PATTERN", string(s)), names(Base))`, which + `filter(s -> contains(string(s), r"PATTERN"), names(Base))`, which searches all the symbols defined in the `Base` module for a given regular-expression pattern `PATTERN`.""" diff --git a/src/msg.jl b/src/msg.jl index e41097a4..61f07650 100644 --- a/src/msg.jl +++ b/src/msg.jl @@ -3,7 +3,7 @@ import Base.show export Msg, msg_pub, msg_reply, send_status, send_ipython # IPython message structure -type Msg +mutable struct Msg idents::Vector{String} header::Dict content::Dict diff --git a/src/stdio.jl b/src/stdio.jl index 31504f24..6d498390 100644 --- a/src/stdio.jl +++ b/src/stdio.jl @@ -4,7 +4,7 @@ # create a wrapper type around redirected stdio streams, # both for overloading things like `flush` and so that we # can set properties like `color`. -immutable IJuliaStdio{IO_t <: IO} <: Base.AbstractPipe +struct IJuliaStdio{IO_t <: IO} <: Base.AbstractPipe io::IOContext{IO_t} end IJuliaStdio(io::IO, stream::AbstractString="unknown") = @@ -38,6 +38,7 @@ end # logging in verbose mode goes to original stdio streams. Use macros # so that we do not even evaluate the arguments in no-verbose modes +using Compat.Printf function get_log_preface() t = now() taskname = get(task_local_storage(), :IJulia_task, "") @@ -82,7 +83,7 @@ function watch_stream(rd::IO, name::AbstractString) buf = IOBuffer() bufs[name] = buf while !eof(rd) # blocks until something is available - nb = nb_available(rd) + nb = @static VERSION < v"0.7.0-DEV.3481" ? nb_available(rd) : bytesavailable(rd) if nb > 0 stdio_bytes[] += nb # if this stream has surpassed the maximum output limit then ignore future bytes @@ -221,17 +222,23 @@ function readline(io::IJuliaStdio) end end +if VERSION < v"0.7.0-DEV.3526" # julia#25647 + _Timer(callback, delay, repeat) = Timer(callback, delay, repeat) +else + _Timer(callback, delay, repeat) = Timer(callback, delay, interval=repeat) +end + function watch_stdio() task_local_storage(:IJulia_task, "init task") if capture_stdout read_task = @async watch_stream(read_stdout[], "stdout") #send STDOUT stream msgs every stream_interval secs (if there is output to send) - Timer(send_stdout, stream_interval, stream_interval) + _Timer(send_stdout, stream_interval, stream_interval) end if capture_stderr readerr_task = @async watch_stream(read_stderr[], "stderr") #send STDERR stream msgs every stream_interval secs (if there is output to send) - Timer(send_stderr, stream_interval, stream_interval) + _Timer(send_stderr, stream_interval, stream_interval) end end @@ -245,7 +252,7 @@ function oslibuv_flush() #refs: https://github.com/JuliaLang/IJulia.jl/issues/347#issuecomment-144505862 # https://github.com/JuliaLang/IJulia.jl/issues/347#issuecomment-144605024 @static if Compat.Sys.iswindows() - ccall(:SwitchToThread, stdcall, Void, ()) + ccall(:SwitchToThread, stdcall, Cvoid, ()) end yield() yield() diff --git a/test/comm.jl b/test/comm.jl index 0d869ca7..4cb08d52 100644 --- a/test/comm.jl +++ b/test/comm.jl @@ -1,4 +1,4 @@ -using Base.Test +using Compat.Test import IJulia: Comm, comm_target diff --git a/test/execute_request.jl b/test/execute_request.jl index 5c3e6857..20497500 100644 --- a/test/execute_request.jl +++ b/test/execute_request.jl @@ -1,14 +1,9 @@ -using Base.Test +using Compat.Test -import IJulia: helpcode, error_content - -@test !haskey(Docs.keywords, :+) -@test "Base.Docs.@repl +" == helpcode("+") - -@test haskey(Docs.keywords, :import) -@test """eval(:(Base.Docs.@repl \$(Symbol("import"))))""" == helpcode("import") +import IJulia: helpcode, error_content, docdict content = error_content(UndefVarError(:a)) @test "UndefVarError" == content["ename"] -@test haskey(IJulia.docdict("sum"), "text/plain") +@test haskey(docdict("import"), "text/plain") +@test haskey(docdict("sum"), "text/plain") diff --git a/test/msg.jl b/test/msg.jl index d710d4e5..7ca425ef 100644 --- a/test/msg.jl +++ b/test/msg.jl @@ -1,5 +1,6 @@ -using Base.Test +using Compat.Test import IJulia: Msg +using Compat.Dates idents = ["idents"] header = Dict("msg_id"=>"c673eed8-7c36-47f4-82af-df8ec546a87d", From f871e6a44e845a52cd688e85123a8efbe786cd6b Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Feb 2018 23:55:40 -0500 Subject: [PATCH 02/19] update appveyor to test nightly too --- appveyor.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 837142c0..9db26ad3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,11 +10,6 @@ branches: - master - /release-.*/ -matrix: - allow_failures: - - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" - - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" - notifications: - provider: Email on_build_success: false From adc626926ee404f5ba8b362070ecc831ddab7220 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 19 Apr 2018 19:32:25 -0400 Subject: [PATCH 03/19] fix merge error --- src/heartbeat.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/heartbeat.jl b/src/heartbeat.jl index 7e7996b9..c6b07c6a 100644 --- a/src/heartbeat.jl +++ b/src/heartbeat.jl @@ -6,7 +6,6 @@ const threadid = zeros(Int, 128) # sizeof(uv_thread_t) <= 8 on Linux, OSX, Win -const libzmq = ZMQ.zmq # entry point for new thread function heartbeat_thread(sock::Ptr{Cvoid}) From d1d65bb932a82f99d3afbfbe69c6ad15749e7bb8 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 19 Apr 2018 19:37:22 -0400 Subject: [PATCH 04/19] missing compat in kernel.jl --- src/kernel.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel.jl b/src/kernel.jl index c28a9729..6c5e9648 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -1,4 +1,5 @@ import IJulia +using Compat # workaround #60: if IJulia.Compat.Sys.isapple() From 1d05a2c3d4a9fd12cdf7c3e4f9bcc657abec4cff Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 19 Apr 2018 19:58:09 -0400 Subject: [PATCH 05/19] REPL.REPLCompletions is now in the stdlib --- src/handlers.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/handlers.jl b/src/handlers.jl index 4c6c546a..0ec91b12 100644 --- a/src/handlers.jl +++ b/src/handlers.jl @@ -51,7 +51,10 @@ Base.ind2chr(m::Msg, str::String, i::Integer) = i == 0 ? 0 : VersionNumber(m.header["version"]) ≥ v"5.2" ? ind2chr(str, i) : ind_to_utf16(str, i) #Compact display of types for Jupyterlab completion -if isdefined(Main, :REPLCompletions) +if VERSION ≥ v"0.7.0-DEV.3500" #25544 + import REPL + import REPL.REPLCompletions: sorted_keywords, emoji_symbols, latex_symbols +elseif isdefined(Main, :REPLCompletions) import REPLCompletions: sorted_keywords, emoji_symbols, latex_symbols else const sorted_keywords = [ From 9bba2a67f1760a1acb0cd5523ff75679fb658b81 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 19 Apr 2018 20:14:40 -0400 Subject: [PATCH 06/19] don't force Compat into user notebooks --- src/kernel.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/kernel.jl b/src/kernel.jl index 6c5e9648..e0be292b 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -1,5 +1,4 @@ import IJulia -using Compat # workaround #60: if IJulia.Compat.Sys.isapple() @@ -13,7 +12,7 @@ import IJulia: ans, In, Out, clear_history pushdisplay(IJulia.InlineDisplay()) -ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0) +ccall(:jl_exit_on_sigint, IJulia.Compat.Cvoid, (Cint,), 0) # the size of truncated output to show should not depend on the terminal # where the kernel is launched, since the display is elsewhere From bbdebe9ece2dbd88525479959689a9eb9302ce54 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 7 Jun 2018 16:57:54 -0400 Subject: [PATCH 07/19] fix more deprecations and a crash in heartbeat --- README.md | 4 ++-- REQUIRE | 2 +- deps/build.jl | 2 +- src/IJulia.jl | 4 ++-- src/eventloop.jl | 2 +- src/execute_request.jl | 28 +++++++++++++++------------- src/handlers.jl | 4 ++-- src/heartbeat.jl | 5 +++-- src/hmac.jl | 2 +- src/init.jl | 18 +++++++++--------- src/kernel.jl | 4 ++-- src/magics.jl | 8 ++++---- src/stdio.jl | 16 ++++++++-------- 13 files changed, 51 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 254fc4cc..ee75a30f 100644 --- a/README.md +++ b/README.md @@ -186,11 +186,11 @@ is `IJulia.load("filename")`. ### Prompting for user input -When you are running in a notebook, ordinary I/O functions on `STDIN` do +When you are running in a notebook, ordinary I/O functions on `stdin` do not function. However, you can prompt for the user to enter a string in one of two ways: -* `readline()` and `readline(STDIN)` both open a `STDIN>` prompt widget where the user can enter a string, which is returned by `readline`. +* `readline()` and `readline(stdin)` both open a `stdin>` prompt widget where the user can enter a string, which is returned by `readline`. * `IJulia.readprompt(prompt)` displays the prompt string `prompt` and returns a string entered by the user. `IJulia.readprompt(prompt, password=true)` does the same thing but hides the text the user types. diff --git a/REQUIRE b/REQUIRE index f728650c..bee34b08 100644 --- a/REQUIRE +++ b/REQUIRE @@ -2,5 +2,5 @@ julia 0.6 MbedTLS 0.4.3 JSON 0.17 ZMQ 0.6.0 -Compat 0.47.0 +Compat 0.68.0 Conda 0.1.5 diff --git a/deps/build.jl b/deps/build.jl index cc4116a0..64e32142 100644 --- a/deps/build.jl +++ b/deps/build.jl @@ -75,7 +75,7 @@ end # Warn people upgrading from older IJulia versions: try juliaprof = chomp(read(pipeline(`$ipython locate profile julia`, - stderr=DevNull), String)) + stderr=devnull), String)) warn("""You should now run IJulia just via `$jupyter notebook`, without the `--profile julia` flag. IJulia no longer maintains the profile. Consider deleting $juliaprof""") diff --git a/src/IJulia.jl b/src/IJulia.jl index 3015a1b9..d9b4fe1a 100644 --- a/src/IJulia.jl +++ b/src/IJulia.jl @@ -243,7 +243,7 @@ function history(io::IO, indices::AbstractVector{Int}) end history(io::IO, x::Union{Integer,AbstractVector{Int}}...) = history(io, vcat(x...)) -history(x...) = history(STDOUT, x...) +history(x...) = history(stdout, x...) history(io::IO, x...) = throw(MethodError(history, (x...,))) history() = history(1:n) """ @@ -256,7 +256,7 @@ The optional `indices` argument is one or more indices or collections of indices indicating a subset input cells to print. The optional `io` argument is for specifying an output stream. The default -is `STDOUT`. +is `stdout`. """ history diff --git a/src/eventloop.jl b/src/eventloop.jl index 7de015e7..6d81b664 100644 --- a/src/eventloop.jl +++ b/src/eventloop.jl @@ -13,7 +13,7 @@ function eventloop(socket) # kernel interruption to interrupt long calculations.) if !isa(e, InterruptException) content = error_content(e, msg="KERNEL EXCEPTION") - map(s -> println(orig_STDERR[], s), content["traceback"]) + map(s -> println(orig_stderr[], s), content["traceback"]) send_ipython(publish[], msg_pub(execute_msg, "error", content)) end finally diff --git a/src/execute_request.jl b/src/execute_request.jl index b72d2f28..c73c3044 100644 --- a/src/execute_request.jl +++ b/src/execute_request.jl @@ -25,27 +25,27 @@ metadata(x) = Dict() # for passing to Jupyter display_data and execute_result messages. function display_dict(x) data = Dict{String,Any}("text/plain" => limitstringmime(text_plain, x)) - if mimewritable(application_vnd_vegalite_v2, x) + if showable(application_vnd_vegalite_v2, x) data[string(application_vnd_vegalite_v2)] = JSON.JSONText(limitstringmime(application_vnd_vegalite_v2, x)) end - if mimewritable(application_vnd_dataresource, x) + if showable(application_vnd_dataresource, x) data[string(application_vnd_dataresource)] = JSON.JSONText(limitstringmime(application_vnd_dataresource, x)) end - if mimewritable(image_svg, x) + if showable(image_svg, x) data[string(image_svg)] = limitstringmime(image_svg, x) end - if mimewritable(image_png, x) + if showable(image_png, x) data[string(image_png)] = limitstringmime(image_png, x) - elseif mimewritable(image_jpeg, x) # don't send jpeg if we have png + elseif showable(image_jpeg, x) # don't send jpeg if we have png data[string(image_jpeg)] = limitstringmime(image_jpeg, x) end - if mimewritable(text_markdown, x) + if showable(text_markdown, x) data[string(text_markdown)] = limitstringmime(text_markdown, x) - elseif mimewritable(text_html, x) + elseif showable(text_html, x) data[string(text_html)] = limitstringmime(text_html, x) - elseif mimewritable(text_latex, x) + elseif showable(text_latex, x) data[string(text_latex)] = limitstringmime(text_latex, x) - elseif mimewritable(text_latex2, x) + elseif showable(text_latex2, x) data[string(text_latex)] = limitstringmime(text_latex2, x) end return data @@ -56,7 +56,7 @@ const displayqueue = Any[] # remove x from the display queue function undisplay(x) - i = findfirst(equalto(x), displayqueue) + i = findfirst(isequal(x), displayqueue) if i !== nothing && i > 0 splice!(displayqueue, i) end @@ -113,6 +113,8 @@ end # use a global array to accumulate "payloads" for the execute_reply message const execute_payloads = Dict[] +const stdout_name = isdefined(Base, :stdout) ? "stdout" : "STDOUT" + function execute_request(socket, msg) code = msg.content["code"] @vprintln("EXECUTING ", code) @@ -139,7 +141,7 @@ function execute_request(socket, msg) # "; ..." cells are interpreted as shell commands for run code = replace(code, r"^\s*;.*$" => m -> string(replace(m, r"^\s*;", "Base.repl_cmd(`"), - "`, STDOUT)")) + "`, ", stdout_name, ")")) # a cell beginning with "? ..." is interpreted as a help request hcode = replace(code, r"^\s*\?" => "") @@ -151,10 +153,10 @@ function execute_request(socket, msg) if hcode != code # help request - eval(Main, helpmode(hcode)) + Core.eval(Main, helpmode(hcode)) else #run the code! - ans = result = contains(code, magics_regex) ? magics_help(code) : + ans = result = occursin(magics_regex, code) ? magics_help(code) : include_string(current_module[], code, "In[$n]") end diff --git a/src/handlers.jl b/src/handlers.jl index 0ec91b12..443ef292 100644 --- a/src/handlers.jl +++ b/src/handlers.jl @@ -109,7 +109,7 @@ function complete_types(comps) expr = Meta.parse(c, raise=false) if typeof(expr) == Symbol try - ctype = complete_type(eval(current_module[], :(typeof($expr)))) + ctype = complete_type(Core.eval(current_module[], :(typeof($expr)))) end elseif !isa(expr, Expr) ctype = complete_type(expr) @@ -200,7 +200,7 @@ function shutdown_request(socket, msg) exit() end -docdict(s::AbstractString) = display_dict(eval(Main, helpmode(DevNull, s))) +docdict(s::AbstractString) = display_dict(Core.eval(Main, helpmode(devnull, s))) import Base: is_id_char, is_id_start_char function get_token(code, pos) diff --git a/src/heartbeat.jl b/src/heartbeat.jl index c6b07c6a..08838cc6 100644 --- a/src/heartbeat.jl +++ b/src/heartbeat.jl @@ -6,16 +6,17 @@ const threadid = zeros(Int, 128) # sizeof(uv_thread_t) <= 8 on Linux, OSX, Win +using ZMQ: libzmq # entry point for new thread function heartbeat_thread(sock::Ptr{Cvoid}) - ccall((:zmq_proxy,ZMQ.libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), + ccall((:zmq_proxy,libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), sock, sock, C_NULL) nothing end function start_heartbeat(sock) - heartbeat_c = cfunction(heartbeat_thread, Cvoid, Tuple{Ptr{Cvoid}}) + heartbeat_c = @cfunction(heartbeat_thread, Cvoid, (Ptr{Cvoid},)) ccall(:uv_thread_create, Cint, (Ptr{Int}, Ptr{Cvoid}, Ptr{Cvoid}), threadid, heartbeat_c, sock.data) end diff --git a/src/hmac.jl b/src/hmac.jl index 8e49a6ff..c6fe856c 100644 --- a/src/hmac.jl +++ b/src/hmac.jl @@ -11,7 +11,7 @@ function hmac(s1,s2,s3,s4) end # Take the digest (returned as a byte array) and convert it to hex string representation digest = MbedTLS.finish!(hmacstate[]) - hexdigest = Vector{UInt8}(uninitialized, length(digest)*2) + hexdigest = Vector{UInt8}(undef, length(digest)*2) for i = 1:length(digest) b = digest[i] d = b >> 4 diff --git a/src/init.jl b/src/init.jl index 119f32e4..850bf950 100644 --- a/src/init.jl +++ b/src/init.jl @@ -13,14 +13,14 @@ else uuid4() = repr(UUIDs.uuid4(IJulia_RNG)) end -const orig_STDIN = Ref{IO}() -const orig_STDOUT = Ref{IO}() -const orig_STDERR = Ref{IO}() +const orig_stdin = Ref{IO}() +const orig_stdout = Ref{IO}() +const orig_stderr = Ref{IO}() function __init__() Random.srand(IJulia_RNG) - orig_STDIN[] = STDIN - orig_STDOUT[] = STDOUT - orig_STDERR[] = STDERR + orig_stdin[] = stdin + orig_stdout[] = stdout + orig_stderr[] = stderr end # the following constants need to be initialized in init(). @@ -103,13 +103,13 @@ function init(args) start_heartbeat(heartbeat[]) if capture_stdout read_stdout[], = redirect_stdout() - redirect_stdout(IJuliaStdio(STDOUT,"stdout")) + redirect_stdout(IJuliaStdio(stdout,"stdout")) end if capture_stderr read_stderr[], = redirect_stderr() - redirect_stderr(IJuliaStdio(STDERR,"stderr")) + redirect_stderr(IJuliaStdio(stderr,"stderr")) end - redirect_stdin(IJuliaStdio(STDIN,"stdin")) + redirect_stdin(IJuliaStdio(stdin,"stdin")) send_status("starting") global inited = true diff --git a/src/kernel.jl b/src/kernel.jl index e0be292b..181b5b09 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -19,13 +19,13 @@ ccall(:jl_exit_on_sigint, IJulia.Compat.Cvoid, (Cint,), 0) ENV["LINES"] = get(ENV, "LINES", 30) ENV["COLUMNS"] = get(ENV, "COLUMNS", 80) -println(IJulia.orig_STDOUT[], "Starting kernel event loops.") +println(IJulia.orig_stdout[], "Starting kernel event loops.") IJulia.watch_stdio() # workaround JuliaLang/julia#4259 delete!(task_local_storage(),:SOURCE_PATH) # workaround JuliaLang/julia#6765 -eval(Base, :(is_interactive = true)) +Core.eval(Base, :(is_interactive = true)) IJulia.waitloop() diff --git a/src/magics.jl b/src/magics.jl index b9bc2821..60882e2b 100644 --- a/src/magics.jl +++ b/src/magics.jl @@ -59,7 +59,7 @@ alias_magic_help(magic::AbstractString, args::AbstractString) = md""" which you can then run with e.g. `bracket("hello world")`.""" function cd_magic_help(magic::AbstractString, args::AbstractString) - if magic == "%cd" && !contains(args, r"\s*-") + if magic == "%cd" && !occursin(r"\s*-", args) return md"""The equivalent of `%cd 'dir'` in IPython is `cd("dir")` in Julia.""" else return md""" @@ -217,7 +217,7 @@ prun_magic_help(magic::AbstractString, args::AbstractString) = md""" psearch_magic_help(magic::AbstractString, args::AbstractString) = md""" A rough analogue of IPython's `%psearch PATTERN` in Julia might be - `filter(s -> contains(string(s), r"PATTERN"), names(Base))`, which + `filter(s -> occursin(r"PATTERN", string(s)), names(Base))`, which searches all the symbols defined in the `Base` module for a given regular-expression pattern `PATTERN`.""" @@ -349,7 +349,7 @@ function pipe_magic_help(magic::AbstractString, args::AbstractString) The analogue of IPython's `$magic ...code...` in Julia can be constructed by first evaluating ``` - macro $(cmd)_str(s) open(`$cmd`,"w",STDOUT) do io; print(io, s); end; end + macro $(cmd)_str(s) open(`$cmd`,"w",stdout) do io; print(io, s); end; end ``` to define the `$cmd"...."` [string macro](http://docs.julialang.org/en/latest/manual/strings/#non-standard-string-literals) in Julia. Subsequently, you can simply do: @@ -358,7 +358,7 @@ function pipe_magic_help(magic::AbstractString, args::AbstractString) ...code... ""\" ``` - to evaluate the code in `$cmd` (outputting to `STDOUT`).""") + to evaluate the code in `$cmd` (outputting to `stdout`).""") end svg_magic_help(magic::AbstractString, args::AbstractString) = md""" diff --git a/src/stdio.jl b/src/stdio.jl index 6d498390..3a09adce 100644 --- a/src/stdio.jl +++ b/src/stdio.jl @@ -1,4 +1,4 @@ -# IJulia redirects STDOUT and STDERR into "stream" messages sent to the +# IJulia redirects stdout and stderr into "stream" messages sent to the # Jupyter front-end. # create a wrapper type around redirected stdio streams, @@ -30,7 +30,7 @@ for s in ("stdout", "stderr", "stdin") S = QuoteNode(Symbol(uppercase(s))) @eval function Base.$f(io::IJuliaStdio) io[:jupyter_stream] != $s && throw(ArgumentError(string("expecting ", $s, " stream"))) - eval(Base, Expr(:(=), $S, io)) + Core.eval(Base, Expr(:(=), $S, io)) return io end end @@ -49,7 +49,7 @@ end macro vprintln(x...) quote if verbose::Bool - println(orig_STDOUT[], get_log_preface(), $(map(esc, x)...)) + println(orig_stdout[], get_log_preface(), $(map(esc, x)...)) end end end @@ -57,7 +57,7 @@ end macro verror_show(e, bt) quote if verbose::Bool - showerror(orig_STDERR[], $(esc(e)), $(esc(bt))) + showerror(orig_stderr[], $(esc(e)), $(esc(bt))) end end end @@ -216,7 +216,7 @@ end import Base.readline function readline(io::IJuliaStdio) if get(io,:jupyter_stream,"unknown") == "stdin" - return readprompt("STDIN> ") + return readprompt("stdin> ") else readline(io.io) end @@ -232,7 +232,7 @@ function watch_stdio() task_local_storage(:IJulia_task, "init task") if capture_stdout read_task = @async watch_stream(read_stdout[], "stdout") - #send STDOUT stream msgs every stream_interval secs (if there is output to send) + #send stdout stream msgs every stream_interval secs (if there is output to send) _Timer(send_stdout, stream_interval, stream_interval) end if capture_stderr @@ -244,8 +244,8 @@ end function flush_all() flush_cstdio() # flush writes to stdout/stderr by external C code - flush(STDOUT) - flush(STDERR) + flush(stdout) + flush(stderr) end function oslibuv_flush() From b25a9609c5bd929981b83134defd84268311b3b2 Mon Sep 17 00:00:00 2001 From: Liam Jongsu Kim Date: Sat, 9 Jun 2018 00:44:52 +0900 Subject: [PATCH 08/19] fix more 0.7 deprecations --- src/IJulia.jl | 11 ++--------- src/execute_request.jl | 24 ++++++++++++++++++++++-- src/handlers.jl | 1 - src/stdio.jl | 7 +++++-- test/execute_request.jl | 2 +- test/stdio.jl | 6 +++--- 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/IJulia.jl b/src/IJulia.jl index d9b4fe1a..8b0d3cec 100644 --- a/src/IJulia.jl +++ b/src/IJulia.jl @@ -41,15 +41,8 @@ using Compat.Unicode: uppercase, lowercase import Compat.Dates using Compat.Dates: now import Compat.Random - -if VERSION ≥ v"0.7.0-DEV.2338" # julia#24361 - using Base64: Base64EncodePipe -end -if isdefined(Base, :REPL) && !Base.isdeprecated(Base, :REPL) - import Base.REPL -else - import REPL -end +using Compat.Base64: Base64EncodePipe +using Compat.REPL ####################################################################### # Debugging IJulia diff --git a/src/execute_request.jl b/src/execute_request.jl index c73c3044..30346cbd 100644 --- a/src/execute_request.jl +++ b/src/execute_request.jl @@ -63,9 +63,15 @@ function undisplay(x) return x end +if VERSION < v"0.7.0-DEV.3498" # julia #25544 + import Base.REPL: ip_matches_func +else + import Base: ip_matches_func +end + function show_bt(io::IO, top_func::Symbol, t, set) # follow PR #17570 code in removing top_func from backtrace - eval_ind = findlast(addr->REPL.ip_matches_func(addr, top_func), t) + eval_ind = findlast(addr->ip_matches_func(addr, top_func), t) eval_ind !== nothing && eval_ind != 0 && (t = t[1:eval_ind-1]) Base.show_backtrace(io, t) end @@ -74,12 +80,26 @@ end # doesn't support keyword arguments. showerror_nobt(io, e, bt) = showerror(io, e, bt, backtrace=false) +@static if VERSION < v"0.7.0-DEV.4724" + # https://github.com/JuliaLang/Compat.jl/pull/572 + # thanks to https://github.com/jipolanco/WriteVTK.jl/commit/ea046493c7787ae651b5f629455aaf7bdaa000b1 + rsplit(s::AbstractString; limit::Integer=0, keepempty::Bool=false) = + Base.rsplit(s) + rsplit(s::AbstractString, splitter; limit::Integer=0, keepempty::Bool=false) = + Base.rsplit(s, splitter; limit=limit, keep=keepempty) + split(s::AbstractString; limit::Integer=0, keepempty::Bool=false) = + Base.split(s) + split(s::AbstractString, splitter; limit::Integer=0, keepempty::Bool=false) = + Base.split(s, splitter; limit=limit, keep=keepempty) +end + # return the content of a pyerr message for exception e function error_content(e, bt=catch_backtrace(); backtrace_top::Symbol=:include_string, msg::AbstractString="") tb = map(x->String(x), split(sprint(show_bt, backtrace_top, bt, 1:typemax(Int)), - "\n", keep=true)) + "\n", keepempty=true)) + ename = string(typeof(e)) evalue = try # Peel away one LoadError layer that comes from running include_string on the cell diff --git a/src/handlers.jl b/src/handlers.jl index 443ef292..402d7875 100644 --- a/src/handlers.jl +++ b/src/handlers.jl @@ -52,7 +52,6 @@ Base.ind2chr(m::Msg, str::String, i::Integer) = i == 0 ? 0 : #Compact display of types for Jupyterlab completion if VERSION ≥ v"0.7.0-DEV.3500" #25544 - import REPL import REPL.REPLCompletions: sorted_keywords, emoji_symbols, latex_symbols elseif isdefined(Main, :REPLCompletions) import REPLCompletions: sorted_keywords, emoji_symbols, latex_symbols diff --git a/src/stdio.jl b/src/stdio.jl index 3a09adce..e2eec9b1 100644 --- a/src/stdio.jl +++ b/src/stdio.jl @@ -27,7 +27,11 @@ Base.setup_stdio(io::IJuliaStdio, readable::Bool) = Base.setup_stdio(io.io.io, r for s in ("stdout", "stderr", "stdin") f = Symbol("redirect_", s) - S = QuoteNode(Symbol(uppercase(s))) + if VERSION >= v"0.7.0-DEV.4068" # Julia PR #25959 + S = QuoteNode(Symbol(lowercase(s))) + else + S = QuoteNode(Symbol(uppercase(s))) + end @eval function Base.$f(io::IJuliaStdio) io[:jupyter_stream] != $s && throw(ArgumentError(string("expecting ", $s, " stream"))) Core.eval(Base, Expr(:(=), $S, io)) @@ -45,7 +49,6 @@ function get_log_preface() @sprintf("%02d:%02d:%02d(%s): ", Dates.hour(t),Dates.minute(t),Dates.second(t),taskname) end - macro vprintln(x...) quote if verbose::Bool diff --git a/test/execute_request.jl b/test/execute_request.jl index 20497500..d5b893db 100644 --- a/test/execute_request.jl +++ b/test/execute_request.jl @@ -1,6 +1,6 @@ using Compat.Test -import IJulia: helpcode, error_content, docdict +import IJulia: helpmode, error_content, docdict content = error_content(UndefVarError(:a)) @test "UndefVarError" == content["ename"] diff --git a/test/stdio.jl b/test/stdio.jl index 230a1f5d..493e5b8a 100644 --- a/test/stdio.jl +++ b/test/stdio.jl @@ -1,4 +1,4 @@ -using Base.Test +using Compat.Test using IJulia mktemp() do path, io @@ -7,7 +7,7 @@ mktemp() do path, io end flush(io) seek(io, 0) - @test readstring(io) == "print\n" + @test read(io, String) == "print\n" @test_throws ArgumentError redirect_stdout(IJulia.IJuliaStdio(io, "stderr")) @test_throws ArgumentError redirect_stdout(IJulia.IJuliaStdio(io, "stdin")) @test_throws ArgumentError redirect_stderr(IJulia.IJuliaStdio(io, "stdout")) @@ -22,7 +22,7 @@ mktemp() do path, io end flush(io) seek(io, 0) - captured = readstring(io) + captured = read(io, String) @test (captured == "\e[1m\e[33mWARNING: \e[39m\e[22m\e[33mwarn\e[39m\n" || captured == "WARNING: warn\n") # output will differ based on whether color is currently enabled end From a82da39ace90c7401b3469523ec9fb0be7177178 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Mon, 11 Jun 2018 15:55:47 -0400 Subject: [PATCH 09/19] don't use uppercase STDIO on 0.7 --- src/stdio.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdio.jl b/src/stdio.jl index 3a09adce..c0639e24 100644 --- a/src/stdio.jl +++ b/src/stdio.jl @@ -27,7 +27,7 @@ Base.setup_stdio(io::IJuliaStdio, readable::Bool) = Base.setup_stdio(io.io.io, r for s in ("stdout", "stderr", "stdin") f = Symbol("redirect_", s) - S = QuoteNode(Symbol(uppercase(s))) + S = QuoteNode(Symbol(isdefined(Base, :stdout) ? s : uppercase(s))) @eval function Base.$f(io::IJuliaStdio) io[:jupyter_stream] != $s && throw(ArgumentError(string("expecting ", $s, " stream"))) Core.eval(Base, Expr(:(=), $S, io)) From 46ea1b5c965a9ef6a69a0058cb78b99659f0f9e8 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Mon, 11 Jun 2018 15:59:10 -0400 Subject: [PATCH 10/19] whitespace --- src/execute_request.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/execute_request.jl b/src/execute_request.jl index 30346cbd..2922c001 100644 --- a/src/execute_request.jl +++ b/src/execute_request.jl @@ -64,9 +64,9 @@ function undisplay(x) end if VERSION < v"0.7.0-DEV.3498" # julia #25544 - import Base.REPL: ip_matches_func + import Base.REPL: ip_matches_func else - import Base: ip_matches_func + import Base: ip_matches_func end function show_bt(io::IO, top_func::Symbol, t, set) From 0338528461ef51d9ffbcaa867b283eb9b0e16621 Mon Sep 17 00:00:00 2001 From: "staticfloat@gmail.com" Date: Mon, 18 Jun 2018 20:33:29 -0700 Subject: [PATCH 11/19] Add logging override for 0.7 --- src/stdio.jl | 19 +++++++++++++++++-- test/stdio.jl | 10 +++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/stdio.jl b/src/stdio.jl index c515c01b..0bd7c0ca 100644 --- a/src/stdio.jl +++ b/src/stdio.jl @@ -27,10 +27,25 @@ Base.setup_stdio(io::IJuliaStdio, readable::Bool) = Base.setup_stdio(io.io.io, r for s in ("stdout", "stderr", "stdin") f = Symbol("redirect_", s) - S = QuoteNode(Symbol(isdefined(Base, :stdout) ? s : uppercase(s))) + Sq = QuoteNode(Symbol(uppercase(s))) + sq = QuoteNode(Symbol(s)) @eval function Base.$f(io::IJuliaStdio) io[:jupyter_stream] != $s && throw(ArgumentError(string("expecting ", $s, " stream"))) - Core.eval(Base, Expr(:(=), $S, io)) + if isdefined(Base, :stdout) + # On Julia 0.7, we need to override the global logger as well + logger = Base.CoreLogging._global_logstate.logger + + # Override logging if it's pointing at the default stderr + if logger.stream == Base.stderr + new_logstate = Base.CoreLogging.LogState(typeof(logger)(io, logger.min_level)) + Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), new_logstate)) + end + + Core.eval(Base, Expr(:(=), $sq, io)) + else + # On Julia 0.6-, the variables are called Base.STDIO, not Base.stdio + Core.eval(Base, Expr(:(=), $Sq, io)) + end return io end end diff --git a/test/stdio.jl b/test/stdio.jl index 493e5b8a..12b13c88 100644 --- a/test/stdio.jl +++ b/test/stdio.jl @@ -16,15 +16,19 @@ mktemp() do path, io @test_throws ArgumentError redirect_stdin(IJulia.IJuliaStdio(io, "stderr")) end +# Helper function to strip out color codes from strings to make it easier to +# compare output within tests that has been colorized +function strip_colorization(s) + return replace(s, r"(\e\[\d+m)"m => "") +end + mktemp() do path, io redirect_stderr(IJulia.IJuliaStdio(io, "stderr")) do warn("warn") end flush(io) seek(io, 0) - captured = read(io, String) - @test (captured == "\e[1m\e[33mWARNING: \e[39m\e[22m\e[33mwarn\e[39m\n" || - captured == "WARNING: warn\n") # output will differ based on whether color is currently enabled + @test strip_colorization(read(io, String)) == "WARNING: warn\n" end mktemp() do path, io From 23e5178507613efa721fb0b5e8317a648754679c Mon Sep 17 00:00:00 2001 From: "staticfloat@gmail.com" Date: Mon, 18 Jun 2018 22:13:18 -0700 Subject: [PATCH 12/19] Fix stdout messages not being sent Julia 0.7 changed the `String()` constructor to deplete `Vector{UInt8}` arguments, so we must `copy()` them first to avoid clobbering. --- src/stdio.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdio.jl b/src/stdio.jl index 0bd7c0ca..5c255c78 100644 --- a/src/stdio.jl +++ b/src/stdio.jl @@ -160,7 +160,7 @@ function send_stream(name::AbstractString) n = num_utf8_trailing(d) dextra = d[end-(n-1):end] resize!(d, length(d) - n) - s = String(d) + s = String(copy(d)) if isvalid(String, s) write(buf, dextra) # assume that the rest of the string will be written later length(d) == 0 && return From cbe06f3ab07be0fc5b2b8c98e655725fee6f2b81 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 5 Jul 2018 08:58:15 +0200 Subject: [PATCH 13/19] fix empty try-catch deprecation add build.log to .gitignore --- .gitignore | 1 + src/handlers.jl | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 7a15e06b..6dd25b8f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.un~ /build/ /deps/deps.jl +/deps/build.log /deps/JUPYTER /deps/julia-* *.jl.*.cov diff --git a/src/handlers.jl b/src/handlers.jl index 402d7875..ddf5d190 100644 --- a/src/handlers.jl +++ b/src/handlers.jl @@ -109,6 +109,7 @@ function complete_types(comps) if typeof(expr) == Symbol try ctype = complete_type(Core.eval(current_module[], :(typeof($expr)))) + catch end elseif !isa(expr, Expr) ctype = complete_type(expr) From 10ddc7cafe359ebeca70defebefca6a3dfc773db Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 5 Jul 2018 09:46:15 +0200 Subject: [PATCH 14/19] add Conda before using it --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 9db26ad3..5f0c766f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,7 +33,7 @@ install: build_script: - C:\projects\julia\bin\julia -e "versioninfo(true); Pkg.clone(pwd(), \"IJulia\"); - using Conda; + Pkg.add(\"Conda\"); using Conda; try Conda.add(\"qt\") end; postlink = normpath(Pkg.dir(\"Conda\"), \"deps/usr/pkgs/qt-4.8.7-vc9_9/Scripts/.qt-post-link.bat\"); isfile(postlink) && rm(postlink); From 543305e32162538602aa71ec363772d40dae3810 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 5 Jul 2018 18:41:10 +0200 Subject: [PATCH 15/19] fix deprecation from spawn --- src/IJulia.jl | 4 ++-- src/init.jl | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/IJulia.jl b/src/IJulia.jl index 8b0d3cec..99f86651 100644 --- a/src/IJulia.jl +++ b/src/IJulia.jl @@ -113,10 +113,10 @@ function notebook(; dir=homedir(), detached=false) inited && error("IJulia is already running") if Compat.Sys.isapple() # issue #551 workaround, remove after macOS 10.12.6 release? withenv("BROWSER"=>"open") do - p = spawn(Cmd(`$notebook_cmd`, detach=true, dir=dir)) + p = run(Cmd(`$notebook_cmd`, detach=true, dir=dir); wait=false) end else - p = spawn(Cmd(`$notebook_cmd`, detach=true, dir=dir)) + p = run(Cmd(`$notebook_cmd`, detach=true, dir=dir); wait=false) end if !detached try diff --git a/src/init.jl b/src/init.jl index 850bf950..1a5db882 100644 --- a/src/init.jl +++ b/src/init.jl @@ -13,6 +13,11 @@ else uuid4() = repr(UUIDs.uuid4(IJulia_RNG)) end +if VERSION < v"0.7.0-DEV.4445" # julia#26130 + run(args...; wait=nothing) = wait === false ? + Base.spawn(args...) : Base.run(args...) +end + const orig_stdin = Ref{IO}() const orig_stdout = Ref{IO}() const orig_stderr = Ref{IO}() @@ -37,7 +42,7 @@ const socket_locks = Dict{Socket,ReentrantLock}() function qtconsole() if inited - spawn(`$jupyter qtconsole --existing $connection_file`) + run(`$jupyter qtconsole --existing $connection_file`; wait=false) else error("IJulia is not running. qtconsole must be called from an IJulia session.") end From 6e73373da10280418ca8ddbb757910c99b2faa74 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 5 Jul 2018 18:42:27 +0200 Subject: [PATCH 16/19] use Compat.AbstractDisplay directly --- src/inline.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/inline.jl b/src/inline.jl index 85f0d463..95dc7580 100644 --- a/src/inline.jl +++ b/src/inline.jl @@ -1,9 +1,6 @@ import Base: display, redisplay -@static if !isdefined(Base, :AbstractDisplay) # remove when Compat.jl#482 is merged and tagged - const AbstractDisplay = Display -end -struct InlineDisplay <: AbstractDisplay end +struct InlineDisplay <: Compat.AbstractDisplay end # supported MIME types for inline display in IPython, in descending order # of preference (descending "richness") From beb1cf3f139a88e1e08d8572804842f214f17b9e Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 6 Jul 2018 10:59:18 +0200 Subject: [PATCH 17/19] Misc 0.7 changes - warn() -> at-warn - emtpy try-catch - remove_destination -> force - start -> firstindex - endof -> lastindex - broadcast + --- deps/build.jl | 9 +++++---- deps/kspec.jl | 2 +- src/handlers.jl | 22 +++++++++++++--------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/deps/build.jl b/deps/build.jl index 64e32142..c1444afb 100644 --- a/deps/build.jl +++ b/deps/build.jl @@ -21,7 +21,7 @@ function prog_version(prog) try return VersionNumber(v) catch - warn("`$jupyter --version` returned an unrecognized version number $v") + Compat.@warn("`$jupyter --version` returned an unrecognized version number $v") return v"0.0" end end @@ -35,7 +35,7 @@ else jupyter_vers = prog_version(jupyter * "-notebook") end if jupyter_vers === nothing - warn("Could not execute `$jupyter --version`.") + Compat.@warn("Could not execute `$jupyter --version`.") end end isconda = dirname(jupyter) == abspath(Conda.SCRIPTDIR) @@ -64,7 +64,7 @@ if isconda try download(highlighter_url, highlighter) catch e - warn("The following error occurred while attempting to download latest ", + Compat.@warn("The following error occurred while attempting to download latest ", "syntax highlighting definitions:\n\n", e, "\n\nSyntax highlighting may ", "not work as expected.") end @@ -76,9 +76,10 @@ end try juliaprof = chomp(read(pipeline(`$ipython locate profile julia`, stderr=devnull), String)) - warn("""You should now run IJulia just via `$jupyter notebook`, without + Compat.@warn("""You should now run IJulia just via `$jupyter notebook`, without the `--profile julia` flag. IJulia no longer maintains the profile. Consider deleting $juliaprof""") +catch end ####################################################################### diff --git a/deps/kspec.jl b/deps/kspec.jl index dba91229..fc398e67 100644 --- a/deps/kspec.jl +++ b/deps/kspec.jl @@ -1,7 +1,7 @@ ####################################################################### # Install Jupyter kernel-spec file. -copy_config(src, dest) = cp(src, joinpath(dest, basename(src)), remove_destination=true) +copy_config(src, dest) = Compat.cp(src, joinpath(dest, basename(src)), force=true) """ installkernel(name, options...; specname=replace(lowercase(name), " "=>"-") diff --git a/src/handlers.jl b/src/handlers.jl index ddf5d190..7a6559cb 100644 --- a/src/handlers.jl +++ b/src/handlers.jl @@ -9,7 +9,7 @@ using .CommManager # with find_parsestart(c,p) = start(c) once julia#9467 is merged. parseok(s) = !Meta.isexpr(Meta.parse(s, raise=false), :error) function find_parsestart(code, cursorpos) - s = start(code) + s = firstindex(code) while s < cursorpos parseok(code[s:cursorpos]) && return s s = nextind(code, s) @@ -17,7 +17,7 @@ function find_parsestart(code, cursorpos) s = nextind(code, s) end end - return start(code) # failed to find parseable lines + return firstindex(code) # failed to find parseable lines end # As described in jupyter/jupyter_client#259, Jupyter's cursor @@ -27,7 +27,7 @@ end # as 2 code units. function utf16_to_ind(str, ic) i = 0 - e = endof(str) + e = lastindex(str) while ic > 0 && i < e i = nextind(str, i) ic -= UInt32(str[i]) < 0x10000 ? 1 : 2 @@ -36,7 +36,7 @@ function utf16_to_ind(str, ic) end function ind_to_utf16(str, i) ic = 0 - i = min(i, endof(str)) + i = min(i, lastindex(str)) while i > 0 ic += UInt32(str[i]) < 0x10000 ? 1 : 2 i = prevind(str, i) @@ -52,8 +52,10 @@ Base.ind2chr(m::Msg, str::String, i::Integer) = i == 0 ? 0 : #Compact display of types for Jupyterlab completion if VERSION ≥ v"0.7.0-DEV.3500" #25544 + import REPL: REPLCompletions import REPL.REPLCompletions: sorted_keywords, emoji_symbols, latex_symbols elseif isdefined(Main, :REPLCompletions) + import REPLCompletions import REPLCompletions: sorted_keywords, emoji_symbols, latex_symbols else const sorted_keywords = [ @@ -63,6 +65,7 @@ else "let", "local", "macro", "module", "mutable struct", "primitive type", "quote", "return", "struct", "true", "try", "using", "while"] + import Base: REPLCompletions import Base.REPL.REPLCompletions: emoji_symbols, latex_symbols end @@ -137,8 +140,9 @@ function complete_request(socket, msg) end codestart = find_parsestart(code, cursorpos) - comps, positions = Base.REPLCompletions.completions(code[codestart:end], cursorpos-codestart+1) - positions += codestart-1 + comps, positions = REPLCompletions.completions(code[codestart:end], cursorpos-codestart+1) + # positions = positions .+ (codestart - 1) on Julia 0.7 + positions = (first(positions) + codestart - 1):(last(positions) + codestart - 1) metadata = Dict() if isempty(comps) # issue #530: REPLCompletions returns inconsistent results @@ -213,7 +217,7 @@ function get_token(code, pos) # TODO: detect operators? startpos = pos - while startpos > start(code) + while startpos > firstindex(code) if is_id_char(code[startpos]) break else @@ -221,14 +225,14 @@ function get_token(code, pos) end end endpos = startpos - while startpos >= start(code) && (is_id_char(code[startpos]) || code[startpos] == '.') + while startpos >= firstindex(code) && (is_id_char(code[startpos]) || code[startpos] == '.') startpos = prevind(code, startpos) end startpos = startpos < pos ? nextind(code, startpos) : pos if !is_id_start_char(code[startpos]) return "" end - while endpos < endof(code) && is_id_char(code[endpos]) + while endpos < lastindex(code) && is_id_char(code[endpos]) endpos = nextind(code, endpos) end if !is_id_char(code[endpos]) From fd0beb49a3c560a0c657d28cec6a5a09d93fca1c Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 6 Jul 2018 11:00:59 +0200 Subject: [PATCH 18/19] replace global logger in init() --- src/init.jl | 5 +++++ src/stdio.jl | 9 --------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/init.jl b/src/init.jl index 1a5db882..e6120531 100644 --- a/src/init.jl +++ b/src/init.jl @@ -116,6 +116,11 @@ function init(args) end redirect_stdin(IJuliaStdio(stdin,"stdin")) + if isdefined(Base, :CoreLogging) + logger = Base.CoreLogging.SimpleLogger(Base.stderr) + Base.CoreLogging.global_logger(logger) + end + send_status("starting") global inited = true end diff --git a/src/stdio.jl b/src/stdio.jl index 5c255c78..1f162507 100644 --- a/src/stdio.jl +++ b/src/stdio.jl @@ -32,15 +32,6 @@ for s in ("stdout", "stderr", "stdin") @eval function Base.$f(io::IJuliaStdio) io[:jupyter_stream] != $s && throw(ArgumentError(string("expecting ", $s, " stream"))) if isdefined(Base, :stdout) - # On Julia 0.7, we need to override the global logger as well - logger = Base.CoreLogging._global_logstate.logger - - # Override logging if it's pointing at the default stderr - if logger.stream == Base.stderr - new_logstate = Base.CoreLogging.LogState(typeof(logger)(io, logger.min_level)) - Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), new_logstate)) - end - Core.eval(Base, Expr(:(=), $sq, io)) else # On Julia 0.6-, the variables are called Base.STDIO, not Base.stdio From 0d07dbd157d79b51fc48644f6ccc03493a836d26 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 6 Jul 2018 11:20:03 +0200 Subject: [PATCH 19/19] test explicit stdout/stderr printing --- test/stdio.jl | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/test/stdio.jl b/test/stdio.jl index 12b13c88..083f0145 100644 --- a/test/stdio.jl +++ b/test/stdio.jl @@ -1,13 +1,16 @@ using Compat.Test using IJulia +using Compat: occursin mktemp() do path, io redirect_stdout(IJulia.IJuliaStdio(io, "stdout")) do + stdout = isdefined(Base, :devnull) ? Base.stdout : Base.STDOUT + println(stdout, "stdout") println("print") end flush(io) seek(io, 0) - @test read(io, String) == "print\n" + @test read(io, String) == "stdout\nprint\n" @test_throws ArgumentError redirect_stdout(IJulia.IJuliaStdio(io, "stderr")) @test_throws ArgumentError redirect_stdout(IJulia.IJuliaStdio(io, "stdin")) @test_throws ArgumentError redirect_stderr(IJulia.IJuliaStdio(io, "stdout")) @@ -16,25 +19,20 @@ mktemp() do path, io @test_throws ArgumentError redirect_stdin(IJulia.IJuliaStdio(io, "stderr")) end -# Helper function to strip out color codes from strings to make it easier to -# compare output within tests that has been colorized -function strip_colorization(s) - return replace(s, r"(\e\[\d+m)"m => "") -end - mktemp() do path, io redirect_stderr(IJulia.IJuliaStdio(io, "stderr")) do - warn("warn") + stderr = isdefined(Base, :devnull) ? Base.stderr : Base.STDERR + println(stderr, "stderr") end flush(io) seek(io, 0) - @test strip_colorization(read(io, String)) == "WARNING: warn\n" + @test read(io, String) == "stderr\n" end mktemp() do path, io redirect_stdin(IJulia.IJuliaStdio(io, "stdin")) do # We can't actually do anything here because `IJuliaexecute_msg` has not - # yet been initialized, so we just make sure that redirect_stdin does + # yet been initialized, so we just make sure that redirect_stdin does # not error. end end