ANN: Exfiltrator

Exfiltrator (https://github.com/antoine-levitt/Exfiltrator.jl) is Infiltrator’s younger sibling. It exfiltrates local variables to the global scope for easier exploration in the REPL. Example from the readme:

using Exfiltrator

julia> function f(x)
           @exfiltrate
       end
f (generic function with 1 method)

julia> f(2)

julia> x
2

There’s also a few variants eg to export variables from multiple calls. Exfiltrator is useful either to debug a program or to export results from deep call stacks (eg for plotting). Feedback welcome!

29 Likes

Could

@testset "foo" begin
    @exfiltrate
    z = 3
end

be made to work?

4 Likes

That one is pretty much impossible, because the declaration of z is after the exfiltrate call so it’s not defined at that point. I thought about supporting @exfiltrate VAR function f()... and @exfiltrate VAR begin... which would exfiltrate all locals at the end of the call. That would take care of your case.

Oh, so I can just put it at the end? That works as well.

1 Like

Sure: it just takes its information from Base.@locals, which gives all the currently defined variables.

8 Likes

Thank you! I like R’s browser() and @infiltrate but sometimes feel constricted by the special REPL. I will definitely use this!

And, remarkably, it’s 37 lines of code.

1 Like

Oh yeah, the thing is completely trivial thanks to the Base.@locals macro, I kind of feel bad for publishing such a stupid thing but it’s useful so… Maybe it could get merged in Infiltrator.jl because it’s similar in purpose, but the name would clash a bit.

Credits go to the people in the slack thread on debugging who said their debugging process is basically exporting variables to the global scope, and to @StefanKarpinski for the idea to just export the variables directly (my previous version exported named tuples only)

11 Likes

This (and Infiltrator) both look pretty useful. Thanks!

I’ve been using it and it’s exactly what I needed. Much easier to write data-cleaning code in functions and know where things go wrong.

This is awesome! It might be only 37 lines of code, but a lot of UI design is trivial but hard to conceive. There is also a knowledge barrier, i.e., I do not know how to implement this macro (I did not know about Base.@locals either), so even though I might have thought of this, because I couldn’t know how much time learning to implement it would take me, I would dismiss the thought.

2 Likes

Is there some trick to using @exfiltrate in package development? I want to be able to put @exfiltrate inside a function in a package, but I don’t necessarily want to add Exfiltrator as a dependency

1 Like

I usually just add using Exfiltrator at the beginning of a file and Revise takes care of it. It’d be great to get rid of the using but I don’t know how

add it to your global enviroment.
then it doesn;t have to be in the project’s dependnecies

Wait, can packages access global dependencies? I thought they were only visible at the REPL.

I would try using Exfiltrator at the REPL, then in the package code use Main.@exfiltrate

1 Like

Good trick, thanks!

Thanks! Actually I had the same question for Infiltrator.jl. This is a very smart trick.

However, the lines with Main.@exfiltrate will still throw an error if you forget to delete them after debugging. I have not yet tested it, but perhaps that could be avoided with:

isdefined(Main, :Exfiltrator) && Main.Exfiltrator.@exfiltrate

(Added Main.Exfiltrator in case the package it is “imported”, instead of “used”.)