1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
4 # Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
5 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
25 This module replaces the standard import mechanism with one
26 that filters some imports that can't be done more than once.
28 This is related to the multi study feature that is implemented
29 by using the Python multi interpreter feature.
30 Some modules register objects or classes by calling modules
31 implemented in C. These operations can't be done multiple times.
32 So it's very important to control these imports.
35 - PyQt : import qt calls a C module to register classes
36 - OmniORB : import *_idl calls a C module to register CORBA interfaces
39 - First import the module : import import_hook. This module will
40 replace the original importer mechanism
42 - Next register the module names or pattern names to filter out::
43 import_hook.register_name("a")
44 import_hook.register_pattern(pattern)
46 where pattern is a function with one parameter, the module name
47 to be imported, that returns true or false depending if this module is
48 to be filtered or not.
52 IMPORTANT : Every subinterpretor has its own import_hook module. import_hook is not shared among subinterpretors.
53 The mechanism only works if shared_imported and pattern are shared between all subinterpretors.
54 This is done by calling init_shared_modules().
57 import sys, imp, __builtin__
59 # Keep in shared_imported a copy of dictionnary modules
60 # that need to be imported only once in multi-study context
63 # patterns contains functions that returns 1 or 0 depending if
64 # the module name (argument) must be filtered out or not
65 # These functions are added by calling register_pattern
68 original_import=__builtin__.__import__
70 def register_name(name):
71 if shared_imported.has_key(name):return
72 shared_imported[name]=None
74 def register_pattern(pattern):
75 patterns.append(pattern)
78 """ Indicate if module name is a shared module
79 among multiple interpreters (return value=1)
81 if shared_imported.has_key(name):return 1
82 for pattern in patterns:
83 if pattern(name) : return 1
86 def get_shared_imported(name,fromlist):
87 """ If the module is registered in shared_imported
88 update the sys.modules dict
89 Let the real import be done by original_import
91 module= shared_imported.get(name)
93 #module name is not shared or not already imported
94 #let original_import do the job
97 # module is already imported and shared. Put it in sys.modules and
98 # let original_import finish the job
99 sys.modules[name]=module
101 def get_real_module(mod,name):
102 """Return effective module on import
103 Standard import returns module A on import A.B
104 To get module A.B use get_real_module with name "A.B"
106 components = name.split('.')
107 for comp in components[1:]:
108 mod = getattr(mod, comp)
111 def set_shared_imported(name,module):
112 """ Register a shared module
113 Name can be a dotted name : package
115 shared_imported[name]=module
116 #print "Module %s shared registered" % name,module
118 def import_module(partname, fqname, parent):
119 """ Try to import module fqname
120 It's parent is module parent and has name partname
122 #print "import_module",partname, fqname, parent
124 m = sys.modules[fqname]
130 def ensure_fromlist(m, fromlist, recursive=0):
131 """ Return the real modules list to be imported
133 #print "ensure_fromlist",m, fromlist, recursive
140 except AttributeError:
143 l.extend(ensure_fromlist(m, all, 1))
145 #try to find if sub is an attribute (eventually dotted) of m
146 components=sub.split('.')
149 for comp in components:
150 if hasattr(submod,comp):
151 submod=getattr(submod, comp)
157 #the attribute has been found
158 if type(submod) == type(sys):
159 l.append(("%s.%s" % (m.__name__, sub),submod))
161 subname="%s.%s" % (m.__name__, sub)
162 submod = import_module(sub, subname, m)
164 raise ImportError, "No module named " + subname
165 l.append((subname,submod))
168 def import_hook(name, globals=None, locals=None, fromlist=None, *args, **kwds):
169 """ Import replacement for sharing modules among multiple interpreters
170 Mostly update sys.modules before doing real import
172 #print "import_hook",name,fromlist
173 m=get_shared_imported(name,fromlist)
175 module= original_import(name, globals, locals, fromlist, *args, **kwds)
178 #when fromlist is specified, module is the real module
179 #fromlist is a list of possibly dotted name
181 for nam,mod in ensure_fromlist(m, fromlist):
183 set_shared_imported(nam,mod)
185 #when fromlist is not specified and name is a dotted name,
186 # module is the root package not the real module
187 #so we need to retrieve it
188 # note: some modules like xml.dom do not play the rule
189 # (import xml: no attribute dom, but import xml.dom OK)
191 m=get_real_module(module,name)
192 except AttributeError:
195 if type(m) == type(sys) and is_shared(m.__name__):
196 set_shared_imported(m.__name__,m)
200 original_reload=__builtin__.reload
202 def reload_hook(module):
203 if is_shared(module.__name__):
205 return original_reload(module)
207 __builtin__.__import__=import_hook
208 # Reload is not replaced
209 #__builtin__.reload=reload_hook
211 def init_shared_modules(shared_module):
212 global shared_imported, patterns
213 shared_imported=shared_module.shared_imported
214 patterns= shared_module.patterns
215 for k,v in shared_imported.items():
216 if v is not None:sys.modules[k]=v
217 shared_imported["salome_shared_modules"]=shared_module
218 import salome_shared_modules
219 for m in salome_shared_modules.list_modules:
220 m.init_shared_modules()