packagescan.py
128 lines
| 4.4 KiB
| text/x-python
|
PythonLexer
/ mercurial / packagescan.py
|
r1308 | # packagescan.py - Helper module for identifing used modules. | ||
|
r1283 | # Used for the py2exe distutil. | ||
|
r2323 | # This module must be the first mercurial module imported in setup.py | ||
|
r1283 | # | ||
|
r2859 | # Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de> | ||
|
r1283 | # | ||
# This software may be used and distributed according to the terms | ||||
# of the GNU General Public License, incorporated herein by reference. | ||||
import glob | ||||
import os | ||||
import sys | ||||
import ihooks | ||||
|
r2322 | import types | ||
import string | ||||
|
r1283 | |||
|
r2323 | # Install this module as fake demandload module | ||
sys.modules['mercurial.demandload'] = sys.modules[__name__] | ||||
# Requiredmodules contains the modules imported by demandload. | ||||
|
r2600 | # Please note that demandload can be invoked before the | ||
|
r2323 | # mercurial.packagescan.scan method is invoked in case a mercurial | ||
# module is imported. | ||||
|
r2600 | requiredmodules = {} | ||
|
r1283 | def demandload(scope, modules): | ||
|
r2600 | """ fake demandload function that collects the required modules | ||
|
r2322 | foo import foo | ||
foo bar import foo, bar | ||||
|
r2993 | foo@bar import foo as bar | ||
|
r2322 | foo.bar import foo.bar | ||
foo:bar from foo import bar | ||||
foo:bar,quux from foo import bar, quux | ||||
foo.bar:quux from foo.bar import quux""" | ||||
|
r1283 | for m in modules.split(): | ||
mod = None | ||||
|
r1841 | try: | ||
|
r2322 | module, fromlist = m.split(':') | ||
fromlist = fromlist.split(',') | ||||
|
r1841 | except: | ||
module = m | ||||
|
r2322 | fromlist = [] | ||
|
r2993 | if '@' in module: | ||
module, as_ = module.split('@') | ||||
|
r2322 | mod = __import__(module, scope, scope, fromlist) | ||
if fromlist == []: | ||||
# mod is only the top package, but we need all packages | ||||
comp = module.split('.') | ||||
i = 1 | ||||
mn = comp[0] | ||||
while True: | ||||
# mn and mod.__name__ might not be the same | ||||
scope[mn] = mod | ||||
requiredmodules[mod.__name__] = 1 | ||||
if len(comp) == i: break | ||||
|
r2600 | mod = getattr(mod,comp[i]) | ||
|
r2322 | mn = string.join(comp[:i+1],'.') | ||
i += 1 | ||||
else: | ||||
# mod is the last package in the component list | ||||
requiredmodules[mod.__name__] = 1 | ||||
for f in fromlist: | ||||
scope[f] = getattr(mod,f) | ||||
if type(scope[f]) == types.ModuleType: | ||||
requiredmodules[scope[f].__name__] = 1 | ||||
|
r1283 | |||
|
r2497 | class SkipPackage(Exception): | ||
def __init__(self, reason): | ||||
self.reason = reason | ||||
scan_in_progress = False | ||||
|
r2323 | def scan(libpath,packagename): | ||
|
r1283 | """ helper for finding all required modules of package <packagename> """ | ||
|
r2497 | global scan_in_progress | ||
scan_in_progress = True | ||||
|
r1283 | # Use the package in the build directory | ||
libpath = os.path.abspath(libpath) | ||||
sys.path.insert(0,libpath) | ||||
|
r2402 | packdir = os.path.join(libpath,packagename.replace('.', '/')) | ||
|
r1308 | # A normal import would not find the package in | ||
|
r1283 | # the build directory. ihook is used to force the import. | ||
|
r1308 | # After the package is imported the import scope for | ||
|
r1283 | # the following imports is settled. | ||
p = importfrom(packdir) | ||||
globals()[packagename] = p | ||||
sys.modules[packagename] = p | ||||
# Fetch the python modules in the package | ||||
cwd = os.getcwd() | ||||
os.chdir(packdir) | ||||
pymodulefiles = glob.glob('*.py') | ||||
extmodulefiles = glob.glob('*.pyd') | ||||
os.chdir(cwd) | ||||
# Import all python modules and by that run the fake demandload | ||||
for m in pymodulefiles: | ||||
if m == '__init__.py': continue | ||||
tmp = {} | ||||
mname,ext = os.path.splitext(m) | ||||
|
r1308 | fullname = packagename+'.'+mname | ||
|
r2497 | try: | ||
__import__(fullname,tmp,tmp) | ||||
except SkipPackage, inst: | ||||
print >> sys.stderr, 'skipping %s: %s' % (fullname, inst.reason) | ||||
continue | ||||
|
r1283 | requiredmodules[fullname] = 1 | ||
# Import all extension modules and by that run the fake demandload | ||||
for m in extmodulefiles: | ||||
tmp = {} | ||||
mname,ext = os.path.splitext(m) | ||||
fullname = packagename+'.'+mname | ||||
__import__(fullname,tmp,tmp) | ||||
requiredmodules[fullname] = 1 | ||||
|
r2323 | |||
def getmodules(): | ||||
return requiredmodules.keys() | ||||
|
r1283 | |||
def importfrom(filename): | ||||
""" | ||||
import module/package from a named file and returns the module. | ||||
It does not check on sys.modules or includes the module in the scope. | ||||
""" | ||||
loader = ihooks.BasicModuleLoader() | ||||
path, file = os.path.split(filename) | ||||
name, ext = os.path.splitext(file) | ||||
m = loader.find_module_in_dir(name, path) | ||||
if not m: | ||||
raise ImportError, name | ||||
m = loader.load_module(name, m) | ||||
return m | ||||