ATLAS Offline Software
Loading...
Searching...
No Matches
Node.py
Go to the documentation of this file.
40
41import warnings
42
43# locked state, allows transitions, locked forever,
44# means it can not later be unlocked
45# dynamic flag loading is possibly even if locked forever
46# since existing nodes do not need to be unlocked
47
48_UNLOCKED = 0
49_LOCKED = 1
50_LOCKED_FOREVER = 2
51
52class Node:
53 """
54 Basic node class, so we can get all the egregious flags from a
55 flags object, and use, and pass round, the individual nodes, as
56 actual nodes without all the nonsense limitations of using the
57 flags directly
58 """
59
60 def __init__(self, name="root", flags=None, root=None ):
61 object.__setattr__(self, "_lockstate", _UNLOCKED)
62 object.__setattr__(self, "_name", name)
63 object.__setattr__(self, "_children", {})
64 object.__setattr__(self, "_flags", flags)
65 object.__setattr__(self, "_root", root)
66
67 def __setattr__(self, name, value):
68 self._fail_if_locked()
69 if name in self._children : raise AttributeError(f"node {name} already exists")
70 current = self.__dict__.get(name)
71 if type(current).__name__ == "CfgFlag":
72 current.set(value)
73 else:
74 object.__setattr__(self, name, value)
75
76 def __getattribute__(self, name):
77 value = object.__getattribute__(self, name)
78 if type(value).__name__ == "CfgFlag":
79 flags = object.__getattribute__(self, "_flags")
80 return value.get(flags)
81 return value
82
83 def __getattr__(self, name):
84 """ will attempt a dynamic load from flags if need be """
85 if name in self._children : return self._children[name]
86 if self._root :
87 if self._root._loadflags( f"{self.name()}.{name}" ) :
88 if name in self._children : return self._children[name]
89 if name in self._root._children : return self._root._children[name]
90 if self._root._loadflags( name ) :
91 if name in self._root._children : return self._root._children[name]
92 else:
93 if self._loadflags( name ) :
94 if name in self._children : return self._children[name]
95
96 raise AttributeError(f"no attribute {name}")
97
98 def __contains__(self, name):
99 return self.has(name)
100
101 def __copy__(self):
102 return self.clone()
103
104 def __delattr__(self, name):
105 self.delete(name)
106
107 def __delitem__(self, name):
108 self.delete(name)
109
110 def lock(self, lockstate=_LOCKED):
111 for node in self.nodes() : node.lock(lockstate)
112 object.__setattr__(self, "_lockstate", lockstate)
113
114 def unlock(self):
116 if self._lockstate == _LOCKED:
117 object.__setattr__(self, "_lockstate", _UNLOCKED)
118 for node in self.nodes(): node.unlock()
119
120 def lock_forever(self):
121 self.lock(_LOCKED_FOREVER)
122
123 def islocked(self):
124 return self._lockstate != _UNLOCKED
125
126 def locked(self):
127 return self.islocked()
128
130 if self._lockstate == _LOCKED_FOREVER : raise RuntimeError(f"Node {self._name} is permanently locked; ")
131
133 if self._lockstate == _LOCKED : raise RuntimeError(f"Node {self._name} is locked; ")
134 if self._lockstate == _LOCKED_FOREVER : raise RuntimeError(f"Node {self._name} is permanently locked; ")
135
136 def _loadflags(self, name ) :
137 """ load dynamic flags - can only load flags on the root node """
138
139 if self._root : return self._root._loadflags( name )
140
141 flags = self._flags
142 if flags is None : raise AttributeError(f"no attribute {name}")
143 lockstate = self._lockstate
144 object.__setattr__(self, "_lockstate", _UNLOCKED)
145 try:
146 if name in flags._loaded : return self._stragglers(flags)
147 if name in flags._dynaflags : return self._addDynaFlags(name)
148 for key in flags._dynaflags :
149 if name in key : return self._addDynaFlags(key)
150 return False
151 finally:
152 # ensure the lock state is restored if something goes wrong ...
153 if lockstate != _UNLOCKED : self.lock(lockstate)
154
155 def _addDynaFlags(self, name) :
156 flags = self._flags
157 self._flags._loadDynaFlags(name)
158 return self._stragglers(flags)
159
160 def _stragglers(self, flags, dbg="") :
161 for key, val in self._flags._flagdict.items() :
162 if self._hasFlagPath(key) : continue
163 self._addFlagUnlock( key, val, flags )
164 return True
165
166 def _rootnode(self):
167 if self._root : return self._root
168 return self
169
170 def _setrootnode(self, rootnode ):
171 if self._root is rootnode : return
172 object.__setattr__(self, "_root", rootnode )
173 for node in self.nodes() : node._setrootnode(rootnode)
174
175 def name(self) :
176 return self._name
177
178 def add(self, attr_name, value):
179 """ add an attribute to this node """
180 setattr(self, attr_name, value)
181
182 def _addFlagImpl(self, tag, value, flags=None, unlock=False):
183 """ addFlag method like that in the egregious flags """
184 node = self
185 if flags is not None and self._flags is None : node._flags = flags
186 names = tag.split(".")
187 for name in names[:-1]:
188 node = node._addNewNode(name, flags )
189 if unlock : object.__setattr__( node, "_lockstate", _UNLOCKED )
190 if flags is not None : node._flags = flags
191 if names[-1] in node.__dict__ : return False
192 # just use a value at the moment, can use CfgFlag(value, type) if we really have to(
193 setattr(node, names[-1], value)
194 return True
195
196 def addFlag(self, tag, value, flags=None):
197 if not self._addFlagImpl( tag, value, flags, False ):
198 raise KeyError(f"flag {tag} already exists")
199
200 def _addFlagUnlock(self, tag, value, flags=None):
201 self._addFlagImpl( tag, value, flags, True )
202
203 def addNode( self, item, flags=None):
204 if isinstance(item, Node) : return self._addNode(item)
205 if isinstance(item, str) : return self._addNewNode(item, flags)
206 raise TypeError(f"Cannot construct node from type {type(item).__name__}, value {item}")
207
208 def _addNewNode(self, name : str, flags=None):
209 """ add a new child node """
210 self._fail_if_locked()
211 if name in self.__dict__: raise AttributeError(f"attribute {name} already exists")
212 rootnode = self._rootnode()
213 if name not in self._children :
214 self._children[name] = ( node := Node(name, root=rootnode) )
215 if flags is not None : node._flags = flags
216 return self._children[name]
217
218 def _addNode(self, node ):
219 """ an en existing node as a child node """
220 self._fail_if_locked()
221 name = node.name()
222 if name in self.__dict__: raise AttributeError(f"attribute {name} already exists")
223 rootnode = self._rootnode()
224 if name not in self._children :
225 if node._root and rootnode is not node._root :
226 raise RuntimeError(f"cannot add node {name} from a different tree")
227 self._children[node.name()] = node
228 if not node._root : node._setrootnode( rootnode )
229 return self._children[node.name()]
230
231 def has(self, name, value=None ):
232 if value is None : return hasattr( self, name )
233 return hasattr( self, name ) and getattr( self, name ) == value
234
235 def hasFlag(self, name ):
236 return name in self.__dict__
237
238 def hasNode(self, name):
239 return name in self._children
240
241 def _hasFlagPath(self, name):
242 parts = name.split('.')
243 node = self._rootnode()
244 for part in parts[:-1]:
245 if not node.hasNode(part) : return False
246 node = node.node(part)
247 return node.hasFlag(parts[-1])
248
249 def nodes(self):
250 return self._children.values()
251
252 def node_flags(self):
253 for key, value in self.__dict__.items():
254 if not key.startswith("_"):
255 yield key, getattr(self, key)
256
257 def node(self, name):
258 if self.hasNode(name) : return self._children[name]
259 raise RuntimeError(f"So such child: {name}")
260
261 def delete(self, name):
262 self._fail_if_locked()
263 if name in self._children : del self._children[name]
264 elif name in self.__dict__ : object.__delattr__(self, name) # delattr( self, name )
265 else : raise AttributeError(f"Node {self._name} has no member {name}")
266
267 def rename( self, name, newname ):
268 if newname in self._children or newname in self.__dict__ :
269 raise RuntimeError(f"name {newname} already in node")
270
271 if name in self.__dict__: setattr(self, newname, self.__dict__.pop(name) )
272 elif name in self._children :
273 self._children[newname] = ( node := self._children.pop(name) )
274 node._name = newname
275
276 def clone(self, name=None):
277 """Return an independent copy" of this node"""
278
279 if name is not None : newnode = Node(name)
280 else: newnode = Node(self._name)
281
282 for key, value in self.__dict__.items():
283 if key in {"_name", "_children", "_lockstate", "_root" } : continue
284 setattr(newnode, key, value)
285
286 for node in self.nodes():
287 child = node.clone()
288 child._root = None
289 newnode._addNode(child)
290
291 return newnode
292
293
294 def print(self, spacer=""):
295 print( f"{spacer}{self._name} (Node)" )
296 if spacer=="" : spacer = "|__ "
297 else: spacer=f" {spacer}"
298 for key, value in self.__dict__.items():
299 if key in {"_name","_children","_lockstate", "_flags", "_root"} : continue
300 print( f"{spacer}{key}\t: {value}" )
301 for node in self.nodes() : node.print( spacer )
302
303
304 def dump(self): self.print()
305
306
307 def cloneAndReplace(self, targetname, flagname ) :
308 # we really, really, should not have this ...
309 warnings.warn( "cloneAndReplace() is unnecessary for Node flags; "
310 "use the appropriate Node directly",
311 RuntimeWarning, stacklevel=2 )
312 # eventually, instead of delegation, should raise an exception ...
313 # raise RuntimeError( "cloneAndReplace() should not be used for node flags" )
314 return self._rootnode()._flags.cloneAndReplace( targetname, flagname )
315
316
317def notDefined(flags, name):
318 """ check whether the flags have an actual item with this name
319 NB using hasFlag(name) is really dengerous, as that seems to
320 actually evaluate any actual functions ? shouldn't
321 something like that be called testFlag() ?
322 """
323 return name not in flags._flagdict
324
325
326
327def decode_flags( flags, domain=None ) :
328 """ take an egregious flags list and convert to a lovely tree
329 or, if it is a lovely tree already, just hand it back
330 """
331
332 if isinstance( flags, Node ) : return flags
333
334 root = Node("root")
335
336 for tag, value in flags._flagdict.items():
337 root.addFlag( tag, value, flags )
338
339 return root
340
341
342
343
344def update_flags( flags, node, domain="" ) :
345 """ take a lovely tree and convert to an egregious flags list,
346 only adding items that are not in the original flags list """
347
348 for key, value in node.__dict__.items():
349 if key in {"_name","_children","_lockstate", "_flags", "_root" } : continue
350 name = f"{domain}.{key}"
351 if notDefined(flags,name) : flags.addFlag( name, value )
352
353 for n in node.nodes() :
354 if domain=="" : update_flags( flags, n, f"{n.name()}" )
355 else: update_flags( flags, n, f"{domain}.{n.name()}" )
356
357
358
359def topnode(flags) :
360 """ Escape hatch in case the user needs to access a node
361 from the top node that has the Same Name, as a node
362 on the local node"""
363 return flags._rootnode()
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
node(node *n=0, const std::string &d="", TObject *t=0)
Definition node.h:32
void name(const std::string &n)
Definition node.h:40
nodes(self)
Definition Node.py:249
print(self, spacer="")
Definition Node.py:294
lock(self, lockstate=_LOCKED)
Definition Node.py:110
addFlag(self, tag, value, flags=None)
Definition Node.py:196
_setrootnode(self, rootnode)
Definition Node.py:170
unlock(self)
Definition Node.py:114
__getattr__(self, name)
Definition Node.py:83
addNode(self, item, flags=None)
Definition Node.py:203
_hasFlagPath(self, name)
Definition Node.py:241
__contains__(self, name)
Definition Node.py:98
_addNewNode(self, str name, flags=None)
Definition Node.py:208
__delitem__(self, name)
Definition Node.py:107
__init__(self, name="root", flags=None, root=None)
Definition Node.py:60
__delattr__(self, name)
Definition Node.py:104
__copy__(self)
Definition Node.py:101
locked(self)
Definition Node.py:126
hasNode(self, name)
Definition Node.py:238
_addNode(self, node)
Definition Node.py:218
has(self, name, value=None)
Definition Node.py:231
_fail_if_locked(self)
Definition Node.py:132
cloneAndReplace(self, targetname, flagname)
Definition Node.py:307
__setattr__(self, name, value)
Definition Node.py:67
_addDynaFlags(self, name)
Definition Node.py:155
hasFlag(self, name)
Definition Node.py:235
clone(self, name=None)
Definition Node.py:276
_addFlagImpl(self, tag, value, flags=None, unlock=False)
Definition Node.py:182
_stragglers(self, flags, dbg="")
Definition Node.py:160
_loadflags(self, name)
Definition Node.py:136
_addFlagUnlock(self, tag, value, flags=None)
Definition Node.py:200
lock_forever(self)
Definition Node.py:120
node_flags(self)
Definition Node.py:252
node(self, name)
Definition Node.py:257
add(self, attr_name, value)
Definition Node.py:178
__getattribute__(self, name)
Definition Node.py:76
return self._root._loadflags(name) _root
Definition Node.py:86
islocked(self)
Definition Node.py:123
_fail_if_locked_forever(self)
Definition Node.py:129
raise AttributeError(f) _children
Definition Node.py:69
raise AttributeError(f) __dict__
Definition Node.py:211
_rootnode(self)
Definition Node.py:166
rename(self, name, newname)
Definition Node.py:267
delete(self, name)
Definition Node.py:261
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
-event-from-file
topnode(flags)
Definition Node.py:359
notDefined(flags, name)
Definition Node.py:317
decode_flags(flags, domain=None)
Definition Node.py:327
update_flags(flags, node, domain="")
Definition Node.py:344