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: names.py 11774 2010-10-26 01:58:00Z kwc $ 
 34   
 35  """ 
 36  Library for manipulating ROS Names. See U{http://ros.org/wiki/Names}. 
 37  """ 
 38   
 39  import os 
 40  import sys 
 41   
 42  import roslib.exceptions 
 43  from roslib.rosenv import ROS_NAMESPACE 
 44   
 45  #TODO: why are these here? 
 46  MSG_EXT = '.msg' 
 47  SRV_EXT = '.srv' 
 48   
 49  #TODO: deprecate PRN_SEPARATOR 
 50  PRN_SEPARATOR = '/' 
 51  TYPE_SEPARATOR = PRN_SEPARATOR #alias 
 52  SEP = '/' 
 53  GLOBALNS = '/' 
 54  PRIV_NAME = '~' 
 55  REMAP = ":=" 
 56  ANYTYPE = '*' 
 57   
58 -def get_ros_namespace(env=None, argv=None):
59 """ 60 @param env: environment dictionary (defaults to os.environ) 61 @type env: dict 62 @param argv: command-line arguments (defaults to sys.argv) 63 @type argv: [str] 64 @return: ROS namespace of current program 65 @rtype: str 66 """ 67 #we force command-line-specified namespaces to be globally scoped 68 if argv is None: 69 argv = sys.argv 70 for a in argv: 71 if a.startswith('__ns:='): 72 return make_global_ns(a[len('__ns:='):]) 73 if env is None: 74 env = os.environ 75 return make_global_ns(env.get(ROS_NAMESPACE, GLOBALNS))
76
77 -def make_caller_id(name):
78 """ 79 Resolve a local name to the caller ID based on ROS environment settings (i.e. ROS_NAMESPACE) 80 81 @param name: local name to calculate caller ID from, e.g. 'camera', 'node' 82 @type name: str 83 @return: caller ID based on supplied local name 84 @rtype: str 85 """ 86 return make_global_ns(ns_join(get_ros_namespace(), name))
87
88 -def make_global_ns(name):
89 """ 90 Convert name to a global name with a trailing namespace separator. 91 92 @param name: ROS resource name. Cannot be a ~name. 93 @type name: str 94 @return str: name as a global name, e.g. 'foo' -> '/foo/'. 95 This does NOT resolve a name. 96 @rtype: str 97 @raise ValueError: if name is a ~name 98 """ 99 if is_private(name): 100 raise ValueError("cannot turn [%s] into a global name"%name) 101 if not is_global(name): 102 name = SEP + name 103 if name[-1] != SEP: 104 name = name + SEP 105 return name
106
107 -def is_global(name):
108 """ 109 Test if name is a global graph resource name. 110 111 @param name: must be a legal name in canonical form 112 @type name: str 113 @return: True if name is a globally referenced name (i.e. /ns/name) 114 @rtype: bool 115 """ 116 return name and name[0] == SEP
117
118 -def is_private(name):
119 """ 120 Test if name is a private graph resource name. 121 122 @param name: must be a legal name in canonical form 123 @type name: str 124 @return bool: True if name is a privately referenced name (i.e. ~name) 125 """ 126 return name and name[0] == PRIV_NAME
127
128 -def namespace(name):
129 """ 130 Get the namespace of name. The namespace is returned with a 131 trailing slash in order to favor easy concatenation and easier use 132 within the global context. 133 134 @param name: name to return the namespace of. Must be a legal 135 name. NOTE: an empty name will return the global namespace. 136 @type name: str 137 @return str: Namespace of name. For example, '/wg/node1' returns '/wg/'. The 138 global namespace is '/'. 139 @rtype: str 140 @raise ValueError: if name is invalid 141 """ 142 "map name to its namespace" 143 if name is None: 144 raise ValueError('name') 145 if not isinstance(name, basestring): 146 raise TypeError('name') 147 if not name: 148 return SEP 149 elif name[-1] == SEP: 150 name = name[:-1] 151 return name[:name.rfind(SEP)+1] or SEP
152
153 -def ns_join(ns, name):
154 """ 155 Join a namespace and name. If name is unjoinable (i.e. ~private or 156 /global) it will be returned without joining 157 158 @param ns: namespace ('/' and '~' are both legal). If ns is the empty string, name will be returned. 159 @type ns: str 160 @param name str: a legal name 161 @return str: name concatenated to ns, or name if it is 162 unjoinable. 163 @rtype: str 164 """ 165 if is_private(name) or is_global(name): 166 return name 167 if ns == PRIV_NAME: 168 return PRIV_NAME + name 169 if not ns: 170 return name 171 if ns[-1] == SEP: 172 return ns + name 173 return ns + SEP + name
174
175 -def load_mappings(argv):
176 """ 177 Load name mappings encoded in command-line arguments. This will filter 178 out any parameter assignment mappings (see roslib.param.load_param_mappings()). 179 180 @param argv: command-line arguments 181 @type argv: [str] 182 @return: name->name remappings. 183 @rtype: dict {str: str} 184 """ 185 mappings = {} 186 for arg in argv: 187 if REMAP in arg: 188 try: 189 src, dst = [x.strip() for x in arg.split(REMAP)] 190 if src and dst: 191 if len(src) > 1 and src[0] == '_' and src[1] != '_': 192 #ignore parameter assignment mappings 193 pass 194 else: 195 mappings[src] = dst 196 except: 197 print >> sys.stderr, "ERROR: Invalid remapping argument '%s'"%arg 198 return mappings
199 200 ####################################################################### 201 # RESOURCE NAMES 202 # resource names refer to entities in a file system 203
204 -def resource_name(res_pkg_name, name, my_pkg=None):
205 """ 206 Convert package name + resource into a fully qualified resource name 207 208 @param res_pkg_name: name of package resource is located in 209 @type res_pkg_name: str 210 @param name: resource base name 211 @type name: str 212 @param my_pkg: name of package resource is being referred to 213 in. If specified, name will be returned in local form if 214 res_pkg_name is my_pkg 215 @type my_pkg: str 216 @return: name for resource 217 @rtype: str 218 """ 219 if res_pkg_name != my_pkg: 220 return res_pkg_name+PRN_SEPARATOR+name 221 return name
222
223 -def resource_name_base(name):
224 """ 225 pkg/typeName -> typeName, typeName -> typeName 226 227 Convert fully qualified resource name into the package-less resource name 228 @param name: package resource name, e.g. 'std_msgs/String' 229 @type name: str 230 @return: resource name sans package-name scope 231 @rtype: str 232 """ 233 234 return name[name.rfind(PRN_SEPARATOR)+1:]
235
236 -def resource_name_package(name):
237 """ 238 pkg/typeName -> pkg, typeName -> None 239 240 @param name: package resource name, e.g. 'std_msgs/String' 241 @type name: str 242 @return: package name of resource 243 @rtype: str 244 """ 245 246 if not PRN_SEPARATOR in name: 247 return None 248 return name[:name.find(PRN_SEPARATOR)]
249
250 -def package_resource_name(name):
251 """ 252 Split a name into its package and resource name parts, e.g. 'std_msgs/String -> std_msgs, String' 253 254 @param name: package resource name, e.g. 'std_msgs/String' 255 @type name: str 256 @return: package name, resource name 257 @rtype: str 258 @raise ValueError: if name is invalid 259 """ 260 if PRN_SEPARATOR in name: 261 val = tuple(name.split(PRN_SEPARATOR)) 262 if len(val) != 2: 263 raise ValueError("invalid name [%s]"%name) 264 else: 265 return val 266 else: 267 return '', name
268
269 -def _is_safe_name(name, type_name):
270 #windows long-file name length is 255 271 if not isinstance(name, basestring) or not name or len(name) > 255: 272 return False 273 return is_legal_resource_name(name)
274 275 ################################################################################ 276 # NAME VALIDATORS 277 278 import re 279 #ascii char followed by (alphanumeric, _, /) 280 RESOURCE_NAME_LEGAL_CHARS_P = re.compile('^[A-Za-z][\w_\/]*$') 297 298 #~,/, or ascii char followed by (alphanumeric, _, /) 299 NAME_LEGAL_CHARS_P = re.compile('^[\~\/A-Za-z][\w_\/]*$') 318 319 BASE_NAME_LEGAL_CHARS_P = re.compile('^[A-Za-z][\w_]*$') #ascii char followed by (alphanumeric, _) 329 330 BASE_RESOURCE_NAME_LEGAL_CHARS_P = re.compile('^[A-Za-z][\w_]*$') #ascii char followed by (alphanumeric, _) 341
342 -def canonicalize_name(name):
343 """ 344 Put name in canonical form. Extra slashes '//' are removed and 345 name is returned without any trailing slash, e.g. /foo/bar 346 @param name: ROS name 347 @type name: str 348 """ 349 if not name or name == SEP: 350 return name 351 elif name[0] == SEP: 352 return '/' + '/'.join([x for x in name.split(SEP) if x]) 353 else: 354 return '/'.join([x for x in name.split(SEP) if x])
355
356 -def resolve_name(name, namespace_, remappings=None):
357 """ 358 Resolve a ROS name to its global, canonical form. Private ~names 359 are resolved relative to the node name. 360 361 @param name: name to resolve. 362 @type name: str 363 @param namespace_: node name to resolve relative to. 364 @type namespace_: str 365 @param remappings: Map of resolved remappings. Use None to indicate no remapping. 366 @return: Resolved name. If name is empty/None, resolve_name 367 returns parent namespace_. If namespace_ is empty/None, 368 @rtype: str 369 """ 370 if not name: #empty string resolves to parent of the namespace_ 371 return namespace(namespace_) 372 373 name = canonicalize_name(name) 374 if name[0] == SEP: #global name 375 resolved_name = name 376 elif is_private(name): #~name 377 # #3044: be careful not to accidentally make rest of name global 378 resolved_name = canonicalize_name(namespace_ + SEP + name[1:]) 379 else: #relative 380 resolved_name = namespace(namespace_) + name 381 382 #Mappings override general namespace-based resolution 383 # - do this before canonicalization as remappings are meant to 384 # match the name as specified in the code 385 if remappings and resolved_name in remappings: 386 return remappings[resolved_name] 387 else: 388 return resolved_name
389
390 -def anonymous_name(id):
391 """ 392 Generate a ROS-legal 'anonymous' name 393 394 @param id: prefix for anonymous name 395 @type id: str 396 """ 397 import socket, random 398 name = "%s_%s_%s_%s"%(id, socket.gethostname(), os.getpid(), random.randint(0, sys.maxint)) 399 # RFC 952 allows hyphens, IP addrs can have '.'s, both 400 # of which are illegal for ROS names. For good 401 # measure, screen ipv6 ':'. 402 name = name.replace('.', '_') 403 name = name.replace('-', '_') 404 return name.replace(':', '_')
405