diff --git a/Project.toml b/Project.toml index 25dce948..9c9ee002 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "UnROOT" uuid = "3cd96dde-e98d-4713-81e9-a4a1b0235ce9" authors = ["Tamas Gal", "Jerry Ling", "Johannes Schumann", "Nick Amin"] -version = "0.3.5" +version = "0.3.6" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" diff --git a/src/UnROOT.jl b/src/UnROOT.jl index 7c8d3d7c..f2b242a7 100644 --- a/src/UnROOT.jl +++ b/src/UnROOT.jl @@ -2,7 +2,7 @@ module UnROOT export ROOTFile, LazyBranch, LazyTree -import Base: keys, get, getindex, getproperty, show, length, iterate, position, ntoh, lock, unlock, reinterpret +import Base: close, keys, get, getindex, getproperty, show, length, iterate, position, ntoh, lock, unlock, reinterpret ntoh(b::Bool) = b import AbstractTrees: children, printnode, print_tree diff --git a/src/root.jl b/src/root.jl index 8a5dabf6..d80fbe34 100644 --- a/src/root.jl +++ b/src/root.jl @@ -15,6 +15,18 @@ struct ROOTFile customstructs::Dict{String, Type} lk::ReentrantLock end +function close(f::ROOTFile) + # TODO: should we take care of the lock? + close(f.fobj) +end +function ROOTFile(f::Function, args...; pv...) + rootfile = ROOTFile(args...; pv...) + try + f(rootfile) + finally + close(rootfile) + end +end lock(f::ROOTFile) = lock(f.lk) unlock(f::ROOTFile) = unlock(f.lk) function Base.hash(rf::ROOTFile, h::UInt) diff --git a/test/runtests.jl b/test/runtests.jl index 939ce72b..96da7fa9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -89,12 +89,13 @@ end @testset "ROOTFile" begin - rootfile = ROOTFile(joinpath(SAMPLES_DIR, "tree_with_histos.root")) - @test 100 == rootfile.header.fBEGIN - @test 1 == length(rootfile.directory.keys) - @test "t1" ∈ keys(rootfile) - for key in keys(rootfile) - rootfile[key] + ROOTFile(joinpath(SAMPLES_DIR, "tree_with_histos.root")) do rootfile + @test 100 == rootfile.header.fBEGIN + @test 1 == length(rootfile.directory.keys) + @test "t1" ∈ keys(rootfile) + for key in keys(rootfile) + rootfile[key] + end end rootfile = ROOTFile(joinpath(SAMPLES_DIR, "tree_with_custom_struct.root")) @@ -104,11 +105,13 @@ end for key in keys(rootfile) rootfile[key] end + close(rootfile) rootfile = ROOTFile(joinpath(SAMPLES_DIR, "histograms.root")) for branch in ["one", "two", "three"] @test branch in keys(rootfile) end + close(rootfile) rootfile = ROOTFile(joinpath(SAMPLES_DIR, "km3net_online.root")) @test 100 == rootfile.header.fBEGIN @@ -126,6 +129,7 @@ end # for key in keys(rootfile) # @test !ismissing(rootfile[key]) # end + close(rootfile) end @testset "readbasketsraw()" begin @@ -133,6 +137,7 @@ end rootfile = ROOTFile(joinpath(SAMPLES_DIR, "km3net_online.root")) data, offsets = UnROOT.array(rootfile, "KM3NET_EVENT/KM3NET_EVENT/snapshotHits"; raw=true) @test array_md5 == md5(data) + close(rootfile) rootfile = ROOTFile(joinpath(SAMPLES_DIR, "tree_with_jagged_array.root")) data, offsets = UnROOT.array(rootfile, "t1/int32_array"; raw=true) @@ -144,6 +149,7 @@ end rootfile = ROOTFile(joinpath(SAMPLES_DIR, "tree_with_vector_multiple_baskets.root")) data, offsets = UnROOT.array(rootfile, "t1/b1"; raw=true) @test unique(diff(offsets)) == [18] + close(rootfile) end @testset "No (basket) compression" begin @@ -151,6 +157,7 @@ end arr = UnROOT.array(rootfile, "t1/int32_array") @test length(arr) == 3 @test all(arr .== [[1,2], [], [3]]) + close(rootfile) end @testset "Compressions" begin @@ -159,10 +166,13 @@ end arr = UnROOT.array(rootfile, "t1/float_array") @test 100000 == length(arr) @test [0.0, 1.0588236, 2.1176472, 3.1764705, 4.2352943] ≈ arr[1:5] atol=1e-7 + close(rootfile) + rootfile = ROOTFile(joinpath(SAMPLES_DIR, "tree_with_large_array_lz4.root")) arr = collect(rootfile["t1/float_array"]) @test 100000 == length(arr) @test [0.0, 1.0588236, 2.1176472, 3.1764705, 4.2352943] ≈ arr[1:5] atol=1e-7 + close(rootfile) end @testset "ROOTDirectoryHeader" begin @@ -176,6 +186,7 @@ end @test 100 == header.fSeekDir @test 0 == header.fSeekParent @test 1398 == header.fSeekKeys + close(rootfile) # rootfile = ROOTFile(joinpath(SAMPLES_DIR, "km3net_online.root")) # header = rootfile.directory.header @@ -187,6 +198,7 @@ end # @test 100 == header.fSeekDir # @test 0 == header.fSeekParent # @test 1619244 == header.fSeekKeys + # close(rootfile) end @testset "LazyBranch and LazyTree" begin @@ -204,6 +216,7 @@ end @test [row.int32_array for row in table[20:30]] == BA[20:30] @test sum(table.int32_array) == sum(row.int32_array for row in table) @test [row.int32_array for row in table] == BA + close(rootfile) end @testset "TLorentzVector" begin @@ -217,6 +230,7 @@ end @test eltype(branch) === LorentzVectors.LorentzVector{Float64} @test tree[1].LV.x == 1.0 @test tree[1].LV.t == 4.0 + close(rootfile) end @testset "TNtuple" begin @@ -226,6 +240,7 @@ end @test arrs[1] ≈ 0:99 @test arrs[2] ≈ arrs[1] .+ arrs[1] ./ 13 @test arrs[3] ≈ arrs[1] .+ arrs[1] ./ 17 + close(rootfile) end @testset "Singly jagged branches" begin @@ -235,6 +250,7 @@ end @test data[1] == Int32[] @test data[1:2] == [Int32[], Int32[0]] @test data[end] == Int32[90, 91, 92, 93, 94, 95, 96, 97, 98] + close(rootfile) # 64bits T T = Float64 @@ -245,6 +261,7 @@ end @test data[1] == T[] @test data[1:2] == [T[], T[0]] @test data[end] == T[90, 91, 92, 93, 94, 95, 96, 97, 98] + close(rootfile) end @testset "Doubly jagged branches" begin @@ -257,6 +274,7 @@ end @test UnROOT.array(rootfile, "t1/bf") == vvf @test rootfile["t1/bf"] == vvf @test eltype(eltype(eltype(rootfile["t1/bf"]))) === Float32 + close(rootfile) end @testset "NanoAOD" begin @@ -273,6 +291,7 @@ end @test sort(propertynames(tree)) == sort([:Muon_pt, :Muon_eta, :Muon_phi, :Muon_charge]) tree = LazyTree(rootfile, "Events", r"Muon_(pt|eta)$") @test sort(propertynames(tree)) == sort([:Muon_pt, :Muon_eta]) + close(rootfile) end @testset "Branch filtering" begin @@ -294,6 +313,7 @@ end for f in files r = ROOTFile(joinpath(SAMPLES_DIR, f)) show(_io, r) + close(r) end end # Custom bootstrap things @@ -338,6 +358,7 @@ end @test headers[1].overlays == 6 @test headers[2].overlays == 21 @test headers[3].overlays == 0 + close(f) end # Histograms @@ -379,9 +400,12 @@ end @test f[k][:fN] == [0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0] end + close(f) + f = ROOTFile(joinpath(SAMPLES_DIR, "cms_ntuple_wjet.root")) binlabels = ["Root", "Weight", "Preselection", "SelectGenPart", "GoodRunsList", "EventFilters", "SelectLeptons", "SelectJets", "Trigger", "ObjectsSelection", "SSPreselection", "NjetGeq4", "AK4CategTagHiggsJets", "AK4CategTagVBSJets", "AK4CategChannels", "AK4CategPresel"] @test f["AK4CategPresel_cutflow"][:fXaxis_fModLabs].objects == binlabels + close(f) end @@ -392,6 +416,7 @@ end @test 2 == length(keys(rootfile)) @test [1.0, 2.0, 3.0] == UnROOT.array(rootfile, "TreeD/nums") @test [1.0, 2.0, 3.0] == UnROOT.array(rootfile, "TreeF/nums") + close(rootfile) # issue 55 rootfile = ROOTFile(joinpath(SAMPLES_DIR, "cms_ntuple_wjet.root")) @@ -402,10 +427,12 @@ end @test Float32[69.96958, 25.149912, 131.66693, 150.56802] == pts1[1:4] @test pts1 == pts2 @test pts3[1:2] == [[454.0, 217.5, 89.5, 30.640625], [184.375, 33.28125, 32.28125, 28.46875]] + close(rootfile) # issue 61 rootfile = ROOTFile(joinpath(SAMPLES_DIR, "issue61.root")) @test rootfile["Events/Jet_pt"][:] == Vector{Float32}[[], [27.324587, 24.889547, 20.853024], [], [20.33066], [], []] + close(rootfile) end @testset "jagged subbranch type by leaf" begin @@ -417,6 +444,8 @@ end ids_jagged = UnROOT.array(rootfile, "E/Evt/trks/trks.id") @test all(ids_jagged[1] .== collect(1:56)) @test all(ids_jagged[9] .== collect(1:54)) + + close(rootfile) end @testset "Type stability" begin @@ -441,4 +470,6 @@ end @test isfullystable(f1) @test isfullystable(f2) + + close(rootfile) end