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 """
36 Warning: do not use this library. It is unstable and most of the routines
37 here have been superceded by other libraries (e.g. genmsg). These
38 routines will likely be *deleted* in future releases.
39 """
40
41 import os
42 import sys
43
44
45 PRN_SEPARATOR = '/'
46 TYPE_SEPARATOR = PRN_SEPARATOR
47 SEP = '/'
48 GLOBALNS = '/'
49 PRIV_NAME = '~'
50 REMAP = ":="
51 ANYTYPE = '*'
52
53 if sys.hexversion > 0x03000000:
55 return isinstance(s, str)
56 else:
58 """
59 Small helper version to check an object is a string in a way that works
60 for both Python 2 and 3
61 """
62 return isinstance(s, basestring)
63
65 """
66 @param env: environment dictionary (defaults to os.environ)
67 @type env: dict
68 @param argv: command-line arguments (defaults to sys.argv)
69 @type argv: [str]
70 @return: ROS namespace of current program
71 @rtype: str
72 """
73
74 if argv is None:
75 argv = sys.argv
76 for a in argv:
77 if a.startswith('__ns:='):
78 return make_global_ns(a[len('__ns:='):])
79 if env is None:
80 env = os.environ
81 return make_global_ns(env.get('ROS_NAMESPACE', GLOBALNS))
82
84 """
85 Resolve a local name to the caller ID based on ROS environment settings (i.e. ROS_NAMESPACE)
86
87 @param name: local name to calculate caller ID from, e.g. 'camera', 'node'
88 @type name: str
89 @return: caller ID based on supplied local name
90 @rtype: str
91 """
92 return make_global_ns(ns_join(get_ros_namespace(), name))
93
95 """
96 Convert name to a global name with a trailing namespace separator.
97
98 @param name: ROS resource name. Cannot be a ~name.
99 @type name: str
100 @return str: name as a global name, e.g. 'foo' -> '/foo/'.
101 This does NOT resolve a name.
102 @rtype: str
103 @raise ValueError: if name is a ~name
104 """
105 if is_private(name):
106 raise ValueError("cannot turn [%s] into a global name"%name)
107 if not is_global(name):
108 name = SEP + name
109 if name[-1] != SEP:
110 name = name + SEP
111 return name
112
114 """
115 Test if name is a global graph resource name.
116
117 @param name: must be a legal name in canonical form
118 @type name: str
119 @return: True if name is a globally referenced name (i.e. /ns/name)
120 @rtype: bool
121 """
122 return name and name[0] == SEP
123
125 """
126 Test if name is a private graph resource name.
127
128 @param name: must be a legal name in canonical form
129 @type name: str
130 @return bool: True if name is a privately referenced name (i.e. ~name)
131 """
132 return name and name[0] == PRIV_NAME
133
135 """
136 Get the namespace of name. The namespace is returned with a
137 trailing slash in order to favor easy concatenation and easier use
138 within the global context.
139
140 @param name: name to return the namespace of. Must be a legal
141 name. NOTE: an empty name will return the global namespace.
142 @type name: str
143 @return str: Namespace of name. For example, '/wg/node1' returns '/wg/'. The
144 global namespace is '/'.
145 @rtype: str
146 @raise ValueError: if name is invalid
147 """
148 "map name to its namespace"
149 if name is None:
150 raise ValueError('name')
151 if not isstring(name):
152 raise TypeError('name')
153 if not name:
154 return SEP
155 elif name[-1] == SEP:
156 name = name[:-1]
157 return name[:name.rfind(SEP)+1] or SEP
158
160 """
161 Join a namespace and name. If name is unjoinable (i.e. ~private or
162 /global) it will be returned without joining
163
164 @param ns: namespace ('/' and '~' are both legal). If ns is the empty string, name will be returned.
165 @type ns: str
166 @param name str: a legal name
167 @return str: name concatenated to ns, or name if it is
168 unjoinable.
169 @rtype: str
170 """
171 if is_private(name) or is_global(name):
172 return name
173 if ns == PRIV_NAME:
174 return PRIV_NAME + name
175 if not ns:
176 return name
177 if ns[-1] == SEP:
178 return ns + name
179 return ns + SEP + name
180
182 """
183 Load name mappings encoded in command-line arguments. This will filter
184 out any parameter assignment mappings (see roslib.param.load_param_mappings()).
185
186 @param argv: command-line arguments
187 @type argv: [str]
188 @return: name->name remappings.
189 @rtype: dict {str: str}
190 """
191 mappings = {}
192 for arg in argv:
193 if REMAP in arg:
194 try:
195 src, dst = [x.strip() for x in arg.split(REMAP)]
196 if src and dst:
197 if len(src) > 1 and src[0] == '_' and src[1] != '_':
198
199 pass
200 else:
201 mappings[src] = dst
202 except:
203 sys.stderr.write("ERROR: Invalid remapping argument '%s'\n"%arg)
204 return mappings
205
206
207
208
209
211 """
212 Convert package name + resource into a fully qualified resource name
213
214 @param res_pkg_name: name of package resource is located in
215 @type res_pkg_name: str
216 @param name: resource base name
217 @type name: str
218 @param my_pkg: name of package resource is being referred to
219 in. If specified, name will be returned in local form if
220 res_pkg_name is my_pkg
221 @type my_pkg: str
222 @return: name for resource
223 @rtype: str
224 """
225 if res_pkg_name != my_pkg:
226 return res_pkg_name+PRN_SEPARATOR+name
227 return name
228
230 """
231 pkg/typeName -> typeName, typeName -> typeName
232
233 Convert fully qualified resource name into the package-less resource name
234 @param name: package resource name, e.g. 'std_msgs/String'
235 @type name: str
236 @return: resource name sans package-name scope
237 @rtype: str
238 """
239
240 return name[name.rfind(PRN_SEPARATOR)+1:]
241
243 """
244 pkg/typeName -> pkg, typeName -> None
245
246 @param name: package resource name, e.g. 'std_msgs/String'
247 @type name: str
248 @return: package name of resource
249 @rtype: str
250 """
251
252 if not PRN_SEPARATOR in name:
253 return None
254 return name[:name.find(PRN_SEPARATOR)]
255
257 """
258 Split a name into its package and resource name parts, e.g. 'std_msgs/String -> std_msgs, String'
259
260 @param name: package resource name, e.g. 'std_msgs/String'
261 @type name: str
262 @return: package name, resource name
263 @rtype: str
264 @raise ValueError: if name is invalid
265 """
266 if PRN_SEPARATOR in name:
267 val = tuple(name.split(PRN_SEPARATOR))
268 if len(val) != 2:
269 raise ValueError("invalid name [%s]"%name)
270 else:
271 return val
272 else:
273 return '', name
274
276
277 if not isstring(name) or not name or len(name) > 255:
278 return False
279 return is_legal_resource_name(name)
280
281
282
283
284 import re
285
286 RESOURCE_NAME_LEGAL_CHARS_P = re.compile('^[A-Za-z][\w_\/]*$')
288 """
289 Check if name is a legal ROS name for filesystem resources
290 (alphabetical character followed by alphanumeric, underscore, or
291 forward slashes). This constraint is currently not being enforced,
292 but may start getting enforced in later versions of ROS.
293
294 @param name: Name
295 @type name: str
296 """
297
298 if name is None:
299 return False
300 m = RESOURCE_NAME_LEGAL_CHARS_P.match(name)
301
302 return m is not None and m.group(0) == name and not '//' in name
303
304
305 NAME_LEGAL_CHARS_P = re.compile('^[\~\/A-Za-z][\w_\/]*$')
307 """
308 Check if name is a legal ROS name for graph resources
309 (alphabetical character followed by alphanumeric, underscore, or
310 forward slashes). This constraint is currently not being enforced,
311 but may start getting enforced in later versions of ROS.
312
313 @param name: Name
314 @type name: str
315 """
316
317 if name is None:
318 return False
319
320 if name == '':
321 return True
322 m = NAME_LEGAL_CHARS_P.match(name)
323 return m is not None and m.group(0) == name and not '//' in name
324
325 BASE_NAME_LEGAL_CHARS_P = re.compile('^[A-Za-z][\w_]*$')
327 """
328 Validates that name is a legal base name for a graph resource. A base name has
329 no namespace context, e.g. "node_name".
330 """
331 if name is None:
332 return False
333 m = BASE_NAME_LEGAL_CHARS_P.match(name)
334 return m is not None and m.group(0) == name
335
336 BASE_RESOURCE_NAME_LEGAL_CHARS_P = re.compile('^[A-Za-z][\w_]*$')
338 """
339 Validates that name is a legal resource base name. A base name has
340 no package context, e.g. "String".
341 """
342
343 if name is None:
344 return False
345 m = BASE_NAME_LEGAL_CHARS_P.match(name)
346 return m is not None and m.group(0) == name
347
349 """
350 Put name in canonical form. Extra slashes '//' are removed and
351 name is returned without any trailing slash, e.g. /foo/bar
352 @param name: ROS name
353 @type name: str
354 """
355 if not name or name == SEP:
356 return name
357 elif name[0] == SEP:
358 return '/' + '/'.join([x for x in name.split(SEP) if x])
359 else:
360 return '/'.join([x for x in name.split(SEP) if x])
361
363 """
364 Resolve a ROS name to its global, canonical form. Private ~names
365 are resolved relative to the node name.
366
367 @param name: name to resolve.
368 @type name: str
369 @param namespace_: node name to resolve relative to.
370 @type namespace_: str
371 @param remappings: Map of resolved remappings. Use None to indicate no remapping.
372 @return: Resolved name. If name is empty/None, resolve_name
373 returns parent namespace_. If namespace_ is empty/None,
374 @rtype: str
375 """
376 if not name:
377 return namespace(namespace_)
378
379 name = canonicalize_name(name)
380 if name[0] == SEP:
381 resolved_name = name
382 elif is_private(name):
383
384 resolved_name = canonicalize_name(namespace_ + SEP + name[1:])
385 else:
386 resolved_name = namespace(namespace_) + name
387
388
389
390
391 if remappings and resolved_name in remappings:
392 return remappings[resolved_name]
393 else:
394 return resolved_name
395
397 """
398 Generate a ROS-legal 'anonymous' name
399
400 @param id: prefix for anonymous name
401 @type id: str
402 """
403 import socket, random
404 name = "%s_%s_%s_%s"%(id, socket.gethostname(), os.getpid(), random.randint(0, sys.maxsize))
405
406
407
408 name = name.replace('.', '_')
409 name = name.replace('-', '_')
410 return name.replace(':', '_')
411