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