ros_loader.py
Go to the documentation of this file.
1 import time
2 #!/usr/bin/env python
3 # Software License Agreement (BSD License)
4 #
5 # Copyright (c) 2012, Willow Garage, Inc.
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions
10 # are met:
11 #
12 # * Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # * Redistributions in binary form must reproduce the above
15 # copyright notice, this list of conditions and the following
16 # disclaimer in the documentation and/or other materials provided
17 # with the distribution.
18 # * Neither the name of Willow Garage, Inc. nor the names of its
19 # contributors may be used to endorse or promote products derived
20 # from this software without specific prior written permission.
21 #
22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 # POSSIBILITY OF SUCH DAMAGE.
34 
35 import roslib
36 import rospy
37 
38 from threading import Lock
39 
40 """ ros_loader contains methods for dynamically loading ROS message classes at
41 runtime. It's achieved by using roslib to load the manifest files for the
42 package that the respective class is contained in.
43 
44 Methods typically return the requested class or instance, or None if not found
45 """
46 
47 # Variable containing the loaded classes
48 _loaded_msgs = {}
49 _loaded_srvs = {}
50 _msgs_lock = Lock()
51 _srvs_lock = Lock()
52 _manifest_lock = Lock()
53 
54 
55 class InvalidTypeStringException(Exception):
56  def __init__(self, typestring):
57  Exception.__init__(self, "%s is not a valid type string" % typestring)
58 
59 
60 class InvalidPackageException(Exception):
61  def __init__(self, package, original_exception):
62  Exception.__init__(self,
63  "Unable to load the manifest for package %s. Caused by: %s"
64  % (package, str(original_exception))
65  )
66 
67 
68 class InvalidModuleException(Exception):
69  def __init__(self, modname, subname, original_exception):
70  Exception.__init__(self,
71  "Unable to import %s.%s from package %s. Caused by: %s"
72  % (modname, subname, modname, str(original_exception))
73  )
74 
75 
76 class InvalidClassException(Exception):
77  def __init__(self, modname, subname, classname, original_exception):
78  Exception.__init__(self,
79  "Unable to import %s class %s from package %s. Caused by %s"
80  % (subname, classname, modname, str(original_exception))
81  )
82 
83 
84 def get_message_class(typestring):
85  """ Loads the message type specified.
86 
87  Returns the loaded class, or throws exceptions on failure """
88  return _get_msg_class(typestring)
89 
90 
91 def get_service_class(typestring):
92  """ Loads the service type specified.
93 
94  Returns the loaded class, or None on failure """
95  return _get_srv_class(typestring)
96 
97 
98 def get_message_instance(typestring):
99  """ If not loaded, loads the specified type.
100  Then returns an instance of it, or None. """
101  cls = get_message_class(typestring)
102  return cls()
103 
104 
105 def get_service_instance(typestring):
106  """ If not loaded, loads the specified type.
107  Then returns an instance of it, or None. """
108  cls = get_service_class(typestring)
109  return cls()
110 
111 
113  cls = get_service_class(typestring)
114  return cls._request_class()
115 
116 
118  cls = get_service_class(typestring)
119  return cls._response_class()
120 
121 
122 def _get_msg_class(typestring):
123  """ If not loaded, loads the specified msg class then returns an instance
124  of it
125 
126  Throws various exceptions if loading the msg class fails """
127  global _loaded_msgs, _msgs_lock
128  return _get_class(typestring, "msg", _loaded_msgs, _msgs_lock)
129 
130 
131 def _get_srv_class(typestring):
132  """ If not loaded, loads the specified srv class then returns an instance
133  of it
134 
135  Throws various exceptions if loading the srv class fails """
136  global _loaded_srvs, _srvs_lock
137  return _get_class(typestring, "srv", _loaded_srvs, _srvs_lock)
138 
139 
140 def _get_class(typestring, subname, cache, lock):
141  """ If not loaded, loads the specified class then returns an instance
142  of it.
143 
144  Loaded classes are cached in the provided cache dict
145 
146  Throws various exceptions if loading the msg class fails """
147 
148  # First, see if we have this type string cached
149  cls = _get_from_cache(cache, lock, typestring)
150  if cls is not None:
151  return cls
152 
153  # Now normalise the typestring
154  modname, classname = _splittype(typestring)
155  norm_typestring = modname + "/" + classname
156 
157  # Check to see if the normalised type string is cached
158  cls = _get_from_cache(cache, lock, norm_typestring)
159  if cls is not None:
160  return cls
161 
162  # Load the class
163  cls = _load_class(modname, subname, classname)
164 
165  # Cache the class for both the regular and normalised typestring
166  _add_to_cache(cache, lock, typestring, cls)
167  _add_to_cache(cache, lock, norm_typestring, cls)
168 
169  return cls
170 
171 
172 def _load_class(modname, subname, classname):
173  """ Loads the manifest and imports the module that contains the specified
174  type.
175 
176  Logic is similar to that of roslib.message.get_message_class, but we want
177  more expressive exceptions.
178 
179  Returns the loaded module, or None on failure """
180  global loaded_modules
181 
182  try:
183  with _manifest_lock:
184  # roslib maintains a cache of loaded manifests, so no need to duplicate
185  roslib.launcher.load_manifest(modname)
186  except Exception as exc:
187  raise InvalidPackageException(modname, exc)
188 
189  try:
190  pypkg = __import__('%s.%s' % (modname, subname))
191  except Exception as exc:
192  raise InvalidModuleException(modname, subname, exc)
193 
194  try:
195  return getattr(getattr(pypkg, subname), classname)
196  except Exception as exc:
197  raise InvalidClassException(modname, subname, classname, exc)
198 
199 
200 def _splittype(typestring):
201  """ Split the string the / delimiter and strip out empty strings
202 
203  Performs similar logic to roslib.names.package_resource_name but is a bit
204  more forgiving about excess slashes
205  """
206  splits = [x for x in typestring.split("/") if x]
207  if len(splits) == 2:
208  return splits
209  raise InvalidTypeStringException(typestring)
210 
211 
212 def _add_to_cache(cache, lock, key, value):
213  with lock:
214  cache[key] = value
215 
216 
217 def _get_from_cache(cache, lock, key):
218  """ Returns the value for the specified key from the cache.
219  Locks the lock before doing anything. Returns None if key not in cache """
220  ret = None
221  with lock:
222  if key in cache:
223  ret = cache[key]
224  return ret
def __init__(self, modname, subname, classname, original_exception)
Definition: ros_loader.py:77
def get_service_request_instance(typestring)
Definition: ros_loader.py:112
def _get_from_cache(cache, lock, key)
Definition: ros_loader.py:217
def _get_class(typestring, subname, cache, lock)
Definition: ros_loader.py:140
def __init__(self, package, original_exception)
Definition: ros_loader.py:61
def _add_to_cache(cache, lock, key, value)
Definition: ros_loader.py:212
def __init__(self, modname, subname, original_exception)
Definition: ros_loader.py:69
def _load_class(modname, subname, classname)
Definition: ros_loader.py:172
def get_service_response_instance(typestring)
Definition: ros_loader.py:117


rosbridge_library
Author(s): Jonathan Mace
autogenerated on Fri Oct 21 2022 02:45:18