Back to index

salome-kernel  6.5.0
import_hook.py
Go to the documentation of this file.
00001 #  -*- coding: iso-8859-1 -*-
00002 # Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00003 #
00004 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00005 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00006 #
00007 # This library is free software; you can redistribute it and/or
00008 # modify it under the terms of the GNU Lesser General Public
00009 # License as published by the Free Software Foundation; either
00010 # version 2.1 of the License.
00011 #
00012 # This library is distributed in the hope that it will be useful,
00013 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 # Lesser General Public License for more details.
00016 #
00017 # You should have received a copy of the GNU Lesser General Public
00018 # License along with this library; if not, write to the Free Software
00019 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00020 #
00021 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00022 #
00023 
00024 """
00025 This module replaces the standard import mechanism with one
00026 that filters some imports that can't be done more than once.
00027 
00028 This is related to the multi study feature that is implemented
00029 by using the Python multi interpreter feature.
00030 Some modules register objects or classes by calling modules
00031 implemented in C. These operations can't be done multiple times.
00032 So it's very important to control these imports.
00033 
00034 Examples:
00035   - PyQt : import qt calls a C module to register classes
00036   - OmniORB : import *_idl calls a C module to register CORBA interfaces
00037 
00038 Usage:
00039   - First import the module : import import_hook. This module will
00040     replace the original importer mechanism
00041 
00042   - Next register the module names or pattern names to filter out::
00043      import_hook.register_name("a")
00044      import_hook.register_pattern(pattern)
00045 
00046     where pattern is a function with one parameter, the module name
00047     to be imported, that returns true or false depending if this module is
00048     to be filtered or not.
00049 
00050   - Then it's done
00051 
00052 IMPORTANT : Every subinterpretor has its own import_hook module. import_hook is not shared among subinterpretors.
00053 The mechanism only works if shared_imported and pattern are shared between all subinterpretors.
00054 This is done by calling init_shared_modules().
00055   
00056 """
00057 import sys, imp, __builtin__
00058 
00059 # Keep in shared_imported a copy of dictionnary modules
00060 # that need to be imported only once in multi-study context
00061 shared_imported={}
00062 
00063 # patterns contains functions that returns 1 or 0 depending if 
00064 # the module name (argument) must be filtered out or not
00065 # These functions are added by calling register_pattern
00066 patterns=[]
00067 
00068 original_import=__builtin__.__import__
00069 
00070 def register_name(name):
00071     if shared_imported.has_key(name):return
00072     shared_imported[name]=None
00073 
00074 def register_pattern(pattern):
00075     patterns.append(pattern)
00076 
00077 def is_shared(name):
00078     """ Indicate if module name is a shared module
00079         among multiple interpreters (return value=1)
00080     """
00081     if shared_imported.has_key(name):return 1
00082     for pattern in patterns:
00083         if pattern(name) : return 1
00084     return 0
00085 
00086 def get_shared_imported(name,fromlist):
00087     """ If the module is registered in shared_imported
00088         update the sys.modules dict
00089         Let the real import be done by original_import
00090     """
00091     module= shared_imported.get(name)
00092     if module is None :
00093        #module name is not shared or not already imported
00094        #let original_import do the job
00095        return None
00096 
00097     # module is already imported and shared. Put it in sys.modules and 
00098     # let original_import finish the job
00099     sys.modules[name]=module
00100 
00101 def get_real_module(mod,name):
00102     """Return effective module on import
00103        Standard import returns module A on import A.B
00104        To get module A.B use get_real_module with name "A.B"
00105     """
00106     components = name.split('.')
00107     for comp in components[1:]:
00108         mod = getattr(mod, comp)
00109     return mod
00110 
00111 def set_shared_imported(name,module):
00112     """ Register a shared module
00113         Name can be a dotted name : package
00114     """
00115     shared_imported[name]=module
00116     #print "Module %s shared registered" % name,module
00117 
00118 def import_module(partname, fqname, parent):
00119     """ Try to import module fqname
00120         It's parent is module parent and has name partname
00121     """
00122     #print "import_module",partname, fqname, parent
00123     try:
00124        m = sys.modules[fqname]
00125     except KeyError:
00126        pass
00127     else:
00128        return m
00129 
00130 def ensure_fromlist(m, fromlist, recursive=0):
00131     """ Return the real modules list to be imported
00132     """
00133     #print "ensure_fromlist",m, fromlist, recursive
00134     l=[]
00135     for sub in fromlist:
00136         if sub == "*":
00137             if not recursive:
00138                 try:
00139                     all = m.__all__
00140                 except AttributeError:
00141                     pass
00142                 else:
00143                     l.extend(ensure_fromlist(m, all, 1))
00144         else:
00145           #try to find if sub is an attribute (eventually dotted) of m
00146           components=sub.split('.')
00147           has_submod=True
00148           submod=m
00149           for comp in components:
00150             if hasattr(submod,comp):
00151               submod=getattr(submod, comp)
00152             else:
00153               has_submod=False
00154               break
00155 
00156           if has_submod:
00157             #the attribute has been found
00158             if type(submod) == type(sys):
00159                l.append(("%s.%s" % (m.__name__, sub),submod))
00160           else:
00161             subname="%s.%s" % (m.__name__, sub)
00162             submod = import_module(sub, subname, m)
00163             #if not found ignore it
00164             if submod:
00165               l.append((subname,submod))
00166     return l
00167 
00168 def import_hook(name, globals=None, locals=None, fromlist=None, *args, **kwds):
00169     """ Import replacement for sharing modules among multiple interpreters
00170         Mostly update sys.modules before doing real import
00171     """
00172     #print "import_hook",name,fromlist
00173     m=get_shared_imported(name,fromlist)
00174 
00175     module= original_import(name, globals, locals, fromlist, *args, **kwds)
00176 
00177     if fromlist:
00178        #when fromlist is specified, module is the real module
00179        #fromlist is a list of possibly dotted name
00180        m=module
00181        for nam,mod in ensure_fromlist(m, fromlist):
00182            if is_shared(nam):
00183               set_shared_imported(nam,mod)
00184     else: 
00185        #when fromlist is not specified and name is a dotted name,
00186        # module is the root package not the real module
00187        #so we need to retrieve it
00188        # note: some modules like xml.dom do not play the rule
00189        # (import xml: no attribute dom, but import xml.dom OK)
00190        try:
00191            m=get_real_module(module,name)
00192        except AttributeError:
00193            m=None
00194 
00195     if type(m) == type(sys) and is_shared(m.__name__):
00196        set_shared_imported(m.__name__,m)
00197 
00198     return module
00199 
00200 original_reload=__builtin__.reload
00201 
00202 def reload_hook(module):
00203     if is_shared(module.__name__):
00204        return module
00205     return original_reload(module)
00206 
00207 __builtin__.__import__=import_hook
00208 # Reload is not replaced 
00209 #__builtin__.reload=reload_hook
00210 
00211 def init_shared_modules(shared_module):
00212     global shared_imported, patterns
00213     shared_imported=shared_module.shared_imported
00214     patterns=       shared_module.patterns
00215     for k,v in shared_imported.items():
00216        if v is not None:sys.modules[k]=v
00217     shared_imported["salome_shared_modules"]=shared_module
00218     import salome_shared_modules
00219     for m in salome_shared_modules.list_modules:
00220         m.init_shared_modules()