ATLAS Offline Software
Loading...
Searching...
No Matches
Node.py
Go to the documentation of this file.
14
15
16from AthenaConfiguration.AthConfigFlags import CfgFlag
17
18# locked state, allows transitions, locked forever,
19# means it can not later be unlocked
20# dynamic flag loading is possibly even if locked forever
21# since existing nodes do not need to be unlocked
22
23_UNLOCKED = 0
24_LOCKED = 1
25_LOCKED_FOREVER = 2
26
27class Node:
28 """
29 Basic node class, so we can get all the egregious flags from a
30 flags object, and use, and pass round, the individual nodes, as
31 actual nodes without all the nonsense limitations of using the
32 flags directly
33 """
34
35 def __init__(self, name="root", flags=None, root=None ):
36 object.__setattr__(self, "_lockstate", _UNLOCKED)
37 object.__setattr__(self, "_name", name)
38 object.__setattr__(self, "_children", {})
39 object.__setattr__(self, "_flags", flags)
40 object.__setattr__(self, "_root", root)
41
42 def lock(self, lockstate=_LOCKED):
43 for node in self.nodes() : node.lock(lockstate)
44 object.__setattr__(self, "_lockstate", lockstate)
45
46 def unlock(self):
48 if self._lockstate == _LOCKED:
49 object.__setattr__(self, "_lockstate", _UNLOCKED)
50 for node in self.nodes(): node.unlock()
51
52 def lock_forever(self):
53 self.lock(_LOCKED_FOREVER)
54
55 def islocked(self):
56 return self._lockstate != _UNLOCKED
57
59 if self._lockstate == _LOCKED_FOREVER : raise RuntimeError(f"Node '{self._name}' is permanently locked; ")
60
61 def _fail_if_locked(self):
62 if self._lockstate == _LOCKED : raise RuntimeError(f"Node '{self._name}' is locked; ")
63 if self._lockstate == _LOCKED_FOREVER : raise RuntimeError(f"Node '{self._name}' is permanently locked; ")
64
65 def __setattr__(self, name, value):
66 self._fail_if_locked()
67 object.__setattr__(self, name, value)
68
69 def __getattribute__(self, name):
70 value = object.__getattribute__(self, name)
71 if isinstance(value, CfgFlag):
72 flags = object.__getattribute__(self, "_flags")
73 return value.get(flags)
74 return value
75
76
77 def __getattr__(self, name):
78 """ will attempt a dynamic load from flags if need be """
79 if name in self._children : return self._children[name]
80 if self._root :
81 if self._root._loadflags( f"{self.name()}.{name}" ) :
82 if name in self._children : return self._children[name]
83
84 if name in self._root._children : return self._root._children[name]
85 if self._root._loadflags( name ) :
86 if name in self._root._children : return self._root._children[name]
87 else:
88 if self._loadflags( name ) :
89 if name in self._children : return self._children[name]
90
91 raise AttributeError(f"no attribute {name}")
92
93
94 def _loadflags(self, name ) :
95 """ load dynamic flags - can only load flags on the root node """
96
97 if self._root : return self._root._loadflags( name )
98
99 flags = self._flags
100 if flags is None : raise AttributeError(f"no attribute {name}")
101 lockstate = self._lockstate
102 object.__setattr__(self, "_lockstate", _UNLOCKED)
103 try:
104 if name in flags._dynaflags : return self._addDynaFlags(name)
105 for key in flags._dynaflags :
106 if name in key : return self._addDynaFlags(key)
107 return False
108 finally:
109 # ensure the lock state is restored if something goes wrong ...
110 if lockstate != _UNLOCKED : self.lock(lockstate)
111
112
113 def _addDynaFlags(self, name) :
114 flags = self._flags
115 self._flags._loadDynaFlags(name)
116 for key, val in self._flags._flagdict.items() :
117 if key == name or key.startswith(name+".") : self._addFlagUnlock( key, val, flags )
118 return True
119
120 def _rootnode(self):
121 if self._root : return self._root
122 return self
123
124 def _setrootnode(self, rootnode ):
125 if self._root is rootnode : return
126 object.__setattr__(self, "_root", rootnode )
127 for node in self.nodes() : node._setrootnode(rootnode)
128
129 def name(self) :
130 return self._name
131
132 def add(self, attr_name, value):
133 """ add an attribute to this node """
134 setattr(self, attr_name, value)
135
136 def _addFlagImpl(self, tag, value, flags=None, unlock=False):
137 """ addFlag method like that in the egregious flags """
138 node = self
139 if flags is not None and self._flags is None : node._flags = flags
140 names = tag.split(".")
141 for name in names[:-1]:
142 node = node.addNewNode(name, flags )
143 if unlock : object.__setattr__( node, "_lockstate", _UNLOCKED )
144 if flags is not None : node._flags = flags
145 if names[-1] in node.__dict__ : return False
146 setattr(node, names[-1], value)
147 return True
148
149 def addFlag(self, tag, value, flags=None):
150 if not self._addFlagImpl( tag, value, flags, False ):
151 raise KeyError(f"node: {tag} already exists")
152
153 def _addFlagUnlock(self, tag, value, flags=None):
154 self._addFlagImpl( tag, value, flags, True )
155
156
157 def addNewNode(self, name, flags=None):
158 """ add a new child node """
159 self._fail_if_locked()
160 rootnode = self._rootnode()
161 if name not in self._children :
162 self._children[name] = ( node := Node(name, root=rootnode) )
163 if flags is not None : node._flags = flags
164 return self._children[name]
165
166 def addNode(self, node):
167 """ an en existing node as a child node """
168 self._fail_if_locked()
169 rootnode = self._rootnode()
170 if node.name() not in self._children :
171 if node._root and rootnode is not node.root :
172 raise RuntimeError(f"cannot add node {node.name()} from a different tree")
173 self._children[node.name()] = node
174 if not node._root : node.setrootnode( rootnode )
175 return self._children[node.name()]
176
177 def has(self, name ):
178 return hasattr( self, name )
179
180 def hasFlag(self, name ):
181 return name in self.__dict__
182
183 def nodes(self):
184 return self._children.values()
185
186 def hasNode(self, name):
187 return name in self._children
188
189 def node(self, name):
190 if self.hasNode(name) : return self._children[name]
191 raise RuntimeError(f"So such child: {name}")
192
193 def delete(self, name):
194 self._fail_if_locked()
195 if name in self._children : del ( self._children[name] )
196 elif name in self.__dict__ : delattr( self, name )
197
198 def rename( self, name, newname ):
199 if newname in self._children or newname in self.__dict__ :
200 raise RuntimeError(f"name {newname} already in node")
201
202 if name in self.__dict__: setattr(self, newname, self.__dict__.pop(name) )
203 elif name in self._children :
204 self._children[newname] = ( node := self._children.pop(name) )
205 node._name = newname
206
207 def clone(self, name=None):
208 """Return an independent copy" of this node"""
209
210 if name is not None : newnode = Node(name)
211 else: newnode = Node(self._name)
212
213 for key, value in self.__dict__.items():
214 if key in {"_name", "_children", "_lockstate", "_root" } : continue
215
216 setattr(newnode, key, value)
217
218 for node in self.nodes():
219 newnode.addNode(node.clone())
220
221 return newnode
222
223
224 def print(self, spacer=""):
225 print( f"{spacer}", self._name, "(Node)" )
226 if spacer=="" : spacer = "|__"
227 else: spacer=f" {spacer}"
228 for key, value in self.__dict__.items():
229 if key in {"_name","_children","_lockstate", "_flags", "_root"} : continue
230 print( spacer, key, " : ", value )
231 for node in self.nodes() : node.print( spacer )
232
233 def dump(self):
234 self.print()
235
236
237
238def notDefined(flags, name):
239 """ check whether the flags have an actual item with this name
240 NB using hasFlag(name) is really dengerous, as that seems to
241 actually evaluate any actual functions ? shouldn't
242 something like that be called testFlag() ?
243 """
244 return name not in flags._flagdict
245
246
247
248def decode_flags( flags, domain=None ) :
249 """ take an egregious flags list and convert to a lovely tree """
250 root = Node("root")
251
252 for tag, value in flags._flagdict.items():
253 root.addFlag( tag, value, flags )
254
255 return root
256
257
258
259
260def update_flags( flags, node, domain="" ) :
261 """ take a lovely tree and convert to an egregious flags list,
262 only adding items that are not in the original flags list """
263
264 for key, value in node.__dict__.items():
265 if key in {"_name","_children","_lockstate", "_flags", "_root" } : continue
266 name = f"{domain}.{key}"
267 if notDefined(flags,name) : flags.addFlag( name, value )
268
269 for n in node.nodes() :
270 if domain=="" : update_flags( flags, n, f"{n.name()}" )
271 else: update_flags( flags, n, f"{domain}.{n.name()}" )
272
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
void name(const std::string &n)
Definition node.h:40
nodes(self)
Definition Node.py:183
print(self, spacer="")
Definition Node.py:224
addNewNode(self, name, flags=None)
Definition Node.py:157
lock(self, lockstate=_LOCKED)
Definition Node.py:42
addFlag(self, tag, value, flags=None)
Definition Node.py:149
_setrootnode(self, rootnode)
Definition Node.py:124
unlock(self)
Definition Node.py:46
__getattr__(self, name)
Definition Node.py:77
return self._children[name] _children
Definition Node.py:79
__init__(self, name="root", flags=None, root=None)
Definition Node.py:35
addNode(self, node)
Definition Node.py:166
hasNode(self, name)
Definition Node.py:186
has(self, name)
Definition Node.py:177
_fail_if_locked(self)
Definition Node.py:61
__setattr__(self, name, value)
Definition Node.py:65
_addDynaFlags(self, name)
Definition Node.py:113
hasFlag(self, name)
Definition Node.py:180
clone(self, name=None)
Definition Node.py:207
_addFlagImpl(self, tag, value, flags=None, unlock=False)
Definition Node.py:136
_loadflags(self, name)
Definition Node.py:94
_addFlagUnlock(self, tag, value, flags=None)
Definition Node.py:153
delattr(self, name) __dict__
Definition Node.py:196
lock_forever(self)
Definition Node.py:52
node(self, name)
Definition Node.py:189
add(self, attr_name, value)
Definition Node.py:132
__getattribute__(self, name)
Definition Node.py:69
return self._root._loadflags(name) _root
Definition Node.py:80
islocked(self)
Definition Node.py:55
_fail_if_locked_forever(self)
Definition Node.py:58
_rootnode(self)
Definition Node.py:120
rename(self, name, newname)
Definition Node.py:198
delete(self, name)
Definition Node.py:193
-event-from-file
notDefined(flags, name)
Definition Node.py:238
decode_flags(flags, domain=None)
Definition Node.py:248
update_flags(flags, node, domain="")
Definition Node.py:260