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