Salome HOME
- Patch for recent Debian distrib:
[modules/kernel.git] / src / KERNEL_PY / import_hook.py
1 #  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 #
3 #  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 #  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 #
6 #  This library is free software; you can redistribute it and/or
7 #  modify it under the terms of the GNU Lesser General Public
8 #  License as published by the Free Software Foundation; either
9 #  version 2.1 of the License.
10 #
11 #  This library is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 #  Lesser General Public License for more details.
15 #
16 #  You should have received a copy of the GNU Lesser General Public
17 #  License along with this library; if not, write to the Free Software
18 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 #  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 #
22 """
23 This module replaces the standard import mechanism with one
24 that filters some imports that can't be done more than once.
25
26 This is related to the multi study feature that is implemented
27 by using the Python multi interpreter feature.
28 Some modules register objects or classes by calling modules
29 implemented in C. These operations can't be done multiple times.
30 So it's very important to control these imports.
31
32 Examples:
33   - PyQt : import qt calls a C module to register classes
34   - OmniORB : import *_idl calls a C module to register CORBA interfaces
35
36 Usage:
37   - First import the module : import import_hook. This module will
38     replace the original importer mechanism
39
40   - Next register the module names or pattern names to filter out::
41      import_hook.register_name("a")
42      import_hook.register_pattern(pattern)
43
44     where pattern is a function with one parameter, the module name
45     to be imported, that returns true or false depending if this module is
46     to be filtered or not.
47
48   - Then it's done
49
50 IMPORTANT : Every subinterpretor has its own import_hook module. import_hook is not shared among subinterpretors.
51 The mechanism only works if shared_imported and pattern are shared between all subinterpretors.
52 This is done by calling init_shared_modules().
53   
54 """
55 import sys, imp, __builtin__
56
57 # Keep in shared_imported a copy of dictionnary modules
58 # that need to be imported only once in multi-study context
59 shared_imported={}
60
61 # patterns contains functions that returns 1 or 0 depending if 
62 # the module name (argument) must be filtered out or not
63 # These functions are added by calling register_pattern
64 patterns=[]
65
66 original_import=__builtin__.__import__
67
68 def register_name(name):
69     if shared_imported.has_key(name):return
70     shared_imported[name]=None
71
72 def register_pattern(pattern):
73     patterns.append(pattern)
74
75 def is_shared(name):
76     """ Indicate if module name is a shared module
77         among multiple interpreters (return value=1)
78     """
79     if shared_imported.has_key(name):return 1
80     for pattern in patterns:
81         if pattern(name) : return 1
82     return 0
83
84 def get_shared_imported(name,fromlist):
85     """ If the module is registered in shared_imported
86         update the sys.modules dict
87         Let the real import be done by original_import
88     """
89     module= shared_imported.get(name)
90     if module is None :
91        #module name is not shared or not already imported
92        #let original_import do the job
93        return None
94
95     # module is already imported and shared. Put it in sys.modules and 
96     # let original_import finish the job
97     sys.modules[name]=module
98
99 def get_real_module(mod,name):
100     """Return effective module on import
101        Standard import returns module A on import A.B
102        To get module A.B use get_real_module with name "A.B"
103     """
104     components = name.split('.')
105     for comp in components[1:]:
106         mod = getattr(mod, comp)
107     return mod
108
109 def set_shared_imported(name,module):
110     """ Register a shared module
111         Name can be a dotted name : package
112     """
113     shared_imported[name]=module
114     #print "Module %s shared registered" % name,module
115
116 def import_module(partname, fqname, parent):
117     """ Try to import module fqname
118         It's parent is module parent and has name partname
119     """
120     try:
121        m = sys.modules[fqname]
122     except KeyError:
123        pass
124     else:
125        return m
126
127 def ensure_fromlist(m, fromlist, recursive=0):
128     """ Return the real modules list to be imported
129     """
130     l=[]
131     for sub in fromlist:
132         if sub == "*":
133             if not recursive:
134                 try:
135                     all = m.__all__
136                 except AttributeError:
137                     pass
138                 else:
139                     l.extend(ensure_fromlist(m, all, 1))
140         elif hasattr(m,sub):
141             submod=getattr(m,sub)
142             if type(submod) == type(sys):
143                l.append(("%s.%s" % (m.__name__, sub),submod))
144         else:
145             subname="%s.%s" % (m.__name__, sub)
146             submod = import_module(sub, subname, m)
147             if not submod:
148                raise ImportError, "No module named " + subname
149             l.append((subname,submod))
150     return l
151
152 def import_hook(name, globals=None, locals=None, fromlist=None, *args):
153     """ Import replacement for sharing modules among multiple interpreters
154         Mostly update sys.modules before doing real import
155     """
156     #print "import_hook",name,fromlist
157     m=get_shared_imported(name,fromlist)
158
159     module= original_import(name, globals, locals, fromlist, *args)
160
161     if fromlist:
162        #when fromlist is specified, module is the real module
163        #fromlist is a list of possibly dotted name
164        m=module
165        for nam,mod in ensure_fromlist(m, fromlist):
166            if is_shared(nam):
167               set_shared_imported(nam,mod)
168     else: 
169        #when fromlist is not specified and name is a dotted name,
170        # module is the root package not the real module
171        #so we need to retrieve it
172        # note: some modules like xml.dom do not play the rule
173        # (import xml: no attribute dom, but import xml.dom OK)
174        try:
175            m=get_real_module(module,name)
176        except AttributeError:
177            m=None
178
179     if type(m) == type(sys) and is_shared(m.__name__):
180        set_shared_imported(m.__name__,m)
181
182     return module
183
184 original_reload=__builtin__.reload
185
186 def reload_hook(module):
187     if is_shared(module.__name__):
188        return module
189     return original_reload(module)
190
191 __builtin__.__import__=import_hook
192 # Reload is not replaced 
193 #__builtin__.reload=reload_hook
194
195 def init_shared_modules(shared_module):
196     global shared_imported, patterns
197     shared_imported=shared_module.shared_imported
198     patterns=       shared_module.patterns
199     for k,v in shared_imported.items():
200        if v is not None:sys.modules[k]=v
201     shared_imported["salome_shared_modules"]=shared_module
202     import salome_shared_modules
203     for m in salome_shared_modules.list_modules:
204         m.init_shared_modules()