[ANN] Infiltrator.jl v1.0

Hey everyone,

Infiltrator.jl 1.0 is out now! There were a few substantial changes and a bunch of QOL improvements:

  • Added an @exfiltrate macro to export all local variables into a global storage space (or safehouse). This is also available as a command from the infil> REPL.
  • Switched from a debug> prompt to infil> to make it easier to distinguish from Debugger.jl.
  • Assignment/function definitions in the infil> REPL now assign into the safehouse instead of doing nothing. It’s not possible to overwrite local variables though.
  • The safehouse (or Infiltrator.store) can be used to access exfiltrated variables directly via safehouse.yourvariable.
  • Infiltrator.set_store!(Main) (or any other module) allows you to exfiltrate variables directly to that module, but is discouraged because you might end up overwriting global variables.
  • Added a @withstore macro that evaluates its argument with all variables in the safehouse defined so @withstore yourvariable will work appropriately. Note that this is for interactive use only.
  • @stop in the infil> REPL is now called @toggle and, well, toggles the current infiltration point.
  • Added a @continue command to continue to the next infiltration point or stop if there is none (same functionality as exiting the REPL mode with ^D).
  • Added an @exit command to stop the current infiltration session, where a session lasts until the code invoked in the Julia REPL has finished running. This uses the REPL hooks introduced in Julia 1.5, so you’ll need to manually call Infiltrator.end_session!() on previous versions after using @exit.
  • Error stack traces are now truncated properly.
  • @locals outputs much less (typically only one line per local variable).

Check the readme for a usage example.


This is wonderful progress!

I am a long-time user of Exfiltrator.jl, and am pleased that Infiltrator.jl supersedes Exfiltrator.jl’s functionality. To emulate Exfiltrator.@exfiltrate, just do


in the REPL before running your code, and Infiltrator.@exfiltrate will work the same.


Wonderful work!

Seeing new functionalities, maybe I am too greedy, but two questions (possible enhancements?) came immediately to my mind:

  • is there a way to list breakpoints, with their enabled/disabled status?
  • is there a way to re-enable a previously disabled breakpoint other than the one in which the code is currently? (Or, better? toggle any other known breakpoint?)

Again, many thanks and bravos for the wonderful (and I am sure very useful) package !

You can list all disabled infiltration points with getfield(safehouse, :disabled) and pop! them out of that Set. Infiltrator.clear_disabled!() just calls empty! on it.

There’s no list of non-disabled infiltration points anywhere though.

Thanks for your answer!
Do you think there would be an interest to implement the two proposed items above, for use in debugging workflow?

It’s not really feasible to discover which infiltration points exist/may be called by your code beforehand. So while there is interest (at least you asked for it :slight_smile: ) I don’t see a good way to implement that functionality. It would be possible to collect all infiltration points after running your code once, but that seems to be of dubious utility.

Couldn’t you just register a line number node during macroexpansion? E.g.

julia> const locs = LineNumberNode[]

julia> macro foo()
           push!(locs, __source__)
@foo (macro with 1 method)

julia> function f(x)
           x + 1
f (generic function with 1 method)

julia> function bar()
           f(1) * 2
bar (generic function with 1 method)

Now we have

julia> locs
2-element Vector{LineNumberNode}:
 :(#= REPL[5]:2 =#)
 :(#= REPL[6]:2 =#)
1 Like

All great! Any hope for vscode integration in one form or another?

Hah, true. I’ll think about adding that functionality then (not 100% convinced about it being useful though).

No progress on that front.