Debugging Julia

After two and half months of intense collaborative development, we (@kristoffer.carlsson, @pfitzseb, and myself, based on original work by @Keno) are pleased to announce a fully-featured debugging stack for Julia. You can read details in a new blog post:


How does one run @interpret MyPackageTests for a package that follows the usual separation of src and test directories?

1 Like

Currently it’s a bit more involved than @interpret, unfortunately. Check out the test/utils.jl file and try something like

run_test_by_eval("name of tests", filename, 10^6)

where filename is the absolute path to your test file. 10^6 controls the maximum number of statements the interpreter will run before giving up and switching to compiled code.

Congratulations and great work by all involved!
This has been epic to watch come together,
and the side-effects bring wide ranging improvements to the ecosystem.
(E.g. Revise.jl v2.0)


Awesome stuff. But how do you set a break point?

Am I doing something wrong with JuliaInterpreter, or is broadcasting just not implemented yet?

In [14]: x = rand(1:500, 16000);

In [15]: @interpret x .* x
UndefVarError: .* not defined

 [1] top-level scope at /home/adam/.julia/packages/JuliaInterpreter/62ZyY/src/construct.jl:638
 [2] execute_request(::ZMQ.Socket, ::IJulia.Msg) at /home/adam/.julia/packages/IJulia/4UizY/src/execute_request.jl:67
 [3] #invokelatest#1 at ./essentials.jl:742 [inlined]
 [4] invokelatest at ./essentials.jl:741 [inlined]
 [5] eventloop(::ZMQ.Socket) at /home/adam/.julia/packages/IJulia/4UizY/src/eventloop.jl:8
 [6] (::getfield(IJulia, Symbol("##15#18")))() at ./task.jl:259

In any case, all of this is very exciting. Kudos to everyone involved.

Nicely done all.


That’s just a case of Julia itself behaving poorly — and same problem as @which x .* x. Instead try @interpret broadcast(*, x, x) or f(x) = x .* x; @interpret f(x).


Ah. Makes sense. I still haven’t entirely wrapped my head around how arguments to macros work. Thanks!

1 Like

All three packages support the methods in JuliaInterpreter, which is what’s documented in Debugger’s README as linked by Stefan. Moreover,

  • in Juno you can just click in the leftmost column (you have to have fully-updated atom packages ink and julia-client)
  • in Rebugger you can just hit b or c when you come to a line that you want to set a breakpoint at

Very Nice! Thanks a lot for this.

How well does this handle things as @async while true .... end things? Last time I checked it didn’t really. (mainly interested in breakpoint on error stuff)

  1. This is awesome, thanks to all involved!!
  2. You might want to change the README’s Usage section to mention that one has to use Juno.@enter when running in Juno (this confused me until I read the blog post).

It can’t work through tasks, at least not yet. Works fine without the @async, though. In Rebugger:

julia> using Rebugger

julia> function foo()
           while true
foo (generic function with 1 method)

julia> foo()
ERROR: oops
 [1] error(::String) at ./error.jl:33
 [2] foo() at ./REPL[2]:3
 [3] top-level scope at none:0

interpret> foo()   # here I hit Meta-i followed by Enter (to run until breakpoint)
foo() in Main at REPL[2]:2
foo() in Main at REPL[2]:2
 error(s::AbstractString) in Base at error.jl:33
  s = oops
 33  error(s::AbstractString) = begin
 33          throw(ErrorException(s))

1 Like

Ok cool, Yea the main issues with debugging I’ve had recently were related to some rendering package I’m working on that let’s you asyncronous interact with what’s displayed. But I’ll somehow find a way to use these tools with it during development! Thanks again

How to remove breakpoints when using Debugger.jl? It doesn’t seem to reexport remove() or disable() from JuliaInterpreter.

Hi, confess that have been having some difficulties using the debugger (btw, thanks a LOT for this work). Shouldn’t the MethodError be caught (at least this one isn’t)?

julia> using Debugger, JuliaInterpreter

julia> cd("c:/v");using GMT, Webview

julia> break_on(:error)

julia> grdcontour("", R=:d, J=:H14, cont=10, A="50+f7p", G=(params=(dist="4i",),), L=(-1000,-1), W=((contour=1,pen="thinnest,-"), (annot=1, pen="thin,-")), T=(gap=("0.1i","0.02i"),), Vd=1)
ERROR: MethodError: no method matching *(::String, ::Tuple{String,String})
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
  *(::Union{AbstractChar, AbstractString}, ::Union{AbstractChar, AbstractString}...) at strings/basic.jl:229
  *(::AbstractString, ::Missing) at missing.jl:144
 [1] add_opt(::NamedTuple{(:params,),Tuple{NamedTuple{(:dist,),Tuple{String}}}}, ::NamedTuple{(:params,),Tuple{Tuple{String,typeof(GMT.helper_decorated)}}}, ::Nothing) at C:\j\.julia\v0.7\GMT\src\common_options.jl:913
 [2] add_opt(::String, ::Char, ::Dict{Symbol,Any}, ::Array{Symbol,2}, ::NamedTuple{(:params,),Tuple{Tuple{String,typeof(GMT.helper_decorated)}}}, ::Bool, ::Nothing) at C:\j\.julia\v0.7\GMT\src\common_options.jl:869
 [3] add_opt at C:\j\.julia\v0.7\GMT\src\common_options.jl:867 [inlined]
 [4] #grdcontour#80(::Bool, ::Base.Iterators.Pairs{Symbol,Any,NTuple{9,Symbol},NamedTuple{(:R, :J, :cont, :A, :G, :L, :W, :T, :Vd),Tuple{Symbol,Symbol,Int64,String,NamedTuple{(:params,),Tuple{NamedTuple{(:dist,),Tuple{String}}}},Tuple{Int64,Int64},Tuple{NamedTuple{(:contour, :pen),Tuple{Int64,String}},NamedTuple{(:annot, :pen),Tuple{Int64,String}}},NamedTuple{(:gap,),Tuple{Tuple{String,String}}},Int64}}}, ::Function, ::String, ::Array{Any,1}) at C:\j\.julia\v0.7\GMT\src\grdcontour.jl:95
 [5] #grdcontour at .\none:0 [inlined] (repeats 2 times)
 [6] top-level scope at none:0
1 Like

We should reexport them as well. You can use Debugger.JuliaInterpreter.remove for now.


1 Like

You need to actually run the debugger (with @enter). Otherwise you are just executing normal julia.

1 Like

Ghrrr, sure. I did it yesterday but today I must be convinced that I already know how to use it (which I obviously don’t. Have also issues breaking at deep nested methods but that’s probably for another question).