node.py
Go to the documentation of this file.
1 # -*- Python -*-
2 # -*- coding: utf-8 -*-
3 
4 '''rtctree
5 
6 Copyright (C) 2009-2014
7  Geoffrey Biggs
8  RT-Synthesis Research Group
9  Intelligent Systems Research Institute,
10  National Institute of Advanced Industrial Science and Technology (AIST),
11  Japan
12  All rights reserved.
13 Licensed under the Eclipse Public License -v 1.0 (EPL)
14 http://www.opensource.org/licenses/eclipse-1.0.txt
15 
16 Object representing a generic node in the tree.
17 
18 '''
19 
20 
21 import threading
22 
23 from rtctree.exceptions import NotRelatedError, NoSuchEventError
24 
25 
26 ##############################################################################
27 ## Base node object
28 
29 class TreeNode(object):
30  '''Base class for a node in the tree.
31 
32  Do not create this class directly. Create objects using a suitable child
33  class of this class.
34 
35  '''
36  def __init__(self, name=None, parent=None, children=None, filter=[],
37  dynamic=False, *args, **kwargs):
38  '''Constructor.
39 
40  @param name Name of this node (i.e. its entry in the path).
41  @param parent The parent node of this node, if any.
42  @param children If the list of children is already known, put it here.
43  @param filter A list of paths to filter by.
44  @param dynamic Enable dynamic features such as observers on this node
45  and any children it creates.
46 
47  '''
48  super(TreeNode, self).__init__(*args, **kwargs)
49  self._mutex = threading.RLock()
50  self._name = name
51  self._parent = parent
52  if children:
53  self._children = children
54  else:
55  self._children = {}
56  self._cbs = {}
57  self._dynamic = dynamic
58  if dynamic:
59  self._enable_dynamic(dynamic)
60 
61  def __str__(self):
62  '''Get this node as a string.'''
63  with self._mutex:
64  indent = ''.rjust(self.depth)
65  result = '{0}{1}, {2}\n'.format(indent, self._name, self._children)
66  for child in self._children:
67  result += str(self._children[child])
68  return result
69 
70  def add_callback(self, event, cb, args=None):
71  '''Add a callback to this node.
72 
73  Callbacks are called when the specified event occurs. The available
74  events depends on the specific node type. Args should be a value to
75  pass to the callback when it is called. The callback should be of the
76  format:
77 
78  def callback(node, value, cb_args):
79 
80  where node will be the node that called the function, value is the
81  relevant information for the event, and cb_args are the arguments you
82  registered with the callback.
83 
84  '''
85  if event not in self._cbs:
87  self._cbs[event] = [(cb, args)]
88 
89  def get_node(self, path):
90  '''Get a child node of this node, or this node, based on a path.
91 
92  @param path A list of path elements pointing to a node in the tree.
93  For example, ['/', 'localhost', 'dir.host']. The first
94  element in this path should be this node's name.
95  @return The node pointed to by @ref path, or None if the path does not
96  point to a node in the tree below this node.
97 
98  '''
99  with self._mutex:
100  if path[0] == self._name:
101  if len(path) == 1:
102  return self
103  elif path[1] in self._children:
104  return self._children[path[1]].get_node(path[1:])
105  else:
106  return None
107  else:
108  return None
109 
110  def has_path(self, path):
111  '''Check if a path exists below this node.
112 
113  @param path A list of path elements pointing to a node in the tree.
114  For example, ['/', 'localhost', 'dir.host']. The first
115  element in this path should be this node's name.
116  @return True if the path points to a node in the tree below this node,
117  or this node itself (for paths one element long). False
118  otherwise.
119 
120  '''
121  with self._mutex:
122  if path[0] == self._name:
123  if len(path) == 1:
124  return True
125  elif path[1] in self._children:
126  return self._children[path[1]].has_path(path[1:])
127  else:
128  return False
129  else:
130  return False
131 
132  def is_child(self, other_node):
133  '''Is @ref other_node a child of this node?'''
134  with self._mutex:
135  return other_node in self._children
136 
137  def is_parent(self, other_node):
138  '''Is @ref other_node the parent of this note?'''
139  return other_node == self.parent
140 
141  def iterate(self, func, args=None, filter=[]):
142  '''Call a function on this node, and recursively all its children.
143 
144  This is a depth-first iteration.
145 
146  @param func The function to call. Its declaration must be
147  'def blag(node, args)', where 'node' is the current node
148  in the iteration and args is the value of @ref args.
149  @param args Extra arguments to pass to the function at each iteration.
150  Pass multiple arguments in as a tuple.
151  @param filter A list of filters to apply before calling func for each
152  node in the iteration. If the filter is not True,
153  @ref func will not be called for that node. Each filter
154  entry should be a string, representing one of the is_*
155  properties (is_component, etc), or a function object.
156  @return The results of the calls to @ref func in a list.
157 
158  '''
159  with self._mutex:
160  result = []
161  if filter:
162  filters_passed = True
163  for f in filter:
164  if type(f) == str:
165  if not eval('self.' + f):
166  filters_passed = False
167  break
168  else:
169  if not f(self):
170  filters_passed = False
171  break
172  if filters_passed:
173  result = [func(self, args)]
174  else:
175  result = [func(self, args)]
176  for child in self._children:
177  result += self._children[child].iterate(func, args, filter)
178  return result
179 
180  def rem_callback(self, event, cb):
181  '''Remove a callback from this node.
182 
183  The callback is removed from the specified event.
184 
185  @param cb The callback function to remove.
186 
187  '''
188  if event not in self._cbs:
189  raise exceptions.NoSuchEventError(self.name, event)
190  c = [(x[0], x[1]) for x in self._cbs[event]]
191  if not c:
192  raise exceptions.NoCBError(self.name, event, cb)
193  self._cbs[event].remove(c[0])
194 
195  @property
196  def children(self):
197  '''The child nodes of this node (if any).'''
198  with self._mutex:
199  return self._children.values()
200 
201  @property
202  def children_names(self):
203  '''A list of the names of the child nodes of this node (if any).'''
204  with self._mutex:
205  return self._children.keys()
206 
207  @property
208  def depth(self):
209  '''The depth of this node in the tree.
210 
211  The root node is depth 0.
212 
213  '''
214  with self._mutex:
215  if self._parent:
216  return len(self.full_path) - 1
217  else:
218  return 0
219 
220  @property
221  def dynamic(self):
222  '''Get and change the dynamic setting of this node.'''
223  with self._mutex:
224  return self._dynamic
225 
226  @dynamic.setter
227  def dynamic(self, dynamic):
228  with self._mutex:
229  if self._dynamic and not dynamic:
230  # Disable dynamism
231  self._enable_dynamic(False)
232  elif not self._dynamic and dynamic:
233  # Enable dynamism
234  self._enable_dynamic(True)
235 
236  @property
237  def full_path(self):
238  '''The full path of this node.'''
239  with self._mutex:
240  if self._parent:
241  return self._parent.full_path + [self._name]
242  else:
243  return [self._name]
244 
245  @property
246  def full_path_str(self):
247  '''The full path of this node as a string.'''
248  with self._mutex:
249  if self._parent:
250  if self._parent._name == '/':
251  return self._parent.full_path_str + self._name
252  else:
253  return self._parent.full_path_str + '/' + self._name
254  else:
255  return self._name
256 
257  @property
258  def is_component(self):
259  '''Is this node a component?'''
260  return False
261 
262  @property
263  def is_directory(self):
264  '''Is this node a directory?'''
265  with self._mutex:
266  if self._name == '/':
267  return True
268  return False
269 
270  @property
271  def is_manager(self):
272  '''Is this node a manager?'''
273  return False
274 
275  @property
276  def is_nameserver(self):
277  '''Is this node a name server (specialisation of directory nodes)?'''
278  return False
279 
280  @property
281  def is_unknown(self):
282  '''Is this node unknown?'''
283  return False
284 
285  @property
286  def is_zombie(self):
287  '''Is this node a zombie?'''
288  return False
289 
290  @property
291  def name(self):
292  '''The name of this node.'''
293  with self._mutex:
294  return self._name
295 
296  @property
297  def nameserver(self):
298  '''The name server of the node (i.e. its top-most parent below /).'''
299  with self._mutex:
300  if not self._parent:
301  # The root node does not have a name server
302  return None
303  elif self._parent.name == '/':
304  return self
305  else:
306  return self._parent.nameserver
307 
308  @property
309  def orb(self):
310  '''The ORB used to access this object.
311 
312  This property's value will be None if no object above this object is a
313  name server.
314 
315  '''
316  with self._mutex:
317  if self._parent.name == '/':
318  return None
319  return self._parent.orb
320 
321  @property
322  def parent(self):
323  '''This node's parent, or None if no parent.'''
324  with self._mutex:
325  return self._parent
326 
327  def remove_child(self, child):
328  # Remove a child from this node.
329  with self._mutex:
330  if child.name not in self._children:
331  raise NotRelatedError(self.name, child.name)
332  del self._children[child.name]
333 
334  @parent.setter
335  def parent(self, new_parent):
336  with self._mutex:
337  if self._parent:
338  # Make sure to unlink the tree as well
339  self._parent.remove_child(self)
340  self._parent = new_parent
341 
342  @property
343  def parent_name(self):
344  '''The name of this node's parent or an empty string if no parent.'''
345  with self._mutex:
346  if self._parent:
347  return self._parent.name
348  else:
349  return ''
350 
351  @property
352  def root(self):
353  '''The root node of the tree this node is in.'''
354  with self._mutex:
355  if self._parent:
356  return self._parent.root
357  else:
358  return self
359 
360  def _add_child(self, new_child):
361  # Add a child to this node.
362  with self._mutex:
363  self._children[new_child._name] = new_child
364 
365  def _call_cb(self, event, value):
366  if event not in self._cbs:
367  raise exceptions.NoSuchEventError(self.name, event)
368  for (cb, args) in self._cbs[event]:
369  cb(self, value, args)
370 
371  def _enable_dynamic(self, enable=True):
372  # Enable or disable dynamic features.
373  # By default, do nothing.
374  pass
375 
377  # Remove all children from this node.
378  self._children = {}
379 
380  def _set_events(self, events):
381  self._cbs = {}
382  for e in events:
383  self._cbs[e] = []
384 
385 
386 # vim: tw=79
387 
def children(self)
Definition: node.py:196
def _enable_dynamic(self, enable=True)
Definition: node.py:371
def is_zombie(self)
Definition: node.py:286
def add_callback(self, event, cb, args=None)
Definition: node.py:70
def has_path(self, path)
Definition: node.py:110
def is_parent(self, other_node)
Definition: node.py:137
def is_manager(self)
Definition: node.py:271
def rem_callback(self, event, cb)
Definition: node.py:180
def full_path_str(self)
Definition: node.py:246
def root(self)
Definition: node.py:352
def name(self)
Definition: node.py:291
def is_nameserver(self)
Definition: node.py:276
def is_directory(self)
Definition: node.py:263
def __str__(self)
Definition: node.py:61
def iterate(self, func, args=None, filter=[])
Definition: node.py:141
def get_node(self, path)
Definition: node.py:89
def dynamic(self)
Definition: node.py:221
def full_path(self)
Definition: node.py:237
def parent_name(self)
Definition: node.py:343
def orb(self)
Definition: node.py:309
def is_component(self)
Definition: node.py:258
def _remove_all_children(self)
Definition: node.py:376
def remove_child(self, child)
Definition: node.py:327
def __init__(self, name=None, parent=None, children=None, filter=[], dynamic=False, args, kwargs)
Definition: node.py:37
def _add_child(self, new_child)
Definition: node.py:360
def is_unknown(self)
Definition: node.py:281
def is_child(self, other_node)
Definition: node.py:132
Base node object.
Definition: node.py:29
def depth(self)
Definition: node.py:208
def nameserver(self)
Definition: node.py:297
def parent(self)
Definition: node.py:322
def _call_cb(self, event, value)
Definition: node.py:365
def _set_events(self, events)
Definition: node.py:380
def children_names(self)
Definition: node.py:202


rtctree
Author(s): Geoffrey Biggs
autogenerated on Fri Jun 7 2019 21:56:24