| """An Python re-implementation of hierarchical module import. |
| |
| This code is intended to be read, not executed. However, it does work |
| -- all you need to do to enable it is "import knee". |
| |
| (The name is a pun on the klunkier predecessor of this module, "ni".) |
| |
| """ |
| |
| import sys, imp, __builtin__ |
| |
| |
| # Replacement for __import__() |
| def import_hook(name, globals=None, locals=None, fromlist=None): |
| parent = determine_parent(globals) |
| q, tail = find_head_package(parent, name) |
| m = load_tail(q, tail) |
| if not fromlist: |
| return q |
| if hasattr(m, "__path__"): |
| ensure_fromlist(m, fromlist) |
| return m |
| |
| def determine_parent(globals): |
| if not globals or not globals.has_key("__name__"): |
| return None |
| pname = globals['__name__'] |
| if globals.has_key("__path__"): |
| parent = sys.modules[pname] |
| assert globals is parent.__dict__ |
| return parent |
| if '.' in pname: |
| i = pname.rfind('.') |
| pname = pname[:i] |
| parent = sys.modules[pname] |
| assert parent.__name__ == pname |
| return parent |
| return None |
| |
| def find_head_package(parent, name): |
| if '.' in name: |
| i = name.find('.') |
| head = name[:i] |
| tail = name[i+1:] |
| else: |
| head = name |
| tail = "" |
| if parent: |
| qname = "%s.%s" % (parent.__name__, head) |
| else: |
| qname = head |
| q = import_module(head, qname, parent) |
| if q: return q, tail |
| if parent: |
| qname = head |
| parent = None |
| q = import_module(head, qname, parent) |
| if q: return q, tail |
| raise ImportError, "No module named " + qname |
| |
| def load_tail(q, tail): |
| m = q |
| while tail: |
| i = tail.find('.') |
| if i < 0: i = len(tail) |
| head, tail = tail[:i], tail[i+1:] |
| mname = "%s.%s" % (m.__name__, head) |
| m = import_module(head, mname, m) |
| if not m: |
| raise ImportError, "No module named " + mname |
| return m |
| |
| def ensure_fromlist(m, fromlist, recursive=0): |
| for sub in fromlist: |
| if sub == "*": |
| if not recursive: |
| try: |
| all = m.__all__ |
| except AttributeError: |
| pass |
| else: |
| ensure_fromlist(m, all, 1) |
| continue |
| if sub != "*" and not hasattr(m, sub): |
| subname = "%s.%s" % (m.__name__, sub) |
| submod = import_module(sub, subname, m) |
| if not submod: |
| raise ImportError, "No module named " + subname |
| |
| def import_module(partname, fqname, parent): |
| try: |
| return sys.modules[fqname] |
| except KeyError: |
| pass |
| try: |
| fp, pathname, stuff = imp.find_module(partname, |
| parent and parent.__path__) |
| except ImportError: |
| return None |
| try: |
| m = imp.load_module(fqname, fp, pathname, stuff) |
| finally: |
| if fp: fp.close() |
| if parent: |
| setattr(parent, partname, m) |
| return m |
| |
| |
| # Replacement for reload() |
| def reload_hook(module): |
| name = module.__name__ |
| if '.' not in name: |
| return import_module(name, name, None) |
| i = name.rfind('.') |
| pname = name[:i] |
| parent = sys.modules[pname] |
| return import_module(name[i+1:], name, parent) |
| |
| |
| # Save the original hooks |
| original_import = __builtin__.__import__ |
| original_reload = __builtin__.reload |
| |
| # Now install our hooks |
| __builtin__.__import__ = import_hook |
| __builtin__.reload = reload_hook |