|
1 """An Python re-implementation of hierarchical module import. |
|
2 |
|
3 This code is intended to be read, not executed. However, it does work |
|
4 -- all you need to do to enable it is "import knee". |
|
5 |
|
6 (The name is a pun on the klunkier predecessor of this module, "ni".) |
|
7 |
|
8 """ |
|
9 |
|
10 import sys, imp, __builtin__ |
|
11 |
|
12 |
|
13 # Replacement for __import__() |
|
14 def import_hook(name, globals=None, locals=None, fromlist=None): |
|
15 parent = determine_parent(globals) |
|
16 q, tail = find_head_package(parent, name) |
|
17 m = load_tail(q, tail) |
|
18 if not fromlist: |
|
19 return q |
|
20 if hasattr(m, "__path__"): |
|
21 ensure_fromlist(m, fromlist) |
|
22 return m |
|
23 |
|
24 def determine_parent(globals): |
|
25 if not globals or not globals.has_key("__name__"): |
|
26 return None |
|
27 pname = globals['__name__'] |
|
28 if globals.has_key("__path__"): |
|
29 parent = sys.modules[pname] |
|
30 assert globals is parent.__dict__ |
|
31 return parent |
|
32 if '.' in pname: |
|
33 i = pname.rfind('.') |
|
34 pname = pname[:i] |
|
35 parent = sys.modules[pname] |
|
36 assert parent.__name__ == pname |
|
37 return parent |
|
38 return None |
|
39 |
|
40 def find_head_package(parent, name): |
|
41 if '.' in name: |
|
42 i = name.find('.') |
|
43 head = name[:i] |
|
44 tail = name[i+1:] |
|
45 else: |
|
46 head = name |
|
47 tail = "" |
|
48 if parent: |
|
49 qname = "%s.%s" % (parent.__name__, head) |
|
50 else: |
|
51 qname = head |
|
52 q = import_module(head, qname, parent) |
|
53 if q: return q, tail |
|
54 if parent: |
|
55 qname = head |
|
56 parent = None |
|
57 q = import_module(head, qname, parent) |
|
58 if q: return q, tail |
|
59 raise ImportError, "No module named " + qname |
|
60 |
|
61 def load_tail(q, tail): |
|
62 m = q |
|
63 while tail: |
|
64 i = tail.find('.') |
|
65 if i < 0: i = len(tail) |
|
66 head, tail = tail[:i], tail[i+1:] |
|
67 mname = "%s.%s" % (m.__name__, head) |
|
68 m = import_module(head, mname, m) |
|
69 if not m: |
|
70 raise ImportError, "No module named " + mname |
|
71 return m |
|
72 |
|
73 def ensure_fromlist(m, fromlist, recursive=0): |
|
74 for sub in fromlist: |
|
75 if sub == "*": |
|
76 if not recursive: |
|
77 try: |
|
78 all = m.__all__ |
|
79 except AttributeError: |
|
80 pass |
|
81 else: |
|
82 ensure_fromlist(m, all, 1) |
|
83 continue |
|
84 if sub != "*" and not hasattr(m, sub): |
|
85 subname = "%s.%s" % (m.__name__, sub) |
|
86 submod = import_module(sub, subname, m) |
|
87 if not submod: |
|
88 raise ImportError, "No module named " + subname |
|
89 |
|
90 def import_module(partname, fqname, parent): |
|
91 try: |
|
92 return sys.modules[fqname] |
|
93 except KeyError: |
|
94 pass |
|
95 try: |
|
96 fp, pathname, stuff = imp.find_module(partname, |
|
97 parent and parent.__path__) |
|
98 except ImportError: |
|
99 return None |
|
100 try: |
|
101 m = imp.load_module(fqname, fp, pathname, stuff) |
|
102 finally: |
|
103 if fp: fp.close() |
|
104 if parent: |
|
105 setattr(parent, partname, m) |
|
106 return m |
|
107 |
|
108 |
|
109 # Replacement for reload() |
|
110 def reload_hook(module): |
|
111 name = module.__name__ |
|
112 if '.' not in name: |
|
113 return import_module(name, name, None) |
|
114 i = name.rfind('.') |
|
115 pname = name[:i] |
|
116 parent = sys.modules[pname] |
|
117 return import_module(name[i+1:], name, parent) |
|
118 |
|
119 |
|
120 # Save the original hooks |
|
121 original_import = __builtin__.__import__ |
|
122 original_reload = __builtin__.reload |
|
123 |
|
124 # Now install our hooks |
|
125 __builtin__.__import__ = import_hook |
|
126 __builtin__.reload = reload_hook |