Added section on passing contextual information to logging and documentation for...
[python.git] / Doc / library / imputil.rst
blob34117fab0f0f41f8ea85ae08a1f9a73b4b4ef099
2 :mod:`imputil` --- Import utilities
3 =====================================================
5 .. module:: imputil
6    :synopsis: Manage and augment the import process.
9 .. index:: statement: import
11 This 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
14 approach to custom :keyword:`import` functions.
17 .. class:: ImportManager([fs_imp])
19    Manage the import process.
21    .. method:: ImportManager.install([namespace])
23       Install this ImportManager into the specified namespace.
25    .. method:: ImportManager.uninstall()
27       Restore the previous import mechanism.
29    .. method:: ImportManager.add_suffix(suffix, importFunc)
31       Undocumented.
34 .. class:: Importer()
36    Base class for replacing standard import functions.
38    .. method:: Importer.import_top(name)
40       Import a top-level module.
42    .. method:: Importer.get_code(parent, modname, fqname)
44       Find and retrieve the code for the given module.
46       *parent* specifies a parent module to define a context for importing.
47       It may be ``None``, indicating no particular context for the search.
49       *modname* specifies a single module (not dotted) within the parent.
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.
55       If there is no parent, then modname==fqname.
57       This method should return ``None``, or a 3-tuple.
59         * If the module was not found, then ``None`` should be returned.
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.
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).
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.
76 .. class:: BuiltinImporter()
78    Emulate the import mechanism for builtin and frozen modules.  This is a
79    sub-class of the :class:`Importer` class.
81    .. method:: BuiltinImporter.get_code(parent, modname, fqname)
83       Undocumented.
85 .. function:: py_suffix_importer(filename, finfo, fqname)
87    Undocumented.
89 .. class:: DynLoadSuffixImporter([desc])
91    Undocumented.
93    .. method:: DynLoadSuffixImporter.import_file(filename, finfo, fqname)
95       Undocumented.
97 .. _examples-imputil:
99 Examples
100 --------
102 This is a re-implementation of hierarchical module import.
104 This code is intended to be read, not executed.  However, it does work
105 -- all you need to do to enable it is "import knee".
107 (The name is a pun on the klunkier predecessor of this module, "ni".)
111    import sys, imp, __builtin__
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
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
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
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
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
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
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)
220    # Save the original hooks
221    original_import = __builtin__.__import__
222    original_reload = __builtin__.reload
224    # Now install our hooks
225    __builtin__.__import__ = import_hook
226    __builtin__.reload = reload_hook
228 .. index::
229    module: knee
231 Also see the :mod:`importers` module (which can be found
232 in :file:`Demo/imputil/` in the Python source distribution) for additional
233 examples.