modmgr.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- Python -*-
00003 # -*- coding: utf-8 -*-
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 ## Module class - stores a dynamically imported module.
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 ## ModuleMgr class - keeps track of loaded extra modules and provides
00075 ## evaluation of Python expressions
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         # Replace / in the name with . to create a Python path
00109         name = name.replace('/', '.')
00110         self._auto_import(name)
00111         # Strip the name down to the class
00112         name = _find_object_name(name)
00113         for m in self._mods.values():
00114             if m.name == 'RTC':
00115                 # Search RTC last to allow user types to override RTC types
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                 # Check for the POA module
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         # If got to here, the type was not found in any other module, so search
00134         # the RTC module
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 ## Internal support functions
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 


rtshell
Author(s): Geoffrey Biggs
autogenerated on Fri Aug 28 2015 12:55:12