Package roslib :: Module names
[frames] | no frames]

Source Code for Module roslib.names

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2008, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  # 
 33  # Revision $Id$ 
 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 re 
 43  import sys 
 44   
 45  # TODO: deprecate PRN_SEPARATOR 
 46  PRN_SEPARATOR = '/' 
 47  TYPE_SEPARATOR = PRN_SEPARATOR  # alias 
 48  SEP = '/' 
 49  GLOBALNS = '/' 
 50  PRIV_NAME = '~' 
 51  REMAP = ':=' 
 52  ANYTYPE = '*' 
 53   
 54  if sys.hexversion > 0x03000000:  # Python3 
55 - def isstring(s):
56 return isinstance(s, str) # Python 3.x
57 else:
58 - def isstring(s):
59 """ 60 Small helper version to check an object is a string in a way that works 61 for both Python 2 and 3 62 """ 63 return isinstance(s, basestring) # Python 2.x
64 65
66 -def get_ros_namespace(env=None, argv=None):
67 """ 68 @param env: environment dictionary (defaults to os.environ) 69 @type env: dict 70 @param argv: command-line arguments (defaults to sys.argv) 71 @type argv: [str] 72 @return: ROS namespace of current program 73 @rtype: str 74 """ 75 # we force command-line-specified namespaces to be globally scoped 76 if argv is None: 77 argv = sys.argv 78 for a in argv: 79 if a.startswith('__ns:='): 80 return make_global_ns(a[len('__ns:='):]) 81 if env is None: 82 env = os.environ 83 return make_global_ns(env.get('ROS_NAMESPACE', GLOBALNS))
84 85
86 -def make_caller_id(name):
87 """ 88 Resolve a local name to the caller ID based on ROS environment settings (i.e. ROS_NAMESPACE) 89 90 @param name: local name to calculate caller ID from, e.g. 'camera', 'node' 91 @type name: str 92 @return: caller ID based on supplied local name 93 @rtype: str 94 """ 95 return make_global_ns(ns_join(get_ros_namespace(), name))
96 97
98 -def make_global_ns(name):
99 """ 100 Convert name to a global name with a trailing namespace separator. 101 102 @param name: ROS resource name. Cannot be a ~name. 103 @type name: str 104 @return str: name as a global name, e.g. 'foo' -> '/foo/'. 105 This does NOT resolve a name. 106 @rtype: str 107 @raise ValueError: if name is a ~name 108 """ 109 if is_private(name): 110 raise ValueError('cannot turn [%s] into a global name' % name) 111 if not is_global(name): 112 name = SEP + name 113 if name[-1] != SEP: 114 name = name + SEP 115 return name
116 117
118 -def is_global(name):
119 """ 120 Test if name is a global graph resource name. 121 122 @param name: must be a legal name in canonical form 123 @type name: str 124 @return: True if name is a globally referenced name (i.e. /ns/name) 125 @rtype: bool 126 """ 127 return name and name[0] == SEP
128 129
130 -def is_private(name):
131 """ 132 Test if name is a private graph resource name. 133 134 @param name: must be a legal name in canonical form 135 @type name: str 136 @return bool: True if name is a privately referenced name (i.e. ~name) 137 """ 138 return name and name[0] == PRIV_NAME
139 140
141 -def namespace(name):
142 """ 143 Get the namespace of name. The namespace is returned with a 144 trailing slash in order to favor easy concatenation and easier use 145 within the global context. 146 147 @param name: name to return the namespace of. Must be a legal 148 name. NOTE: an empty name will return the global namespace. 149 @type name: str 150 @return str: Namespace of name. For example, '/wg/node1' returns '/wg/'. The 151 global namespace is '/'. 152 @rtype: str 153 @raise ValueError: if name is invalid 154 """ 155 'map name to its namespace' 156 if name is None: 157 raise ValueError('name') 158 if not isstring(name): 159 raise TypeError('name') 160 if not name: 161 return SEP 162 elif name[-1] == SEP: 163 name = name[:-1] 164 return name[:name.rfind(SEP)+1] or SEP
165 166
167 -def ns_join(ns, name):
168 """ 169 Join a namespace and name. If name is unjoinable (i.e. ~private or 170 /global) it will be returned without joining 171 172 @param ns: namespace ('/' and '~' are both legal). If ns is the empty string, name will be returned. 173 @type ns: str 174 @param name str: a legal name 175 @return str: name concatenated to ns, or name if it is 176 unjoinable. 177 @rtype: str 178 """ 179 if is_private(name) or is_global(name): 180 return name 181 if ns == PRIV_NAME: 182 return PRIV_NAME + name 183 if not ns: 184 return name 185 if ns[-1] == SEP: 186 return ns + name 187 return ns + SEP + name
188 189
190 -def load_mappings(argv):
191 """ 192 Load name mappings encoded in command-line arguments. This will filter 193 out any parameter assignment mappings (see roslib.param.load_param_mappings()). 194 195 @param argv: command-line arguments 196 @type argv: [str] 197 @return: name->name remappings. 198 @rtype: dict {str: str} 199 """ 200 mappings = {} 201 for arg in argv: 202 if REMAP in arg: 203 try: 204 src, dst = [x.strip() for x in arg.split(REMAP)] 205 if src and dst: 206 if len(src) > 1 and src[0] == '_' and src[1] != '_': 207 # ignore parameter assignment mappings 208 pass 209 else: 210 mappings[src] = dst 211 except Exception: 212 sys.stderr.write("ERROR: Invalid remapping argument '%s'\n" % arg) 213 return mappings
214 215 216 ####################################################################### 217 # RESOURCE NAMES 218 # resource names refer to entities in a file system 219
220 -def resource_name(res_pkg_name, name, my_pkg=None):
221 """ 222 Convert package name + resource into a fully qualified resource name 223 224 @param res_pkg_name: name of package resource is located in 225 @type res_pkg_name: str 226 @param name: resource base name 227 @type name: str 228 @param my_pkg: name of package resource is being referred to 229 in. If specified, name will be returned in local form if 230 res_pkg_name is my_pkg 231 @type my_pkg: str 232 @return: name for resource 233 @rtype: str 234 """ 235 if res_pkg_name != my_pkg: 236 return res_pkg_name+PRN_SEPARATOR+name 237 return name
238 239
240 -def resource_name_base(name):
241 """ 242 pkg/typeName -> typeName, typeName -> typeName 243 244 Convert fully qualified resource name into the package-less resource name 245 @param name: package resource name, e.g. 'std_msgs/String' 246 @type name: str 247 @return: resource name sans package-name scope 248 @rtype: str 249 """ 250 251 return name[name.rfind(PRN_SEPARATOR)+1:]
252 253
254 -def resource_name_package(name):
255 """ 256 pkg/typeName -> pkg, typeName -> None 257 258 @param name: package resource name, e.g. 'std_msgs/String' 259 @type name: str 260 @return: package name of resource 261 @rtype: str 262 """ 263 264 if PRN_SEPARATOR not in name: 265 return None 266 return name[:name.find(PRN_SEPARATOR)]
267 268
269 -def package_resource_name(name):
270 """ 271 Split a name into its package and resource name parts, e.g. 'std_msgs/String -> std_msgs, String' 272 273 @param name: package resource name, e.g. 'std_msgs/String' 274 @type name: str 275 @return: package name, resource name 276 @rtype: str 277 @raise ValueError: if name is invalid 278 """ 279 if PRN_SEPARATOR in name: 280 val = tuple(name.split(PRN_SEPARATOR)) 281 if len(val) != 2: 282 raise ValueError('invalid name [%s]' % name) 283 else: 284 return val 285 else: 286 return '', name
287 288
289 -def _is_safe_name(name, type_name):
290 # windows long-file name length is 255 291 if not isstring(name) or not name or len(name) > 255: 292 return False 293 return is_legal_resource_name(name)
294 295 296 ################################################################################ 297 # NAME VALIDATORS 298 299 # ascii char followed by (alphanumeric, _, /) 300 RESOURCE_NAME_LEGAL_CHARS_P = re.compile(r'^[A-Za-z][\w_\/]*$') 301 302 319 320 321 # ~,/, or ascii char followed by (alphanumeric, _, /) 322 NAME_LEGAL_CHARS_P = re.compile(r'^[\~\/A-Za-z][\w_\/]*$') 323 324 343 344 345 BASE_NAME_LEGAL_CHARS_P = re.compile(r'^[A-Za-z][\w_]*$') # ascii char followed by (alphanumeric, _) 346 347 357 358 359 BASE_RESOURCE_NAME_LEGAL_CHARS_P = re.compile(r'^[A-Za-z][\w_]*$') # ascii char followed by (alphanumeric, _) 360 361 372 373
374 -def canonicalize_name(name):
375 """ 376 Put name in canonical form. Extra slashes '//' are removed and 377 name is returned without any trailing slash, e.g. /foo/bar 378 @param name: ROS name 379 @type name: str 380 """ 381 if not name or name == SEP: 382 return name 383 elif name[0] == SEP: 384 return '/' + '/'.join([x for x in name.split(SEP) if x]) 385 else: 386 return '/'.join([x for x in name.split(SEP) if x])
387 388
389 -def resolve_name(name, namespace_, remappings=None):
390 """ 391 Resolve a ROS name to its global, canonical form. Private ~names 392 are resolved relative to the node name. 393 394 @param name: name to resolve. 395 @type name: str 396 @param namespace_: node name to resolve relative to. 397 @type namespace_: str 398 @param remappings: Map of resolved remappings. Use None to indicate no remapping. 399 @return: Resolved name. If name is empty/None, resolve_name 400 returns parent namespace_. If namespace_ is empty/None, 401 @rtype: str 402 """ 403 if not name: # empty string resolves to parent of the namespace_ 404 return namespace(namespace_) 405 406 name = canonicalize_name(name) 407 if name[0] == SEP: # global name 408 resolved_name = name 409 elif is_private(name): # ~name 410 # #3044: be careful not to accidentally make rest of name global 411 resolved_name = canonicalize_name(namespace_ + SEP + name[1:]) 412 else: # relative 413 resolved_name = namespace(namespace_) + name 414 415 # Mappings override general namespace-based resolution 416 # - do this before canonicalization as remappings are meant to 417 # match the name as specified in the code 418 if remappings and resolved_name in remappings: 419 return remappings[resolved_name] 420 else: 421 return resolved_name
422 423
424 -def anonymous_name(id):
425 """ 426 Generate a ROS-legal 'anonymous' name 427 428 @param id: prefix for anonymous name 429 @type id: str 430 """ 431 import random 432 import socket 433 name = '%s_%s_%s_%s' % (id, socket.gethostname(), os.getpid(), random.randint(0, sys.maxsize)) 434 # RFC 952 allows hyphens, IP addrs can have '.'s, both 435 # of which are illegal for ROS names. For good 436 # measure, screen ipv6 ':'. 437 name = name.replace('.', '_') 438 name = name.replace('-', '_') 439 return name.replace(':', '_')
440