blob: 34117fab0f0f41f8ea85ae08a1f9a73b4b4ef099 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001
2:mod:`imputil` --- Import utilities
3=====================================================
4
5.. module:: imputil
6 :synopsis: Manage and augment the import process.
7
8
9.. index:: statement: import
10
11This module provides a very handy and useful mechanism for custom
12:keyword:`import` hooks. Compared to the older :mod:`ihooks` module,
13:mod:`imputil` takes a dramatically simpler and more straight-forward
14approach to custom :keyword:`import` functions.
15
16
17.. class:: ImportManager([fs_imp])
18
19 Manage the import process.
20
21 .. method:: ImportManager.install([namespace])
22
23 Install this ImportManager into the specified namespace.
24
25 .. method:: ImportManager.uninstall()
26
27 Restore the previous import mechanism.
28
29 .. method:: ImportManager.add_suffix(suffix, importFunc)
30
31 Undocumented.
32
33
34.. class:: Importer()
35
36 Base class for replacing standard import functions.
37
38 .. method:: Importer.import_top(name)
39
40 Import a top-level module.
41
42 .. method:: Importer.get_code(parent, modname, fqname)
43
44 Find and retrieve the code for the given module.
45
46 *parent* specifies a parent module to define a context for importing.
47 It may be ``None``, indicating no particular context for the search.
48
49 *modname* specifies a single module (not dotted) within the parent.
50
51 *fqname* specifies the fully-qualified module name. This is a
52 (potentially) dotted name from the "root" of the module namespace
53 down to the modname.
54
55 If there is no parent, then modname==fqname.
56
57 This method should return ``None``, or a 3-tuple.
58
59 * If the module was not found, then ``None`` should be returned.
60
61 * The first item of the 2- or 3-tuple should be the integer 0 or 1,
62 specifying whether the module that was found is a package or not.
63
64 * The second item is the code object for the module (it will be
65 executed within the new module's namespace). This item can also
66 be a fully-loaded module object (e.g. loaded from a shared lib).
67
68 * The third item is a dictionary of name/value pairs that will be
69 inserted into new module before the code object is executed. This
70 is provided in case the module's code expects certain values (such
71 as where the module was found). When the second item is a module
72 object, then these names/values will be inserted *after* the module
73 has been loaded/initialized.
74
75
76.. class:: BuiltinImporter()
77
78 Emulate the import mechanism for builtin and frozen modules. This is a
79 sub-class of the :class:`Importer` class.
80
81 .. method:: BuiltinImporter.get_code(parent, modname, fqname)
82
83 Undocumented.
84
85.. function:: py_suffix_importer(filename, finfo, fqname)
86
87 Undocumented.
88
89.. class:: DynLoadSuffixImporter([desc])
90
91 Undocumented.
92
93 .. method:: DynLoadSuffixImporter.import_file(filename, finfo, fqname)
94
95 Undocumented.
96
97.. _examples-imputil:
98
99Examples
100--------
101
102This is a re-implementation of hierarchical module import.
103
104This code is intended to be read, not executed. However, it does work
105-- all you need to do to enable it is "import knee".
106
107(The name is a pun on the klunkier predecessor of this module, "ni".)
108
109::
110
111 import sys, imp, __builtin__
112
113 # Replacement for __import__()
114 def import_hook(name, globals=None, locals=None, fromlist=None):
115 parent = determine_parent(globals)
116 q, tail = find_head_package(parent, name)
117 m = load_tail(q, tail)
118 if not fromlist:
119 return q
120 if hasattr(m, "__path__"):
121 ensure_fromlist(m, fromlist)
122 return m
123
124 def determine_parent(globals):
125 if not globals or not globals.has_key("__name__"):
126 return None
127 pname = globals['__name__']
128 if globals.has_key("__path__"):
129 parent = sys.modules[pname]
130 assert globals is parent.__dict__
131 return parent
132 if '.' in pname:
133 i = pname.rfind('.')
134 pname = pname[:i]
135 parent = sys.modules[pname]
136 assert parent.__name__ == pname
137 return parent
138 return None
139
140 def find_head_package(parent, name):
141 if '.' in name:
142 i = name.find('.')
143 head = name[:i]
144 tail = name[i+1:]
145 else:
146 head = name
147 tail = ""
148 if parent:
149 qname = "%s.%s" % (parent.__name__, head)
150 else:
151 qname = head
152 q = import_module(head, qname, parent)
153 if q: return q, tail
154 if parent:
155 qname = head
156 parent = None
157 q = import_module(head, qname, parent)
158 if q: return q, tail
159 raise ImportError, "No module named " + qname
160
161 def load_tail(q, tail):
162 m = q
163 while tail:
164 i = tail.find('.')
165 if i < 0: i = len(tail)
166 head, tail = tail[:i], tail[i+1:]
167 mname = "%s.%s" % (m.__name__, head)
168 m = import_module(head, mname, m)
169 if not m:
170 raise ImportError, "No module named " + mname
171 return m
172
173 def ensure_fromlist(m, fromlist, recursive=0):
174 for sub in fromlist:
175 if sub == "*":
176 if not recursive:
177 try:
178 all = m.__all__
179 except AttributeError:
180 pass
181 else:
182 ensure_fromlist(m, all, 1)
183 continue
184 if sub != "*" and not hasattr(m, sub):
185 subname = "%s.%s" % (m.__name__, sub)
186 submod = import_module(sub, subname, m)
187 if not submod:
188 raise ImportError, "No module named " + subname
189
190 def import_module(partname, fqname, parent):
191 try:
192 return sys.modules[fqname]
193 except KeyError:
194 pass
195 try:
196 fp, pathname, stuff = imp.find_module(partname,
197 parent and parent.__path__)
198 except ImportError:
199 return None
200 try:
201 m = imp.load_module(fqname, fp, pathname, stuff)
202 finally:
203 if fp: fp.close()
204 if parent:
205 setattr(parent, partname, m)
206 return m
207
208
209 # Replacement for reload()
210 def reload_hook(module):
211 name = module.__name__
212 if '.' not in name:
213 return import_module(name, name, None)
214 i = name.rfind('.')
215 pname = name[:i]
216 parent = sys.modules[pname]
217 return import_module(name[i+1:], name, parent)
218
219
220 # Save the original hooks
221 original_import = __builtin__.__import__
222 original_reload = __builtin__.reload
223
224 # Now install our hooks
225 __builtin__.__import__ = import_hook
226 __builtin__.reload = reload_hook
227
228.. index::
229 module: knee
230
231Also see the :mod:`importers` module (which can be found
232in :file:`Demo/imputil/` in the Python source distribution) for additional
233examples.
234