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
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”.)