1 """Find modules used by a script, using introspection."""
11 if sys
.platform
=="win32":
12 # On Windows, we can locate modules in the registry with
13 # the help of the win32api package.
17 print "The win32api module is not available - modules listed"
18 print "in the registry will not be found."
22 IMPORT_NAME
= dis
.opname
.index('IMPORT_NAME')
23 IMPORT_FROM
= dis
.opname
.index('IMPORT_FROM')
25 # Modulefinder does a good job at simulating Python's, but it can not
26 # handle __path__ modifications packages make at runtime. Therefore there
27 # is a mechanism whereby you can register extra paths in this map for a
28 # package, and it will be honoured.
30 # Note this is a mapping is lists of paths.
34 def AddPackagePath(packagename
, path
):
35 paths
= packagePathMap
.get(packagename
, [])
37 packagePathMap
[packagename
] = paths
41 def __init__(self
, name
, file=None, path
=None):
48 s
= "Module(%s" % `self
.__name
__`
49 if self
.__file
__ is not None:
50 s
= s
+ ", %s" % `self
.__file
__`
51 if self
.__path
__ is not None:
52 s
= s
+ ", %s" % `self
.__path
__`
59 def __init__(self
, path
=None, debug
=0, excludes
= []):
67 self
.excludes
= excludes
69 def msg(self
, level
, str, *args
):
70 if level
<= self
.debug
:
71 for i
in range(self
.indent
):
78 def msgin(self
, *args
):
80 if level
<= self
.debug
:
81 self
.indent
= self
.indent
+ 1
84 def msgout(self
, *args
):
86 if level
<= self
.debug
:
87 self
.indent
= self
.indent
- 1
90 def run_script(self
, pathname
):
91 self
.msg(2, "run_script", pathname
)
93 stuff
= ("", "r", imp
.PY_SOURCE
)
94 self
.load_module('__main__', fp
, pathname
, stuff
)
96 def load_file(self
, pathname
):
97 dir, name
= os
.path
.split(pathname
)
98 name
, ext
= os
.path
.splitext(name
)
100 stuff
= (ext
, "r", imp
.PY_SOURCE
)
101 self
.load_module(name
, fp
, pathname
, stuff
)
103 def import_hook(self
, name
, caller
=None, fromlist
=None):
104 self
.msg(3, "import_hook", name
, caller
, fromlist
)
105 parent
= self
.determine_parent(caller
)
106 q
, tail
= self
.find_head_package(parent
, name
)
107 m
= self
.load_tail(q
, tail
)
111 self
.ensure_fromlist(m
, fromlist
)
113 def determine_parent(self
, caller
):
114 self
.msgin(4, "determine_parent", caller
)
116 self
.msgout(4, "determine_parent -> None")
118 pname
= caller
.__name
__
120 parent
= self
.modules
[pname
]
121 assert caller
is parent
122 self
.msgout(4, "determine_parent ->", parent
)
125 i
= string
.rfind(pname
, '.')
127 parent
= self
.modules
[pname
]
128 assert parent
.__name
__ == pname
129 self
.msgout(4, "determine_parent ->", parent
)
131 self
.msgout(4, "determine_parent -> None")
134 def find_head_package(self
, parent
, name
):
135 self
.msgin(4, "find_head_package", parent
, name
)
137 i
= string
.find(name
, '.')
144 qname
= "%s.%s" % (parent
.__name
__, head
)
147 q
= self
.import_module(head
, qname
, parent
)
149 self
.msgout(4, "find_head_package ->", (q
, tail
))
154 q
= self
.import_module(head
, qname
, parent
)
156 self
.msgout(4, "find_head_package ->", (q
, tail
))
158 self
.msgout(4, "raise ImportError: No module named", qname
)
159 raise ImportError, "No module named " + qname
161 def load_tail(self
, q
, tail
):
162 self
.msgin(4, "load_tail", q
, tail
)
165 i
= string
.find(tail
, '.')
166 if i
< 0: i
= len(tail
)
167 head
, tail
= tail
[:i
], tail
[i
+1:]
168 mname
= "%s.%s" % (m
.__name
__, head
)
169 m
= self
.import_module(head
, mname
, m
)
171 self
.msgout(4, "raise ImportError: No module named", mname
)
172 raise ImportError, "No module named " + mname
173 self
.msgout(4, "load_tail ->", m
)
176 def ensure_fromlist(self
, m
, fromlist
, recursive
=0):
177 self
.msg(4, "ensure_fromlist", m
, fromlist
, recursive
)
181 all
= self
.find_all_submodules(m
)
183 self
.ensure_fromlist(m
, all
, 1)
184 elif not hasattr(m
, sub
):
185 subname
= "%s.%s" % (m
.__name
__, sub
)
186 submod
= self
.import_module(sub
, subname
, m
)
188 raise ImportError, "No module named " + subname
190 def find_all_submodules(self
, m
):
194 suffixes
= [".py", ".pyc", ".pyo"]
195 for dir in m
.__path
__:
197 names
= os
.listdir(dir)
199 self
.msg(2, "can't list directory", dir)
203 for suff
in suffixes
:
205 if name
[-n
:] == suff
:
208 if mod
and mod
!= "__init__":
210 return modules
.keys()
212 def import_module(self
, partname
, fqname
, parent
):
213 self
.msgin(3, "import_module", partname
, fqname
, parent
)
215 m
= self
.modules
[fqname
]
219 self
.msgout(3, "import_module ->", m
)
221 if self
.badmodules
.has_key(fqname
):
222 self
.msgout(3, "import_module -> None")
224 self
.badmodules
[fqname
][parent
.__name
__] = None
227 fp
, pathname
, stuff
= self
.find_module(partname
,
228 parent
and parent
.__path
__)
230 self
.msgout(3, "import_module ->", None)
233 m
= self
.load_module(fqname
, fp
, pathname
, stuff
)
237 setattr(parent
, partname
, m
)
238 self
.msgout(3, "import_module ->", m
)
241 def load_module(self
, fqname
, fp
, pathname
, (suffix
, mode
, type)):
242 self
.msgin(2, "load_module", fqname
, fp
and "fp", pathname
)
243 if type == imp
.PKG_DIRECTORY
:
244 m
= self
.load_package(fqname
, pathname
)
245 self
.msgout(2, "load_module ->", m
)
247 if type == imp
.PY_SOURCE
:
248 co
= compile(fp
.read()+'\n', pathname
, 'exec')
249 elif type == imp
.PY_COMPILED
:
250 if fp
.read(4) != imp
.get_magic():
251 self
.msgout(2, "raise ImportError: Bad magic number", pathname
)
252 raise ImportError, "Bad magic number in %s", pathname
254 co
= marshal
.load(fp
)
257 m
= self
.add_module(fqname
)
258 m
.__file
__ = pathname
261 self
.scan_code(co
, m
)
262 self
.msgout(2, "load_module ->", m
)
265 def scan_code(self
, co
, m
):
274 if op
>= dis
.HAVE_ARGUMENT
:
275 oparg
= ord(code
[i
]) + ord(code
[i
+1])*256
277 if op
== IMPORT_NAME
:
278 name
= lastname
= co
.co_names
[oparg
]
279 if not self
.badmodules
.has_key(lastname
):
281 self
.import_hook(name
, m
)
282 except ImportError, msg
:
283 self
.msg(2, "ImportError:", str(msg
))
284 if not self
.badmodules
.has_key(name
):
285 self
.badmodules
[name
] = {}
286 self
.badmodules
[name
][m
.__name
__] = None
287 elif op
== IMPORT_FROM
:
288 name
= co
.co_names
[oparg
]
289 assert lastname
is not None
290 if not self
.badmodules
.has_key(lastname
):
292 self
.import_hook(lastname
, m
, [name
])
293 except ImportError, msg
:
294 self
.msg(2, "ImportError:", str(msg
))
295 fullname
= lastname
+ "." + name
296 if not self
.badmodules
.has_key(fullname
):
297 self
.badmodules
[fullname
] = {}
298 self
.badmodules
[fullname
][m
.__name
__] = None
301 for c
in co
.co_consts
:
302 if isinstance(c
, type(co
)):
305 def load_package(self
, fqname
, pathname
):
306 self
.msgin(2, "load_package", fqname
, pathname
)
307 m
= self
.add_module(fqname
)
308 m
.__file
__ = pathname
309 m
.__path
__ = [pathname
]
311 # As per comment at top of file, simulate runtime __path__ additions.
312 m
.__path
__ = m
.__path
__ + packagePathMap
.get(fqname
, [])
314 fp
, buf
, stuff
= self
.find_module("__init__", m
.__path
__)
315 self
.load_module(fqname
, fp
, buf
, stuff
)
316 self
.msgout(2, "load_package ->", m
)
319 def add_module(self
, fqname
):
320 if self
.modules
.has_key(fqname
):
321 return self
.modules
[fqname
]
322 self
.modules
[fqname
] = m
= Module(fqname
)
325 def find_module(self
, name
, path
):
326 if name
in self
.excludes
:
327 self
.msgout(3, "find_module -> Excluded")
328 raise ImportError, name
331 if name
in sys
.builtin_module_names
:
332 return (None, None, ("", "", imp
.C_BUILTIN
))
334 # Emulate the Registered Module support on Windows.
335 if sys
.platform
=="win32" and win32api
is not None:
336 HKEY_LOCAL_MACHINE
= 0x80000002
338 pathname
= win32api
.RegQueryValue(HKEY_LOCAL_MACHINE
, "Software\\Python\\PythonCore\\%s\\Modules\\%s" % (sys
.winver
, name
))
339 fp
= open(pathname
, "rb")
340 # XXX - To do - remove the hard code of C_EXTENSION.
341 stuff
= "", "rb", imp
.C_EXTENSION
342 return fp
, pathname
, stuff
343 except win32api
.error
:
347 return imp
.find_module(name
, path
)
351 print " %-25s %s" % ("Name", "File")
352 print " %-25s %s" % ("----", "----")
353 # Print modules found
354 keys
= self
.modules
.keys()
357 m
= self
.modules
[key
]
362 print "%-25s" % key
, m
.__file
__ or ""
364 # Print missing modules
365 keys
= self
.badmodules
.keys()
368 # ... but not if they were explicitely excluded.
369 if key
not in self
.excludes
:
370 mods
= self
.badmodules
[key
].keys()
372 print "?", key
, "from", string
.join(mods
, ', ')
379 opts
, args
= getopt
.getopt(sys
.argv
[1:], "dmp:qx:")
380 except getopt
.error
, msg
:
395 addpath
= addpath
+ string
.split(a
, os
.pathsep
)
401 # Provide default arguments
407 # Set the path based on sys.path and the script directory
409 path
[0] = os
.path
.dirname(script
)
410 path
= addpath
+ path
416 # Create the module finder and turn its crank
417 mf
= ModuleFinder(path
, debug
, exclude
)
424 mf
.import_hook(arg
[:-2], None, ["*"])
429 mf
.run_script(script
)
433 if __name__
== '__main__':
436 except KeyboardInterrupt:
437 print "\n[interrupt]"