Skip to content

Commit b931e66

Browse files
authored
QOL improvements on the what should be attempted to be tagged (#260)
* add function `istaggable` * incorporate `istaggable` into `produce_or_load`. * add docs about it * add tests, up version, cangelog
1 parent 3eec2d5 commit b931e66

File tree

8 files changed

+67
-20
lines changed

8 files changed

+67
-20
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# 2.0.4
2+
* `produce_or_load` now will not attempt to `tagsave` for inappropriate file formats, like `.csv`.
13
# 2.0.3
24
* Added a kwarg `equals` to `savename` to extend applicability.
35
# 2.0

Project.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DrWatson"
22
uuid = "634d3b9d-ee7a-5ddf-bec9-22491ea816e1"
33
repo = "https://github.com/JuliaDynamics/DrWatson.jl.git"
4-
version = "2.0.3"
4+
version = "2.0.4"
55

66
[deps]
77
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
@@ -22,6 +22,7 @@ julia = "1.0"
2222

2323
[extras]
2424
BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0"
25+
CSVFiles = "5d742f6a-9f54-50ce-8119-2520741973ca"
2526
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
2627
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
2728
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
@@ -31,4 +32,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
3132
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3233

3334
[targets]
34-
test = ["Test", "BSON", "FileIO", "Parameters", "DataFrames", "JLD2", "Statistics", "Dates"]
35+
test = [
36+
"Test", "BSON", "FileIO", "Parameters", "DataFrames",
37+
"JLD2", "Statistics", "Dates", "CSVFiles"
38+
]

docs/src/save.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ In addition, it attempts to minimize computing energy spent on getting a result.
5656

5757
```@docs
5858
produce_or_load
59+
istaggable
5960
```
60-
See [Stopping "Did I run this?"](@ref) for an example usage of `produce_or_load`.
61+
62+
See [Stopping "Did I run this?"](@ref) for an example usage of `produce_or_load`. While `produce_or_load` will try to by default tag your data if possible, you can also use it with other formats. An example is when your simulation function `f` returns a `DataFrame` and the file suffix is `"csv"`. In this case tagging will not happen, but `produce_or_load` will work as expected.
63+
6164

6265
## Converting a struct to a dictionary
6366
[`savename`](@ref) gives great support for getting a name out of any Julia composite type. To save something though, one needs a dictionary. So the following function can be conveniently used to directly save a struct using any saving function:

src/DrWatson.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ _wsave(filename, data...; kwargs...) = FileIO.save(filename, data...; kwargs...)
2727
wsave(filename, data...; kwargs...)
2828
2929
Save `data` at `filename` by first creating the appropriate paths.
30-
Default fallback is `FileIO.save`. Extend `wsave` for your type
31-
by extending `DrWatson._wsave(filename, data...; kwargs...)`.
30+
Default fallback is `FileIO.save`. Extend this for your types
31+
by extending `DrWatson._wsave(filename, data::YourType...; kwargs...)`.
3232
"""
3333
function wsave(filename, data...; kwargs...)
3434
mkpath(dirname(filename))

src/saving_files.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@ that produces your data. Then save `file` as `s` and then return `file, s`.
1111
The function `f` must return a dictionary,
1212
the macros [`@dict`](@ref) and [`@strdict`](@ref) can help with that.
1313
14-
You can use [do-block](https://docs.julialang.org/en/v1/manual/functions/#Do-Block-Syntax-for-Function-Arguments) instead of defining a function to pass in. For example,
14+
You can use [do-block]
15+
(https://docs.julialang.org/en/v1/manual/functions/#Do-Block-Syntax-for-Function-Arguments)
16+
instead of defining a function to pass in. For example,
1517
```julia
1618
produce_or_load([path="",] c) do c
1719
# simulation wiht config `c` runs here
1820
end
1921
```
2022
2123
## Keywords
22-
* `tag = true` : Save the file using [`tagsave`](@ref).
24+
* `suffix = "jld2", prefix = default_prefix(c)` : Used in [`savename`](@ref).
25+
* `tag::Bool = istaggable(suffix)` : Save the file using [`tagsave`](@ref) if `true`.
2326
* `gitpath, storepatch` : Given to [`tagsave`](@ref) if `tag` is `true`.
24-
* `suffix = "jld2", prefix = default_prefix(c)` : Used in `savename`.
2527
* `force = false` : If `true` then don't check if file `s` exists and produce
2628
it and save it anyway.
2729
* `loadfile = true` : If `false`, this function does not actually load the
@@ -30,15 +32,13 @@ end
3032
exist it is still produced and saved.
3133
* `verbose = true` : print info about the process, if the file doesn't exist.
3234
* `kwargs...` : All other keywords are propagated to `savename`.
33-
34-
See also [`savename`](@ref).
3535
"""
3636
produce_or_load(c, f; kwargs...) = produce_or_load("", c, f; kwargs...)
3737
produce_or_load(f::Function, c; kwargs...) = produce_or_load(c, f; kwargs...)
3838
produce_or_load(f::Function, path, c; kwargs...) = produce_or_load(path, c, f; kwargs...)
3939
function produce_or_load(path, c, f::Function;
40-
tag::Bool = true, gitpath = projectdir(), loadfile = true,
4140
suffix = "jld2", prefix = default_prefix(c),
41+
tag::Bool = istaggable(suffix), gitpath = projectdir(), loadfile = true,
4242
force = false, verbose = true, storepatch = true, kwargs...)
4343

4444
s = joinpath(path, savename(prefix, c, suffix; kwargs...))

src/saving_tools.jl

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
export gitdescribe, current_commit, tag!, @tag!
22
export dict_list, dict_list_count
3+
export struct2dict, struct2ntuple
4+
export istaggable
35

6+
########################################################################################
7+
# Obtaining Git information
8+
########################################################################################
49
"""
510
gitdescribe(gitpath = projectdir()) -> gitstr
611
@@ -134,12 +139,11 @@ function gitpatch(path = projectdir(); try_submodule_diff=true)
134139
end
135140
end
136141
return nothing
137-
# tree = LibGit2.GitTree(repo, "HEAD^{tree}")
138-
# diff = LibGit2.diff_tree(repo, tree)
139-
# now there is no way to generate the patch with LibGit2.jl.
140-
# Instead use commands:
141142
end
142143

144+
########################################################################################
145+
# Tagging
146+
########################################################################################
143147
"""
144148
tag!(d::Dict; gitpath = projectdir(), storepatch = true, force = false) -> d
145149
Tag `d` by adding an extra field `gitcommit` which will have as value
@@ -201,7 +205,7 @@ function tag!(d::Dict{K,T}; gitpath = projectdir(), storepatch = true, force = f
201205
d[patchname] = patch
202206
end
203207
end
204-
if source != nothing && !force
208+
if source !== nothing && !force
205209
if haskey(d, scriptname)
206210
@warn "The dictionary already has a key named `script`. We won't "*
207211
"overwrite it with the script name."
@@ -249,7 +253,23 @@ macro tag!(d,args...)
249253
return :(tag!($(esc(d)),$(esc.(convert_to_kw.(args))...),source=$s))
250254
end
251255

252-
export struct2dict
256+
########################################################################################
257+
# Tagging Utilities
258+
########################################################################################
259+
const TAGGABLE_FILE_ENDINGS = ("bson", "jld", "jld2")
260+
"""
261+
istaggable(file::AbstractStrig) → bool
262+
Return `true` if the file save format (file ending) is "taggable", i.e. allows adding
263+
additional data fields as strings. Currently endings that can do this are:
264+
```
265+
$(TAGGABLE_FILE_ENDINGS)
266+
```
267+
268+
istaggable(x) = x isa AbstractDictionary
269+
"""
270+
istaggable(file::AbstractString) = any(endswith(file, e) for e TAGGABLE_FILE_ENDINGS)
271+
istaggable(x) = x isa AbstractDict
272+
253273

254274
"""
255275
struct2dict(s) -> d
@@ -263,8 +283,6 @@ function struct2dict(s)
263283
Dict(x => getfield(s, x) for x in fieldnames(typeof(s)))
264284
end
265285

266-
export struct2ntuple
267-
268286
"""
269287
struct2ntuple(s) -> n
270288
Convert a Julia composite type `s` to a NamedTuple `n`.

test/savefiles_tests.jl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ function f(simulation)
1515
return @strdict a b simulation
1616
end
1717

18-
@testset "Tagsafe ($ending)" for ending ["bson", "jld2"]
1918
################################################################################
2019
# tagsave #
2120
################################################################################
21+
@testset "Tagsafe ($ending)" for ending ["bson", "jld2"]
2222
t = f(simulation)
2323
tagsave(savename(simulation, ending), t, gitpath=findproject())
2424
file = load(savename(simulation, ending))
@@ -113,6 +113,21 @@ end
113113
rm(savename(simulation, "jld2"))
114114
@test !isfile(savename(simulation, "jld2"))
115115

116+
using DataFrames
117+
@testset "produce_or_load with dataframe" begin
118+
function makedf(c)
119+
a = c[:a]
120+
return DataFrame(A = a, B = rand(3))
121+
end
122+
c = (a = 0.5,)
123+
_, spath = produce_or_load(c, makedf; suffix = "csv")
124+
@test isfile(spath)
125+
df = DataFrame(load(spath))
126+
@test df.A == [0.5, 0.5, 0.5]
127+
rm(spath)
128+
@test !isfile(spath)
129+
end
130+
116131
################################################################################
117132
# Backup files before saving #
118133
################################################################################

test/stools_tests.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,8 @@ end
262262
rm(tmpdir, force = true, recursive = true)
263263
@test !isdir(tmpdir)
264264

265+
## is taggable
266+
@test DrWatson.istaggable("test.jld2")
267+
@test !DrWatson.istaggable("test.csv")
268+
@test !DrWatson.istaggable(0.5)
269+
@test DrWatson.istaggable(Dict(:a => 0.5))

0 commit comments

Comments
 (0)