Skip to content

Commit

Permalink
Add filename option for produce_or_load (#324)
Browse files Browse the repository at this point in the history
* Add `filename` option to produce_or_load

Closes #322

* Update changelog and version

* Refactoring and docs as discussed in review

* Use "possibly overriding..." in CHANGELOG
* Add discussion of use case to doc of `filename` argument
* Rename output `filename` to `file`, with
  `file = joinpath(path, filename`)
  • Loading branch information
goerz authored Jan 20, 2022
1 parent 4a92f3e commit 04d2d20
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# 2.9.0
* Add `filename` option in `produce_or_load`, possibly overriding the default filename generated by `savename`
# 2.8.0
* Add filtering of `collect_results` using `rinclude` and `rexclude` keyword arguments.
# 2.7.2
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "DrWatson"
uuid = "634d3b9d-ee7a-5ddf-bec9-22491ea816e1"
repo = "https://github.com/JuliaDynamics/DrWatson.jl.git"
version = "2.8.0"
version = "2.9.0"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand Down
48 changes: 27 additions & 21 deletions src/saving_files.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
export produce_or_load, @produce_or_load, tagsave, @tagsave, safesave

"""
produce_or_load([path="",] config, f; kwargs...) -> data, filename
Let `filename = joinpath(path, savename(prefix, config, suffix))` where
`config` is some kind of named parameter container.
If `filename` exists then load it and return the contained `data`, along
with the global path that it is saved at (`filename`).
produce_or_load([path="",] config, f; kwargs...) -> data, file
Let `file = joinpath(path, savename(prefix, config, suffix))` by default,
where `config` is some kind of named parameter container.
If `file` exists then load it and return the contained `data`, along
with the global path that it is saved at (`file`).
If the file does not exist then call `data = f(config)`, with `f` your function
that produces your data. Then save the `data` as `filename` and then return
`data, filename`.
that produces your data. Then save the `data` as `file` and then return
`data, file`.
The function `f` should return a dictionary if the data are saved in the default
format of JLD2.jl., the macro [`@strdict`](@ref) can help with that.
Expand All @@ -24,15 +24,19 @@ end
```
## Keywords
* `filename = savename(prefix, config, suffix; kwargs...)` : Name of the file
to produce or load, relative to `path`. This may be useful in situations
where `config` has too many parameters for [`savename`](@ref) to be useful, and an
explicitly specified name is more suitable.
* `suffix = "jld2", prefix = default_prefix(config)` : Used in [`savename`](@ref).
* `tag::Bool = DrWatson.readenv("DRWATSON_TAG", istaggable(suffix))` : Save the file
using [`tagsave`](@ref) if `true` (which is the default).
* `gitpath, storepatch` : Given to [`tagsave`](@ref) if `tag` is `true`.
* `force = false` : If `true` then don't check if `filename` exists and produce
* `force = false` : If `true` then don't check if `file` exists and produce
it and save it anyway.
* `loadfile = true` : If `false`, this function does not actually load the
file, but only checks if it exists. The return value in this case is always
`nothing, filename`, regardless of whether the file exists or not. If it doesn't
`nothing, file`, regardless of whether the file exists or not. If it doesn't
exist it is still produced and saved.
* `verbose = true` : print info about the process, if the file doesn't exist.
* `wsave_kwargs = Dict()` : Keywords to pass to `wsave` (e.g. to enable
Expand All @@ -48,40 +52,42 @@ function produce_or_load(path, c, f::Function;
gitpath = projectdir(), loadfile = true,
storepatch::Bool = readenv("DRWATSON_STOREPATCH", false),
force = false, verbose = true, wsave_kwargs = Dict(),
filename::Union{Nothing, AbstractString} = nothing,
kwargs...
)

filename = joinpath(path, savename(prefix, c, suffix; kwargs...))
isnothing(filename) && (filename = savename(prefix, c, suffix; kwargs...))
file = joinpath(path, filename)

if !force && isfile(filename)
if !force && isfile(file)
if loadfile
data = wload(filename)
return data, filename
data = wload(file)
return data, file
else
return nothing, filename
return nothing, file
end
else
if force
verbose && @info "Producing file $filename now..."
verbose && @info "Producing file $file now..."
else
verbose && @info "File $filename does not exist. Producing it now..."
verbose && @info "File $file does not exist. Producing it now..."
end
data = f(c)
try
if tag
tagsave(filename, data; safe = false, gitpath = gitpath, storepatch = storepatch, wsave_kwargs...)
tagsave(file, data; safe = false, gitpath = gitpath, storepatch = storepatch, wsave_kwargs...)
else
wsave(filename, copy(data); wsave_kwargs...)
wsave(file, copy(data); wsave_kwargs...)
end
verbose && @info "File $filename saved."
verbose && @info "File $file saved."
catch er
@warn "Could not save file. Error stacktrace:"
Base.showerror(stderr, er, stacktrace(catch_backtrace()))
end
if loadfile
return data, filename
return data, file
else
return nothing, filename
return nothing, file
end
end
end
Expand Down
29 changes: 29 additions & 0 deletions test/savefiles_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,35 @@ end
rm(path)
end

@testset "Produce or Load with manual filename ($ending)" for ending ["bson", "jld2"]

# test with empty `path`
filename = joinpath(mktempdir(), "out.$ending")
@test !isfile(filename)
sim, file = @produce_or_load(simulation, filename=filename) do config
f(config)
end
@test file == filename
@test isfile(filename)
@test sim["simulation"].T == T
@test "script" keys(sim)
rm(filename)

# test with both `path` and filename
path = mktempdir()
filename = joinpath("sub", "out.$ending")
@test !isfile(joinpath(path, filename))
sim, file = @produce_or_load(path, simulation, filename=filename) do config
f(config)
end
@test file == joinpath(path, filename)
@test isfile(file)
@test sim["simulation"].T == T
@test "script" keys(sim)
rm(file)

end

@testset "Produce or Load wsave keyword pass through" begin
# Create some highly compressible data
data = Dict("data" => fill(1, 10000))
Expand Down

0 comments on commit 04d2d20

Please sign in to comment.