Skip to content
This repository was archived by the owner on Jun 21, 2022. It is now read-only.

Commit d9ea740

Browse files
authored
Implemented TFileUpdate.bulk_write (#518)
* Implemented TFileUpdate.bulk_write * Renamed bulk_write to update and make it compatible to dict.update
1 parent 576a386 commit d9ea740

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

tests/test_write.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,3 +2134,22 @@ def test_jagged_i4_manybasket(tmp_path):
21342134
tree = f.Get("t")
21352135
for i, event in enumerate(tree):
21362136
assert(numpy.all([x for x in event.branch] == tester[i]))
2137+
2138+
def test_update(tmp_path):
2139+
filename = join(str(tmp_path), "example.root")
2140+
testfile = join(str(tmp_path), "test.root")
2141+
n = 3
2142+
2143+
f = ROOT.TFile.Open(testfile, "RECREATE")
2144+
h = ROOT.TH1F("hvar", "title", 5, 1, 10)
2145+
h.Write()
2146+
f.Close()
2147+
2148+
t = uproot.open(testfile)
2149+
hist = t["hvar"]
2150+
with uproot.recreate(filename, compression=None) as f:
2151+
f.update(("test%d" % i, hist) for i in range(n))
2152+
2153+
f = ROOT.TFile.Open(filename)
2154+
for i in range(n):
2155+
assert f.Get("test%d" % i).GetNbinsX() == 5, i

uproot/write/TFile.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
import sys
99
import struct
1010
import uuid
11+
from itertools import chain
12+
try:
13+
from collections.abc import Mapping
14+
except ImportError:
15+
from collections import Mapping
16+
1117

1218
import uproot_methods.convert
1319

@@ -102,6 +108,60 @@ def __setitem__(self, where, what):
102108
self._rootdir.setkey(newkey)
103109
self._sink.flush()
104110

111+
def update(self, *args, **kwargs):
112+
if len(args) > 1:
113+
raise TypeError("update expected at most 1 argument, got %s" % len(args))
114+
items = args[0] if args else ()
115+
if isinstance(items, Mapping):
116+
items = items.items()
117+
items = chain(items, kwargs.items())
118+
self.util = Util()
119+
120+
cursor = uproot.write.sink.cursor.Cursor(self._fSeekFree)
121+
for where, what in items:
122+
where, cycle = self._normalizewhere(where)
123+
124+
isTTree = what.__class__.__name__ in ("newtree", "TTree")
125+
assert not isTTree # prevent TTree writing, otherwise migth invoke nasty magic
126+
if not isTTree:
127+
what = uproot_methods.convert.towriteable(what)
128+
elif what.__class__.__name__ == "newtree":
129+
what = TTree(where, what, self)
130+
131+
newkey = uproot.write.TKey.TKey(
132+
fClassName=what._fClassName,
133+
fName=where,
134+
fTitle=what._fTitle,
135+
fObjlen=0,
136+
fSeekKey=cursor.index,
137+
fSeekPdir=self._fBEGIN,
138+
fCycle=cycle if cycle is not None else self._rootdir.newcycle(where),
139+
)
140+
if isTTree:
141+
# Need to (re)attach the cycle number to allow getitem to access writable TTree
142+
tree_where = where + b";" + str(newkey.fCycle).encode("utf-8")
143+
self._treedict[tree_where] = what
144+
145+
newkeycursor = uproot.write.sink.cursor.Cursor(newkey.fSeekKey)
146+
newkey.write(cursor, self._sink)
147+
what._write(self, cursor, where, self.compression, newkey, newkeycursor, self.util)
148+
149+
dirkey = (newkey.fName, newkey.fCycle)
150+
if dirkey in self._rootdir.keys:
151+
self._rootdir.headkey.fObjlen -= self._rootdir.keys[dirkey].fKeylen
152+
self._rootdir.headkey.fObjlen += newkey.fKeylen
153+
self._rootdir.keys[dirkey] = newkey
154+
155+
# write (root) TDirectory
156+
self._rootdir.fNbytesKeys = self._rootdir._nbyteskeys()
157+
while self._rootdir.fNbytesKeys > self._rootdir.allocationbytes:
158+
self._rootdir.allocationbytes *= self._rootdir.growfactor
159+
160+
self._rootdir.writekeys(cursor)
161+
162+
self._expandfile(cursor)
163+
self._sink.flush()
164+
105165
def __delitem__(self, where):
106166
where, cycle = self._normalizewhere(where)
107167
try:

0 commit comments

Comments
 (0)