Sean Reifscheider | 99cafb9 | 2007-08-28 09:07:54 +0000 | [diff] [blame^] | 1 | |
| 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 | |
| 11 | This module provides a very handy and useful mechanism for custom |
| 12 | :keyword:`import` hooks. Compared to the standard library's ihooks.py, |
| 13 | imputil.py takes a dramatically simpler and more straight-forward approach |
| 14 | 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. It |
| 47 | 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 Importer module. |
| 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 | |
| 99 | Examples |
| 100 | -------- |
| 101 | |
| 102 | This is a re-implementation of hierarchical module import. |
| 103 | |
| 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". |
| 106 | |
| 107 | (The name is a pun on the klunkier predecessor of this module, "ni".) |
| 108 | |
| 109 | |
| 110 | import sys, imp, __builtin__ |
| 111 | |
| 112 | # Replacement for __import__() |
| 113 | def import_hook(name, globals=None, locals=None, fromlist=None): |
| 114 | parent = determine_parent(globals) |
| 115 | q, tail = find_head_package(parent, name) |
| 116 | m = load_tail(q, tail) |
| 117 | if not fromlist: |
| 118 | return q |
| 119 | if hasattr(m, "__path__"): |
| 120 | ensure_fromlist(m, fromlist) |
| 121 | return m |
| 122 | |
| 123 | def determine_parent(globals): |
| 124 | if not globals or not globals.has_key("__name__"): |
| 125 | return None |
| 126 | pname = globals['__name__'] |
| 127 | if globals.has_key("__path__"): |
| 128 | parent = sys.modules[pname] |
| 129 | assert globals is parent.__dict__ |
| 130 | return parent |
| 131 | if '.' in pname: |
| 132 | i = pname.rfind('.') |
| 133 | pname = pname[:i] |
| 134 | parent = sys.modules[pname] |
| 135 | assert parent.__name__ == pname |
| 136 | return parent |
| 137 | return None |
| 138 | |
| 139 | def find_head_package(parent, name): |
| 140 | if '.' in name: |
| 141 | i = name.find('.') |
| 142 | head = name[:i] |
| 143 | tail = name[i+1:] |
| 144 | else: |
| 145 | head = name |
| 146 | tail = "" |
| 147 | if parent: |
| 148 | qname = "%s.%s" % (parent.__name__, head) |
| 149 | else: |
| 150 | qname = head |
| 151 | q = import_module(head, qname, parent) |
| 152 | if q: return q, tail |
| 153 | if parent: |
| 154 | qname = head |
| 155 | parent = None |
| 156 | q = import_module(head, qname, parent) |
| 157 | if q: return q, tail |
| 158 | raise ImportError, "No module named " + qname |
| 159 | |
| 160 | def load_tail(q, tail): |
| 161 | m = q |
| 162 | while tail: |
| 163 | i = tail.find('.') |
| 164 | if i < 0: i = len(tail) |
| 165 | head, tail = tail[:i], tail[i+1:] |
| 166 | mname = "%s.%s" % (m.__name__, head) |
| 167 | m = import_module(head, mname, m) |
| 168 | if not m: |
| 169 | raise ImportError, "No module named " + mname |
| 170 | return m |
| 171 | |
| 172 | def ensure_fromlist(m, fromlist, recursive=0): |
| 173 | for sub in fromlist: |
| 174 | if sub == "*": |
| 175 | if not recursive: |
| 176 | try: |
| 177 | all = m.__all__ |
| 178 | except AttributeError: |
| 179 | pass |
| 180 | else: |
| 181 | ensure_fromlist(m, all, 1) |
| 182 | continue |
| 183 | if sub != "*" and not hasattr(m, sub): |
| 184 | subname = "%s.%s" % (m.__name__, sub) |
| 185 | submod = import_module(sub, subname, m) |
| 186 | if not submod: |
| 187 | raise ImportError, "No module named " + subname |
| 188 | |
| 189 | def import_module(partname, fqname, parent): |
| 190 | try: |
| 191 | return sys.modules[fqname] |
| 192 | except KeyError: |
| 193 | pass |
| 194 | try: |
| 195 | fp, pathname, stuff = imp.find_module(partname, |
| 196 | parent and parent.__path__) |
| 197 | except ImportError: |
| 198 | return None |
| 199 | try: |
| 200 | m = imp.load_module(fqname, fp, pathname, stuff) |
| 201 | finally: |
| 202 | if fp: fp.close() |
| 203 | if parent: |
| 204 | setattr(parent, partname, m) |
| 205 | return m |
| 206 | |
| 207 | |
| 208 | # Replacement for reload() |
| 209 | def reload_hook(module): |
| 210 | name = module.__name__ |
| 211 | if '.' not in name: |
| 212 | return import_module(name, name, None) |
| 213 | i = name.rfind('.') |
| 214 | pname = name[:i] |
| 215 | parent = sys.modules[pname] |
| 216 | return import_module(name[i+1:], name, parent) |
| 217 | |
| 218 | |
| 219 | # Save the original hooks |
| 220 | original_import = __builtin__.__import__ |
| 221 | original_reload = __builtin__.reload |
| 222 | |
| 223 | # Now install our hooks |
| 224 | __builtin__.__import__ = import_hook |
| 225 | __builtin__.reload = reload_hook |
| 226 | |
| 227 | .. index:: |
| 228 | module: knee |
| 229 | |
| 230 | Also see the :mod:`importers` module (which can be found |
| 231 | in :file:`Demo/imputil/` in the Python source distribution) for additional |
| 232 | examples. |
| 233 | |