Package rospy :: Module names

Source Code for Module rospy.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 10179 2010-06-29 00:13:48Z kwc $ 
 34   
 35  """ 
 36  Support for ROS Names 
 37   
 38  See: U{http://www.ros.org/wiki/Names} 
 39  """ 
 40   
 41  import sys 
 42  import os 
 43  from itertools import ifilter 
 44   
 45  from roslib.names import namespace, get_ros_namespace, ns_join, make_global_ns, load_mappings, \ 
 46       SEP, GLOBALNS, TYPE_SEPARATOR, REMAP, ANYTYPE, \ 
 47       is_global, is_private 
 48  import roslib.names 
 49   
 50  from rospy.exceptions import ROSException 
 51  from rospy.impl.validators import ParameterInvalid 
 52   
 53  TOPIC_ANYTYPE = ANYTYPE #indicates that a subscriber will connect any datatype given to it 
 54  SERVICE_ANYTYPE = ANYTYPE #indicates that a service client does not have a fixed type 
 55   
56 -def canonicalize_name(name):
57 """ 58 Put name in canonical form. Double slashes '//' are removed and 59 name is returned without any trailing slash, e.g. /foo/bar 60 @param name: ROS name 61 @type name: str 62 """ 63 if not name or name == SEP: 64 return name 65 elif name[0] == SEP: 66 return '/' + '/'.join([x for x in name.split(SEP) if x]) 67 else: 68 return '/'.join([x for x in name.split(SEP) if x])
69 ##if len(name) > 1 and name[-1] == SEP: 70 ## return name[:-1] 71 ##return name 72 73 # Mappings override name resolution by substituting fully-qualified 74 # names in for local name references. They override any name 75 # reference, with exception of '.local' names. We load remapping args 76 # as soon as client API is referenced so that they are initialized 77 # before Topic constructors are invoked. 78 _mappings = load_mappings(sys.argv) 79 _resolved_mappings = {} 80
81 -def reload_mappings(argv):
82 """ 83 Re-initialize the name remapping table. 84 85 @param argv: Command line arguments to this program. ROS reads 86 these arguments to find renaming params. 87 @type argv: [str] 88 """ 89 global _mappings 90 _mappings = load_mappings(argv)
91 92 # #1810
93 -def initialize_mappings(node_name):
94 """ 95 Initialize the remapping table based on provide node name. 96 97 @param node_name: name of node (caller ID) 98 @type node_name: str 99 """ 100 global _resolved_mappings 101 _resolved_mappings = {} 102 for m,v in _mappings.iteritems(): 103 # resolve both parts of the mappings. use the roslib.names 104 # version of resolve_name to avoid circular mapping. 105 if m.startswith('__'): # __name, __log, etc... 106 _resolved_mappings[m] = v 107 else: 108 _resolved_mappings[roslib.names.resolve_name(m, node_name)] = roslib.names.resolve_name(v, node_name)
109
110 -def resolve_name_without_node_name(name):
111 """ 112 The need for this function is complicated -- Topics and Services can be created before init_node is called. 113 In general, this is okay, unless the name is a ~name, in which 114 case we have to raise an ValueError 115 116 @param name: ROS name to resolve 117 @type name: str 118 @raise ValueError: if name is a ~name 119 @raise ROSInitException: if name is remapped to a ~name 120 """ 121 if is_private(name): 122 raise ValueError("~name topics cannot be created before init_node() has been called") 123 124 # we use the underlying roslib.names.resolve_name to avoid dependencies on nodename/remappings 125 fake_caller_id = ns_join(get_namespace(), 'node') 126 fake_resolved = roslib.names.resolve_name(name, fake_caller_id) 127 128 for m, v in _mappings.iteritems(): 129 if roslib.names.resolve_name(m, fake_caller_id) == fake_resolved: 130 if is_private(name): 131 raise ROSInitException("due to the way this node is written, %s cannot be remapped to a ~name. \nThe declaration of topics/services must be moved after the call to init_node()"%name) 132 else: 133 return roslib.names.resolve_name(v, fake_caller_id) 134 return fake_resolved
135
136 -def get_mappings():
137 """ 138 Get mapping table with unresolved names 139 140 @return: command-line remappings {name: name} 141 @rtype: {str: str} 142 """ 143 return _mappings
144
145 -def get_resolved_mappings():
146 """ 147 Get mapping table with resolved names 148 149 @return: command-line remappings {name: name} 150 @rtype: {str: str} 151 """ 152 return _resolved_mappings
153 154 #TODO: port to a wrapped call to roslib.names.resolve_name
155 -def resolve_name(name, caller_id=None):
156 """ 157 Resolve a ROS name to its global, canonical form. Private ~names 158 are resolved relative to the node name. 159 160 @param name: name to resolve. 161 @type name: str 162 @param caller_id: node name to resolve relative to. To 163 resolve to local namespace, omit this parameter (or use None) 164 @type caller_id: str 165 @return: Resolved name. If name is empty/None, resolve_name 166 returns parent namespace. If namespace is empty/None, 167 @rtype: str 168 """ 169 if not caller_id: 170 caller_id = get_name() 171 if not name: #empty string resolves to namespace 172 return namespace(caller_id) 173 174 name = canonicalize_name(name) 175 if name[0] == SEP: #global name 176 resolved_name = name 177 elif is_private(name): #~name 178 resolved_name = ns_join(caller_id, name[1:]) 179 else: #relative 180 resolved_name = namespace(caller_id) + name 181 182 #Mappings override general namespace-based resolution 183 # - do this before canonicalization as remappings are meant to 184 # match the name as specified in the code 185 if resolved_name in _resolved_mappings: 186 return _resolved_mappings[resolved_name] 187 else: 188 return resolved_name
189 190
191 -def remap_name(name, caller_id=None, resolved=True):
192 """ 193 Remap a ROS name. This API should be used to instead of 194 resolve_name for APIs in which you don't wish to resolve the name 195 unless it is remapped. 196 @param name: name to remap 197 @type name: str 198 199 @param resolved: if True (default), use resolved names in remappings, which is the standard for ROS. 200 @type resolved: bool 201 202 @return: Remapped name 203 @rtype: str 204 """ 205 if not caller_id: 206 caller_id = get_caller_id() 207 if name in _mappings: 208 return roslib.names.resolve_name(_mappings[name], caller_id) 209 return name
210
211 -def scoped_name(caller_id, name):
212 """ 213 Convert the global caller_id to a relative name within the namespace. For example, for 214 namespace '/foo' and name '/foo/bar/name', the return value will 215 be 'bar/name' 216 217 WARNING: scoped_name does not validate that name is actually within 218 the supplied namespace. 219 @param caller_id: caller ID, in canonical form 220 @type caller_id: str 221 @param name: name to scope 222 @type name: str 223 @return: name scoped to the caller_id's namespace. 224 @rtype: str 225 """ 226 if not is_global(caller_id): 227 raise ROSException("caller_id must be global") 228 return canonicalize_name(name)[len(namespace(caller_id)):]
229 230 231 ################################################### 232 # Name validators ############################ 233 234 #Technically XMLRPC will never send a None, but I don't want to code masterslave.py to be 235 #XML-RPC specific in this way. 236
237 -def valid_name_validator_resolved(param_name, param_value, caller_id):
238 if not param_value or not isinstance(param_value, basestring): 239 raise ParameterInvalid("ERROR: parameter [%s] must be a non-empty string"%param_name) 240 #TODO: actual validation of chars 241 # I added the colon check as the common error will be to send an URI instead of name 242 if ':' in param_value or ' ' in param_value: 243 raise ParameterInvalid("ERROR: parameter [%s] contains illegal chars"%param_name) 244 #don't use our own resolve_name because we do not want to remap 245 return roslib.names.resolve_name(param_value, caller_id, remappings=None)
246 -def valid_name_validator_unresolved(param_name, param_value, caller_id):
247 if not param_value or not isinstance(param_value, basestring): 248 raise ParameterInvalid("ERROR: parameter [%s] must be a non-empty string"%param_name) 249 #TODO: actual validation of chars 250 # I added the colon check as the common error will be to send an URI instead of name 251 if ':' in param_value or ' ' in param_value: 252 raise ParameterInvalid("ERROR: parameter [%s] contains illegal chars"%param_name) 253 return param_value
254
255 -def valid_name(param_name, resolve=True):
256 """ 257 Validator that resolves names and also ensures that they are not empty 258 @param param_name: name 259 @type param_name: str 260 @param resolve: if True/omitted, the name will be resolved to 261 a global form. Otherwise, no resolution occurs. 262 @type resolve: bool 263 @return: resolved parameter value 264 @rtype: str 265 """ 266 def validator(param_value, caller_id): 267 if resolve: 268 return valid_name_validator_resolved(param_name, param_value, caller_id) 269 return valid_name_validator_unresolved(param_name, param_value, caller_id)
270 return validator 271
272 -def global_name(param_name):
273 """ 274 Validator that checks for valid, global graph resource name. 275 @return: parameter value 276 @rtype: str 277 """ 278 def validator(param_value, caller_id): 279 if not param_value or not isinstance(param_value, basestring): 280 raise ParameterInvalid("ERROR: parameter [%s] must be a non-empty string"%param_name) 281 #TODO: actual validation of chars 282 if not is_global(param_value): 283 raise ParameterInvalid("ERROR: parameter [%s] must be a globally referenced name"%param_name) 284 return param_value
285 return validator 286 287 ######################################################### 288 #Global Namespace Routines 289 # - Global state, e.g. singletons and namespace 290 291 _caller_namespace = get_ros_namespace() 292 _caller_id = _caller_namespace+'unnamed' #default for non-node. 293
294 -def get_namespace():
295 """ 296 Get namespace of local node. 297 @return: fully-qualified name of local node or '' if not applicable 298 @rtype: str 299 """ 300 return _caller_namespace
301
302 -def get_name():
303 """ 304 Get fully resolved name of local node. If this is not a node, 305 use empty string 306 @return: fully-qualified name of local node or '' if not applicable 307 @rtype: str 308 """ 309 return _caller_id
310 311 # backwards compatibility 312 get_caller_id = get_name 313
314 -def _set_caller_id(caller_id):
315 """ 316 Internal API. 317 Set the global name (i.e. caller_id) and namespace. Methods can 318 check what the name of the current node is by calling get_caller_id. 319 320 The caller_id is important as it is the first parameter to any API 321 call on a remote node. Invoked by ROSNode constructor 322 @param caller_id: new caller ID 323 @type caller_id: str 324 """ 325 global _caller_id, _caller_namespace 326 _caller_id = caller_id 327 _caller_namespace = namespace(caller_id)
328