00001
00002
00003
00004
00005 '''rtshell
00006
00007 Copyright (C) 2009-2014
00008 Geoffrey Biggs
00009 RT-Synthesis Research Group
00010 Intelligent Systems Research Institute,
00011 National Institute of Advanced Industrial Science and Technology (AIST),
00012 Japan
00013 All rights reserved.
00014 Licensed under the Eclipse Public License -v 1.0 (EPL)
00015 http://www.opensource.org/licenses/eclipse-1.0.txt
00016
00017 Objects for managing dynamically-loaded modules and evaluating strings.
00018
00019 '''
00020
00021
00022 import imp
00023 import inspect
00024 import OpenRTM_aist
00025 import os.path
00026 import re
00027 import RTC
00028 import sys
00029 import time
00030
00031 import rts_exceptions
00032
00033
00034
00035
00036
00037 class Module(object):
00038 def __init__(self, name, mod=None, *args, **kwargs):
00039 super(Module, self).__init__()
00040 self._name = name
00041 self._mod = mod
00042
00043 def __str__(self):
00044 return '{0}: {1}'.format(self._name, self._mod)
00045
00046 @property
00047 def name(self):
00048 '''The name of the module, as it would be called in source.'''
00049 return self._name
00050
00051 @property
00052 def mod(self):
00053 '''The module object.'''
00054 return self._mod
00055
00056 def _load_mod(self):
00057 '''Loads the module object.'''
00058 f = None
00059 try:
00060 f, p, d = imp.find_module(self._name)
00061 self._mod = imp.load_module(self._name, f, p, d)
00062 finally:
00063 if f:
00064 f.close()
00065
00066
00067 class AutoModule(Module):
00068 def __init__(self, name, *args, **kwargs):
00069 super(AutoModule, self).__init__(name, *args, **kwargs)
00070 self._load_mod()
00071
00072
00073
00074
00075
00076
00077 class ModuleMgr(object):
00078 def __init__(self, verbose=False, paths=[], *args, **kwargs):
00079 super(ModuleMgr, self).__init__()
00080 self._mods = {'RTC': Module('RTC', mod=RTC)}
00081 self._verb = verbose
00082 self._add_paths(paths)
00083
00084 def _add_paths(self, paths=[]):
00085 for p in paths:
00086 if self._verb:
00087 print >>sys.stderr, 'Adding {0} to PYTHONPATH'.format(p)
00088 sys.path.insert(0, p)
00089
00090 def evaluate(self, expr):
00091 self._auto_import(expr)
00092 repl_expr = self._repl_mod_name(_replace_time(expr))
00093 if not repl_expr:
00094 raise rts_exceptions.EmptyConstExprError
00095 if self._verb:
00096 print >>sys.stderr, 'Evaluating expression {0}'.format(repl_expr)
00097 const = eval(repl_expr)
00098 return const
00099
00100 def find_class(self, name):
00101 '''Find a class constructor in one of the modules.
00102
00103 The first matching class's constructor will be returned.
00104
00105 @param name The name of the class to search for.
00106
00107 '''
00108
00109 name = name.replace('/', '.')
00110 self._auto_import(name)
00111
00112 name = _find_object_name(name)
00113 for m in self._mods.values():
00114 if m.name == 'RTC':
00115
00116 continue
00117 types = [member for member in inspect.getmembers(m.mod,
00118 inspect.isclass) if member[0] == name or "IDL:"+self._mods.keys()[0]+"/"+member[0]+":1.0" == name]
00119 if len(types) == 0:
00120 continue
00121 elif len(types) != 1:
00122 raise rts_exceptions.AmbiguousTypeError(type_name)
00123 else:
00124
00125 if m.name != 'RTC':
00126 if not [other_m for other_m in self._mods.values() \
00127 if other_m.name == m.name + '__POA']:
00128 raise rts_exceptions.MissingPOAError(m.name)
00129 if self._verb:
00130 print >>sys.stderr, 'Found type {0} in module {1}'.format(
00131 name, m.name)
00132 return types[0][1]
00133
00134
00135 m = self._mods['RTC']
00136 types = [member for member in inspect.getmembers(m.mod,
00137 inspect.isclass) if member[0] == name]
00138 if len(types) != 0:
00139 if len(types) != 1:
00140 raise rts_exceptions.AmbiguousTypeError(type_name)
00141 if self._verb:
00142 print >>sys.stderr, 'Found type {0} in module {1}'.format(
00143 name, m.name)
00144 return types[0][1]
00145 raise rts_exceptions.TypeNotFoundError(name)
00146
00147 def load_mod(self, mod):
00148 '''Load a module.'''
00149 m = AutoModule(mod)
00150 self._mods[mod] = m
00151
00152 def load_mods(self, mods):
00153 '''Load a list of modules.
00154
00155 @param mods The module names, as a list of strings.
00156
00157 '''
00158 [self.load_mod(m) for m in mods]
00159
00160 def load_mods_and_poas(self, mods):
00161 '''Load a set of modules and their POA modules.
00162
00163 @param mods The module names, as a list of strings.
00164
00165 '''
00166 for m in mods:
00167 self.load_mod(m)
00168 try:
00169 self.load_mod(m + '__POA')
00170 except ImportError:
00171 print >>sys.stderr, '{0}: Failed to import module {1}'.format(\
00172 os.path.basename(sys.argv[0]), m + '__POA')
00173 pass
00174
00175 @property
00176 def loaded_mod_names(self):
00177 return self._mods.keys()
00178
00179 def _auto_import(self, expr):
00180 '''Tries to import all module names found in an expression.
00181
00182 A failure to import a module will cause a warning, not an error.
00183
00184 '''
00185 names = [m for m in _find_module_names(expr) if m not in self._mods]
00186 if self._verb:
00187 print >>sys.stderr, 'Automatically importing modules {0}'.format(
00188 names)
00189 for n in names:
00190 try:
00191 self.load_mod(n)
00192 except ImportError:
00193 print >>sys.stderr, \
00194 '{0}: Warning: failed to import module {1}'.format(
00195 os.path.basename(sys.argv[0]), n)
00196 continue
00197 try:
00198 self.load_mod(n + '__POA')
00199 except ImportError:
00200 print >>sys.stderr, \
00201 '{0}: Warning: failed to import module {1}'.format(
00202 os.path.basename(sys.argv[0]), n + '__POA')
00203 continue
00204
00205 def _repl_mod_name(self, expr):
00206 '''Replace the name of a module.
00207
00208 Replaces a reference to a module in a string with its reference in
00209 the modules array.
00210
00211 '''
00212 for m in self._mods:
00213 if m in expr:
00214 expr = expr.replace(m, 'self._mods["{0}"].mod'.format(m))
00215 return expr
00216
00217
00218
00219
00220
00221 def _replace_time(expr):
00222 '''Replaces any occurances with {time} with the system time.'''
00223 now = time.time()
00224 sys_time = RTC.Time(int(now), int((now - int(now)) * 1e9))
00225 return expr.format(time=sys_time)
00226
00227
00228 def _find_module_names(expr):
00229 '''Finds all potential module names in an expression.'''
00230 return [x[:-1] for x in re.findall(r'(?P<mod>[a-zA-Z][\w.]*\.)+[a-zA-Z]',
00231 expr)]
00232
00233
00234 def _find_object_name(expr):
00235 '''Finds the object at the end of a module...module.object line.'''
00236 return expr[expr.rfind('.') + 1:]
00237