1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 """
35 Generic namespace model for ROS. This powers most of rosh by enabling
36 iPython tab-complete on a ROS namespace'd resource (e.g. topics,
37 services, parameters).
38 """
39
40
41
42 from __future__ import with_statement
43
44 import roslib.names
45
46 -class Context(object):
47 """
48 ROSH context instance. Instead of globals, we need a context
49 instance that implementation can store state in.
50
51 Plugins may store properties on this object as long as they
52 include their name as a prefix.
53 """
54
56
57 self.master = None
58 self.plugin_handlers = {}
59
60 - def add_plugin_handler(self, key, args):
61 self.plugin_handlers[key] = args
62
64 """
65 NamespaceConfig is a configuration object for a L{Namespace} instance,
66 storing common data structures and objects that all L{Namespace}
67 instances need.
68 """
69
71 """
72 @param ctx: rosh context object
73 @type ctx: dict
74 @param lock: lock for controlling access to cache
75 @param master: ROS master handle, if applicable
76 @type master: rosgraph.MasterApi
77 """
78 self.cache = {}
79 self.lock = lock
80 self.ctx = ctx
81 self.master = ctx.master
82
84 """
85 Namespace provides lightweight accessors to a ROS namespace and its data. The behavior of the namespace
86 object is determined by a L{NamespaceConfig} instance.
87 """
88
90 """
91 ctor.
92 @param config: Namespace configuration instance.
93 @type config: L{NamespaceConfig}
94 """
95 self._name = name
96 self._ns = name + '/'
97 self._config = config
98
100 """
101 Subclasses should override.
102 """
103 raise NotImplemented
104
106 """
107 Subclasses should override if they have props
108 """
109 return []
110
112 """
113 Subclasses should override.
114 """
115 raise NotImplemented
116
118 return list(set([s[len(self._ns):].split('/')[0] for s in self._list()]))
119
121 if key.startswith('_') or key == 'trait_names':
122 return object.__getattribute__(self, key)
123 else:
124 return self.__getitem__(key)
125
127 return (getattr(self, k) for k in self._getAttributeNames())
128
129 - def _get_entry(self, key):
130 """
131 By default, creates a new Namespace instance of the correct
132 subclass. Subclasses may wish to override.
133 """
134 cache = self._config.cache
135 with self._config.lock:
136 if key in cache:
137 obj = cache[key]
138 else:
139
140
141 obj = self.__class__(key, self._config)
142 cache[key] = obj
143 return obj
144
146 """
147 Dictionary-style accessor
148 """
149 key = roslib.names.ns_join(self._ns, key)
150 if key in self._config.cache:
151 return self._config.cache[key]
152 else:
153 val = self._get_entry(key)
154 return val
155
157
159 """
160 @param ctx: Context instance
161 @type ctx: L{Context}
162 @param lock: Resource lock for modifying ctx resources
163 @type lock: threading.Lock
164 @param nstype: Namespace class
165 @type nstype: class
166 """
167 self._master = ctx.master
168
169 self._config = NamespaceConfig(ctx, lock)
170 self._root = nstype('', self._config)
171 self._nstype = nstype
172
174 """
175 Subclasses should override (if necessary)
176 """
177 raise NotImplemented
178
180 return self._root._getAttributeNames()
181
183 """
184 Subclasses should override if they have props
185 """
186 return []
187
190
196
198 """
199 Dictionary-style accessor for topics
200 """
201 return self._root.__getitem__(key)
202
204 """
205 A ResourceList presents a IPython tab-completable list of
206 resources as if they are attributes. The general form of
207 ResourceList only presents a flat list of resources. For a
208 ResourceList that is namespace-aware, use L{NSResourceList}.
209
210 ResourceList can share a config with a Namespace instance, which
211 makes them useful as views against larger pools of resources.
212 """
213
214 - def __init__(self, config, resources, resource_class):
215 """
216 @param config: NamespaceConfig instance
217 @param resource_class: Class to instantiate to create new
218 resources if resource has not already been created.
219 @type resource_class: Class
220 """
221
222 self._resources = resources
223 self._config = config
224 self._resource_class = resource_class
225
227 return '\n'.join(self._resources)
228
230 """
231 Not thread-safe. If ResourceList is modified during iteration, this will fail
232 """
233 for r in self._resources:
234 yield self._get_entry(r)
235
237 return self._resources
238
240 return self._resources
241
243 if key.startswith('_') or key == 'trait_names':
244 return object.__getattribute__(self, key)
245 else:
246 return self.__getitem__(key)
247
249 if key in self._config.cache:
250 return self._config.cache[key]
251 else:
252 val = self._get_entry(key)
253 return val
254
255 - def _get_entry(self, key):
256
257
258 if not key in self._resources:
259 raise AttributeError(key)
260 cache = self._config.cache
261 with self._config.lock:
262 if key in cache:
263 obj = cache[key]
264 else:
265
266
267 obj = self._resource_class(key, self._config)
268 cache[key] = obj
269 return obj
270
272 """
273 NSResourceList is a constrained version of a Namespace instance and
274 can be used to create a view against a larger Namespace. It can
275 share a config with a Namespace instance.
276 """
277
278 - def __init__(self, name, config, resources, resource_class):
279 self._ns = name + '/'
280
281 self._resources = resources
282 self._config = config
283 self._resource_class = resource_class
284
286 """
287 Change resource list
288 """
289 self._resources = resources
290
292 return '\n'.join([x for x in self._resources if x.startswith(self._ns)])
293
295 return self._resources
296
298 """
299 Not thread-safe. If ResourceList is modified during iteration, this will fail
300 """
301 for r in self._resources:
302 yield self._get_entry(r)
303
305 return list(set([s[len(self._ns):].split('/')[0] for s in self._list()]))
306
308 if key.startswith('_') or key == 'trait_names':
309 return object.__getattribute__(self, key)
310 else:
311 return self.__getitem__(key)
312
314 key = roslib.names.ns_join(self._ns, key)
315
316
317
318
319 if key in self._resources and key in self._config.cache:
320 return self._config.cache[key]
321 else:
322 val = self._get_entry(key)
323 return val
324
325 - def _get_entry(self, key):
326
327
328 res = self._resources
329 cache = self._config.cache
330 with self._config.lock:
331 if key in res:
332 if key in cache:
333 obj = cache[key]
334 else:
335
336 obj = self._resource_class(key, self._config)
337 cache[key] = obj
338 else:
339
340
341
342
343 if any(r for r in res if r.startswith(key+'/')):
344 obj = self.__class__(key, self._config, res, self._resource_class)
345 else:
346
347 return None
348 return obj
349
350
352 """
353 Get or set the ROS type of an object. This is generally associated
354 with Namespace instances that have associated types.
355
356 @param type_: (optional) set type of object to type_, if possible
357 @raise TypeError: if type_ is not of the correct type
358 @raise ROSHException: if type cannot be set
359 """
360 if type_ is None:
361 if hasattr(ns_obj, '_get_type'):
362 return ns_obj._get_type()
363 else:
364 raise ROSHException("object has no ROS type")
365 else:
366 if hasattr(ns_obj, '_set_type'):
367 ns_obj._set_type(type_)
368 else:
369 raise ROSHException("object has no ROS type")
370
371
373 if hasattr(ns_obj, '_info'):
374 return ns_obj._info()
375 else:
376 raise ROSHException("object not not support _info")
377