Skip to content

Commit 92d2f12

Browse files
Merge pull request #91 from darsnack/darsnack/module-fix
Update to #28
2 parents 7f15a4b + 072d83b commit 92d2f12

File tree

6 files changed

+62
-25
lines changed

6 files changed

+62
-25
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ version = "0.3.1"
66
julia = "0.7, 1"
77

88
[extras]
9+
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
910
Profile = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"
1011
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1112

1213
[targets]
13-
test = ["Test", "Profile"]
14+
test = ["DataFrames", "Test", "Profile"]

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,24 @@ Dict{Symbol,Any} with 4 entries:
6666

6767
This is also how the data will appear to readers in other languages, should you
6868
wish to move data outside of Julia.
69+
70+
## Notes
71+
72+
Below is some semi-official documentation on more advanced usage.
73+
74+
### Loading custom data types within modules
75+
76+
For packages that use BSON.jl to load data, just writing `BSON.load("mydata.bson")` will not work with custom data types. Here's a simple example of that for DataFrames.jl:
77+
```julia
78+
module A
79+
using DataFrames, BSON
80+
d = DataFrame(a = 1:10, b = 5:14)
81+
bson("data.bson", Dict(:d=>d))
82+
d2 = BSON.load("data.bson") # this will throw an error
83+
end
84+
```
85+
In these cases, you can specify the namespace under which to resolve types like so:
86+
```julia
87+
d2 = BSON.load("data.bson", @__MODULE__)
88+
```
89+
This will use the current module's namespace when loading the data. You could also pass any module name as the second argument (though almost all cases will use `@__MODULE__`). By default, the namespace is `Main` (i.e. the REPL).

src/anonymous.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ end
5050

5151
baremodule __deserialized_types__ end
5252

53-
function newstruct_raw(cache, ::Type{TypeName}, d)
54-
name = raise_recursive(d[:data][2], cache)
53+
function newstruct_raw(cache, ::Type{TypeName}, d, init)
54+
name = raise_recursive(d[:data][2], cache, init)
5555
name = isdefined(__deserialized_types__, name) ? gensym() : name
5656
tn = ccall(:jl_new_typename_in, Ref{Core.TypeName}, (Any, Any),
5757
name, __deserialized_types__)
5858
cache[d] = tn
5959
names, super, parameters, types, has_instance,
60-
abstr, mutabl, ninitialized = map(x -> raise_recursive(x, cache), d[:data][3:end-1])
60+
abstr, mutabl, ninitialized = map(x -> raise_recursive(x, cache, init), d[:data][3:end-1])
6161
tn.names = names
6262
ndt = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Any, Cint, Cint, Cint),
6363
tn, tn.module, super, parameters, names, types,
@@ -68,7 +68,7 @@ function newstruct_raw(cache, ::Type{TypeName}, d)
6868
# use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
6969
Core.setfield!(ty, :instance, ccall(:jl_new_struct, Any, (Any, Any...), ty))
7070
end
71-
mt = raise_recursive(d[:data][end], cache)
71+
mt = raise_recursive(d[:data][end], cache, init)
7272
if mt != nothing
7373
mtname, defs, maxa, kwsorter = mt
7474
tn.mt = ccall(:jl_new_method_table, Any, (Any, Any), name, tn.module)

src/extensions.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ tags[:svec] = d -> Core.svec(d[:data]...)
1818

1919
ref(path::Symbol...) = BSONDict(:tag => "ref", :path => Base.string.([path...]))
2020

21-
resolve(fs) = reduce((m, f) -> getfield(m, Symbol(f)), fs; init = Main)
21+
resolve(fs, init) = reduce((m, f) -> getfield(m, Symbol(f)), fs; init = init)
2222

23-
tags[:ref] = d -> resolve(d[:path])
23+
tags[:ref] = (d, init) -> resolve(d[:path], init)
2424

2525
function modpath(x::Module)
2626
y = parentmodule(x)
@@ -51,7 +51,7 @@ normalize_typeparams(x::Union{Int32,Int64}) = Int(x)
5151
constructtype(T, Ts) = (length(Ts) == 0) ? T : T{map(normalize_typeparams, Ts)...}
5252
constructtype(T::Type{Tuple}, Ts) = T{map(normalize_typeparams, Ts)...}
5353

54-
tags[:datatype] = d -> constructtype(resolve(d[:name]), d[:params])
54+
tags[:datatype] = (d, init) -> constructtype(resolve(d[:name], init), d[:params])
5555

5656
lower(v::UnionAll) =
5757
BSONDict(:tag => "unionall",
@@ -120,9 +120,9 @@ function newstruct(T, xs...)
120120
end
121121
end
122122

123-
function newstruct_raw(cache, T, d)
123+
function newstruct_raw(cache, T, d, init)
124124
x = cache[d] = initstruct(T)
125-
fs = map(x -> raise_recursive(x, cache), d[:data])
125+
fs = map(x -> raise_recursive(x, cache, init), d[:data])
126126
return newstruct!(x, fs...)
127127
end
128128

@@ -135,10 +135,10 @@ tags[:struct] = d ->
135135

136136
iscyclic(T) = ismutable(T)
137137

138-
raise[:struct] = function (d, cache)
139-
T = d[:type] = raise_recursive(d[:type], cache)
140-
iscyclic(T) || return _raise_recursive(d, cache)
141-
return newstruct_raw(cache, T, d)
138+
raise[:struct] = function (d, cache, init)
139+
T = d[:type] = raise_recursive(d[:type], cache, init)
140+
iscyclic(T) || return _raise_recursive(d, cache, init)
141+
return newstruct_raw(cache, T, d, init)
142142
end
143143

144144
lower(v::Type{Union{}}) = BSONDict(:tag=>"jl_bottom_type")

src/read.jl

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,34 +74,38 @@ const tags = Dict{Symbol,Function}()
7474

7575
const raise = Dict{Symbol,Function}()
7676

77-
function _raise_recursive(d::AbstractDict, cache)
77+
function _raise_recursive(d::AbstractDict, cache, init)
7878
if haskey(d, :tag) && haskey(tags, Symbol(d[:tag]))
79-
cache[d] = tags[Symbol(d[:tag])](applychildren!(x -> raise_recursive(x, cache), d))
79+
if Symbol(d[:tag]) in (:ref, :datatype)
80+
cache[d] = tags[Symbol(d[:tag])](applychildren!(x -> raise_recursive(x, cache, init), d), init)
81+
else
82+
cache[d] = tags[Symbol(d[:tag])](applychildren!(x -> raise_recursive(x, cache, init), d))
83+
end
8084
else
8185
cache[d] = d
82-
applychildren!(x -> raise_recursive(x, cache), d)
86+
applychildren!(x -> raise_recursive(x, cache, init), d)
8387
end
8488
end
8589

86-
function raise_recursive(d::AbstractDict, cache)
90+
function raise_recursive(d::AbstractDict, cache, init)
8791
haskey(cache, d) && return cache[d]
88-
haskey(d, :tag) && haskey(raise, Symbol(d[:tag])) && return raise[Symbol(d[:tag])](d, cache)
89-
_raise_recursive(d::AbstractDict, cache)
92+
haskey(d, :tag) && haskey(raise, Symbol(d[:tag])) && return raise[Symbol(d[:tag])](d, cache, init)
93+
_raise_recursive(d::AbstractDict, cache, init)
9094
end
9195

92-
function raise_recursive(v::BSONArray, cache)
96+
function raise_recursive(v::BSONArray, cache, init)
9397
cache[v] = v
94-
applychildren!(x -> raise_recursive(x, cache), v)
98+
applychildren!(x -> raise_recursive(x, cache, init), v)
9599
end
96100

97-
raise_recursive(x, cache) = x
101+
raise_recursive(x, cache, init) = x
98102

99-
raise_recursive(x) = raise_recursive(x, IdDict())
103+
raise_recursive(x, init) = raise_recursive(x, IdDict(), init)
100104

101105
parse(io::IO) = backrefs!(parse_doc(io))
102106
parse(path::String) = open(parse, path)
103107

104-
load(x) = raise_recursive(parse(x))
108+
load(x, init=Main) = raise_recursive(parse(x), init)
105109

106110
function roundtrip(x)
107111
buf = IOBuffer()

test/runtests.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ end
2323

2424
struct S end
2525

26+
module A
27+
using DataFrames, BSON
28+
d = DataFrame(a = 1:10, b = rand(10))
29+
bson("test_25_dataframe.bson", Dict(:d=>d))
30+
end
31+
2632
@testset "BSON" begin
2733

2834
@testset "Primitive Types" begin
@@ -99,4 +105,9 @@ end
99105
@test BSON.load(joinpath(@__DIR__, "test_MultiDimsArray_from_64bit.bson"))[:a] == ones(Float32, 2, 2)
100106
end
101107

108+
@testset "Namespace other than Main #25" begin
109+
@test BSON.load("test_25_dataframe.bson", A)[:d] == A.d
110+
rm("test_25_dataframe.bson")
111+
end
112+
102113
end

0 commit comments

Comments
 (0)