Autoreload is a package for autoreloading modules in IJulia. It is intended to allow a workflow where you develop Julia source in some editor, while interacting with it via an IJulia notebook or the command-line REPL. It helps get around annoying type redefinition issues. It is modeled after IPython's autoreload extension.
In a Julia session, type
Pkg.update()
Pkg.clone("Autoreload")
First load the package:
using Autoreload
You can then use the arequire(filename)
where you normally would have used require
or import
. If you then call areload()
, all files included with arequire
will be reloaded if the source files have been modified since their last reload.
You can use smart_reload(filename)
to reload filename
in a way that avoids type redefinition issues. smart_reload
is automatically called by areload
, but you can use it even for files and packages you are not auto-reloading.
A list of files marked for autoreloading can be seen by calling arequire()
. A file can be deleted from the autoreload list by calling arequire(filename, :off)
.
There is basic support for handling dependencies between files which are to be reloaded. For example, if a file M3.jl should be loaded only after loading files M1.jl and M2.jl (for example, if M3 imports M1 and M2), you can write
arequire("M3", depends_on=["M1", "M2"])
M3 will then be auto-reloaded if either M1.jl, M2.jl, or M3.jl is edited, will all three files being reloaded in the correct order. If an autoreloaded file has include
statements, any file it includes will automatically be determined to be a dependency. This makes it convenient to interactively write a package by calling arequire
with the package name and including the rest of the package files with include
statements in the main package source file.
If you are using IJulia (recommended), then areload()
will automatically be called before each cell is executed. This behavioral can be toggled on and off by calling areload(:on)
and areload(:off)
.
In a file called M.jl, I have
x="First version"
In an interactive session, I type
using Autoreload
arequire("M.jl")
x
This will evaluate to "First version".
I then edit M.jl to be
x="Second version"
Then in the same interactive session, I type
areload()
x
and get back "Second version". If I had been using IJulia, the call to areload()
would have been unnecessary.
Say you are creating a package organized on disk as ~/.julia/MyPackage/src/[source files].jl. One of the source files will be called MyPackage.jl and is typically loaded to load the rest of the package. If Autoreload finds a file called src/MyPackage_reload.jl
, however, then when reloading the package, the package will be reloaded via MyPackage_reload.jl
instead of MyPackage.jl. This allows you to only define constants and code in MyPackage.jl, while MyPackage_reload.jl only reloads code. This allows you to specify custom logic for reloading your package. Here is an example
arequire("MyPackage") # ~/.julia/MyPackage/src/MyPackage.jl is loaded
...
# make an edit to some file included in MyPackage.jl
areload() # ~/.julia/MyPackage/src/MyPackage_reload.jl is executed instead of ~/.julia/MyPackage/src/MyPackage.jl
This behavior can be disabled by running aoptions_set(constants=true)
.
Autoreload provides a function called smart_reload
. It has similar semantics to reload
, but avoids some common issues that make reload
inconvenient for interactive development.
If you try to reload a type that is already defined in the global scope (e.g, you are auto-reloading a file that defines a type not wrapped in a module), you would normally get an error about redefining a constant. Autoreload will automatically remove the type declaration before reloading your script it is identical to a type that is already defined, avoiding an error.
If you reload a module that defines types, then those type definitions will be stripped out of the module, and the remaining expressions in the reloaded module will be executed in the context of the old module. That way, variables in the global namespace that has the type of a type defined in the module won't have to be redefined when you reload the module. Here is a clarifying example:
A file called M.jl contains:
module M
type MyType
x::Int
end
f(var::MyType) = print("First version")
end
Then in an interactive session, I have:
using Autoreload
arequire("M")
my_var = M.MyType(5)
M.f(my_var)
this will print "First version". Now I edit M.jl, and replace it with
module M
type MyType
x::Int
end
f(var::MyType) = print("Second version")
end
Then in the interactive section, I write
areload()
M.f(my_var)
This will print "Second version". If you had used Base.reload("M.jl")
instead of reloading via smart_reload
, "First version" would have been printed in first case, but second case would have resulted in an error. If a file is marked for autoreloading (via ```arequire), then whenever that file or any file it includes changes, it will be reloaded with
smart_reload``.
Autoreload.jl uses Julia's built-in reload
command, and as such is subject to various limitations inherent in the current Julia architecture.