diff --git a/iu.py b/iu.py index 1e432f4..cdd5173 100644 --- a/iu.py +++ b/iu.py @@ -1,4 +1,6 @@ +# # Copyright (C) 2005, Giovanni Bajo +# # Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc. # # This program is free software; you can redistribute it and/or @@ -22,8 +24,11 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - +# +# # **NOTE** This module is used during bootstrap. Import *ONLY* builtin modules. +# + import sys import imp import marshal @@ -39,6 +44,11 @@ try: except ImportError: zipimport = None +try: + STRINGTYPE = basestring +except NameError: + STRINGTYPE = type("") + #=======================Owners==========================# # An Owner does imports from a particular piece of turf # That is, there's an Owner for each thing on sys.path @@ -48,21 +58,22 @@ except ImportError: # sys.path to their owners) is used so that sys.path # (or a package's __path__) is still a bunch of strings, -STRINGTYPE = type('') - class OwnerError(IOError): - def __init__(self, msg): - self.msg = msg def __str__(self): - return "" % self.msg + return "" % self.message + class Owner: def __init__(self, path): self.path = path + def __str__(self): return self.path + def getmod(self, nm): return None + + class DirOwner(Owner): def __init__(self, path): if path == '': @@ -70,7 +81,9 @@ class DirOwner(Owner): if not pathisdir(path): raise OwnerError("%s is not a directory" % path) Owner.__init__(self, path) - def getmod(self, nm, getsuffixes=imp.get_suffixes, loadco=marshal.loads, newmod=imp.new_module): + + def getmod(self, nm, getsuffixes=imp.get_suffixes, + loadco=marshal.loads, newmod=imp.new_module): pth = _os_path_join(self.path, nm) possibles = [(pth, 0, None)] if pathisdir(pth): @@ -124,6 +137,7 @@ class DirOwner(Owner): mod.__co__ = co return mod + ZipOwner = None if zipimport: class ZipOwner(Owner): @@ -156,17 +170,21 @@ _globalownertypes = filter(None, [ class ImportDirector(Owner): pass + class BuiltinImportDirector(ImportDirector): def __init__(self): self.path = 'Builtins' + def getmod(self, nm, isbuiltin=imp.is_builtin): if isbuiltin(nm): mod = imp.load_module(nm, None, nm, ('','',imp.C_BUILTIN)) return mod return None + class FrozenImportDirector(ImportDirector): def __init__(self): self.path = 'FrozenModules' + def getmod(self, nm, isfrozen=imp.is_frozen): if isfrozen(nm): mod = imp.load_module(nm, None, nm, ('','',imp.PY_FROZEN)) @@ -174,6 +192,7 @@ class FrozenImportDirector(ImportDirector): mod.__importsub__ = lambda name, pname=nm, owner=self: owner.getmod(pname+'.'+name) return mod return None + class RegistryImportDirector(ImportDirector): # for Windows only def __init__(self): @@ -209,6 +228,7 @@ class RegistryImportDirector(ImportDirector): hskey.Close() hkey.Close() break + def getmod(self, nm): stuff = self.map.get(nm) if stuff: @@ -235,8 +255,10 @@ class PathImportDirector(ImportDirector): self.shadowpath = {} self.inMakeOwner = 0 self.building = {} + def __str__(self): return str(self.path) + def getmod(self, nm): mod = None for thing in self.path: @@ -251,6 +273,7 @@ class PathImportDirector(ImportDirector): if mod: break return mod + def makeOwner(self, path): if self.building.get(path): return None @@ -283,9 +306,11 @@ UNTRIED = -1 class ImportManagerException(Exception): def __init__(self, args): self.args = args + def __repr__(self): return "<%s: %s>" % (self.__name__, self.args) + class ImportManager: # really the equivalent of builtin import def __init__(self): @@ -299,6 +324,7 @@ class ImportManager: self.rlock = None self.locker = None self.setThreaded() + def setThreaded(self): thread = sys.modules.get('thread', None) if thread and not self.threaded: @@ -306,10 +332,12 @@ class ImportManager: self.threaded = 1 self.rlock = thread.allocate_lock() self._get_ident = thread.get_ident + def install(self): import __builtin__ __builtin__.__import__ = self.importHook __builtin__.reload = self.reloadHook + def importHook(self, name, globals=None, locals=None, fromlist=None, level=-1): # first see if we could be importing a relative name #print "importHook(%s, %s, locals, %s)" % (name, getattr(globals, '__name__', None), fromlist) @@ -397,6 +425,7 @@ class ImportManager: self._release() #print "importHook done with %s %s %s (case 3)" % (name, globals['__name__'], fromlist) return bottommod + def doimport(self, nm, parentnm, fqname, reload=0): # Not that nm is NEVER a dotted name at this point #print "doimport(%s, %s, %s)" % (nm, parentnm, fqname) @@ -448,12 +477,13 @@ class ImportManager: delattr(parent, nm) raise if fqname == 'thread' and not self.threaded: -## print "thread detected!" + #print "thread detected!" self.setThreaded() else: sys.modules[fqname] = None #print "..found %s" % mod, 'when looking for', fqname return mod + def reloadHook(self, mod): fqnm = mod.__name__ nm = namesplit(fqnm)[-1] @@ -461,26 +491,28 @@ class ImportManager: newmod = self.doimport(nm, parentnm, fqnm, reload=1) #mod.__dict__.update(newmod.__dict__) return newmod + def _acquire(self): if self.rlock.locked(): if self.locker == self._get_ident(): self.lockcount = self.lockcount + 1 -## print "_acquire incrementing lockcount to", self.lockcount + #print "_acquire incrementing lockcount to", self.lockcount return self.rlock.acquire() self.locker = self._get_ident() self.lockcount = 0 -## print "_acquire first time!" + #print "_acquire first time!" + def _release(self): if self.lockcount: self.lockcount = self.lockcount - 1 -## print "_release decrementing lockcount to", self.lockcount + #print "_release decrementing lockcount to", self.lockcount else: self.locker = None self.rlock.release() -## print "_release releasing lock!" + #print "_release releasing lock!" -#=========some helper functions=============================# +#========= some helper functions =============================# def packagename(s): for i in range(len(s)-1, -1, -1): @@ -515,31 +547,53 @@ def pathisdir(pathname): return None return (s[0] & 0170000) == 0040000 + _os_stat = _os_path_join = _os_getcwd = _os_path_dirname = None + def _os_bootstrap(): "Set up 'os' module replacement functions for use during import bootstrap." + global _os_stat, _os_path_join, _os_path_dirname, _os_getcwd + + def join(a, b, sep=sep): + if a == '': + return b + lastchar = a[-1:] + if lastchar == '/' or lastchar == sep: + return a + b + return a + sep + b + + def dirname(a, sep=sep, mindirlen=mindirlen): + for i in range(len(a)-1, -1, -1): + c = a[i] + if c == '/' or c == sep: + if i < mindirlen: + return a[:i+1] + return a[:i] + return '' + names = sys.builtin_module_names join = dirname = None mindirlen = 0 if 'posix' in names: + from posix import stat, getcwd sep = '/' mindirlen = 1 - from posix import stat, getcwd elif 'nt' in names: - sep = '\\' - mindirlen = 3 from nt import stat, getcwd - elif 'dos' in names: sep = '\\' mindirlen = 3 + elif 'dos' in names: from dos import stat, getcwd - elif 'os2' in names: sep = '\\' + mindirlen = 3 + elif 'os2' in names: from os2 import stat, getcwd + sep = '\\' elif 'mac' in names: from mac import stat, getcwd + # overwrite join(): def join(a, b): if a == '': return b @@ -552,38 +606,14 @@ def _os_bootstrap(): else: raise ImportError, 'no os specific module found' - if join is None: - def join(a, b, sep=sep): - if a == '': - return b - lastchar = a[-1:] - if lastchar == '/' or lastchar == sep: - return a + b - return a + sep + b - - if dirname is None: - def dirname(a, sep=sep, mindirlen=mindirlen): - for i in range(len(a)-1, -1, -1): - c = a[i] - if c == '/' or c == sep: - if i < mindirlen: - return a[:i+1] - return a[:i] - return '' - - global _os_stat _os_stat = stat - - global _os_path_join + _os_getcwd = getcwd _os_path_join = join - - global _os_path_dirname _os_path_dirname = dirname - global _os_getcwd - _os_getcwd = getcwd _string_replace = _string_join = _string_split = None + def _string_bootstrap(): """ Set up 'string' module replacement functions for use during import bootstrap. @@ -592,51 +622,40 @@ def _string_bootstrap(): yet. For Python 2.0+, we can use string methods so this is not a problem. For Python 1.5, we would need the string module, so we need replacements. """ - s = type('') - global _string_replace, _string_join, _string_split - if hasattr(s, "join"): - _string_join = s.join - else: - def join(sep, words): - res = '' - for w in words: - res = res + (sep + w) - return res[len(sep):] - _string_join = join + def join(sep, words): + res = '' + for w in words: + res = res + (sep + w) + return res[len(sep):] - if hasattr(s, "split"): - _string_split = s.split - else: - def split(s, sep, maxsplit=0): - res = [] - nsep = len(sep) - if nsep == 0: - return [s] - ns = len(s) - if maxsplit <= 0: maxsplit = ns - i = j = 0 - count = 0 - while j+nsep <= ns: - if s[j:j+nsep] == sep: - count = count + 1 - res.append(s[i:j]) - i = j = j + nsep - if count >= maxsplit: break - else: - j = j + 1 - res.append(s[i:]) - return res - _string_split = split + def split(s, sep, maxsplit=0): + res = [] + nsep = len(sep) + if nsep == 0: + return [s] + ns = len(s) + if maxsplit <= 0: maxsplit = ns + i = j = 0 + count = 0 + while j+nsep <= ns: + if s[j:j+nsep] == sep: + count = count + 1 + res.append(s[i:j]) + i = j = j + nsep + if count >= maxsplit: break + else: + j = j + 1 + res.append(s[i:]) + return res - if hasattr(s, "replace"): - _string_replace = s.replace - else: - def replace(str, old, new): - return _string_join(new, _string_split(str, old)) - _string_replace = replace + def replace(str, old, new): + return _string_join(new, _string_split(str, old)) + _string_join = getattr(STRINGTYPE, "join", join) + _string_split = getattr(STRINGTYPE, "split", split) + _string_replace = getattr(STRINGTYPE, "replace", replace) _os_bootstrap() diff --git a/mf.py b/mf.py index 03e28c2..f7c0bda 100644 --- a/mf.py +++ b/mf.py @@ -27,18 +27,6 @@ except ImportError: import suffixes -#=======================Owners==========================# -# An Owner does imports from a particular piece of turf -# That is, there's an Owner for each thing on sys.path -# There are owners for directories and .pyz files. -# There could be owners for zip files, or even URLs. -# Note that they replace the string in sys.path, -# but str(sys.path[n]) should yield the original string. - -try: - STRINGTYPE = basestring -except NameError: - STRINGTYPE = type("") if not os.environ.has_key('PYTHONCASEOK') and sys.version_info >= (2, 1): def caseOk(filename): @@ -57,12 +45,22 @@ def pyco(): else: return 'o' +#=======================Owners==========================# +# An Owner does imports from a particular piece of turf +# That is, there's an Owner for each thing on sys.path +# There are owners for directories and .pyz files. +# There could be owners for zip files, or even URLs. +# Note that they replace the string in sys.path, +# but str(sys.path[n]) should yield the original string. + class Owner: def __init__(self, path, target_platform=None): self.path = path self.target_platform = target_platform + def __str__(self): return self.path + def getmod(self, nm): return None @@ -142,6 +140,7 @@ class DirOwner(Owner): #print "DirOwner.getmod -> %s" % mod return mod + class PYZOwner(Owner): def __init__(self, path, target_platform=None): import archive @@ -155,6 +154,7 @@ class PYZOwner(Owner): return PkgInPYZModule(nm, co, self) return PyModule(nm, self.path, co) + ZipOwner = None if zipimport: class ZipOwner(Owner): @@ -186,20 +186,25 @@ _globalownertypes = filter(None, [ class ImportDirector(Owner): pass + class BuiltinImportDirector(ImportDirector): def __init__(self): self.path = 'Builtins' + def getmod(self, nm, isbuiltin=imp.is_builtin): if isbuiltin(nm): return BuiltinModule(nm) return None + class FrozenImportDirector(ImportDirector): def __init__(self): self.path = 'FrozenModules' + def getmod(self, nm, isfrozen=imp.is_frozen): if isfrozen(nm): return FrozenModule(nm) return None + class RegistryImportDirector(ImportDirector): # for Windows only def __init__(self): @@ -232,6 +237,7 @@ class RegistryImportDirector(ImportDirector): hskey.Close() hkey.Close() break + def getmod(self, nm): stuff = self.map.get(nm) if stuff: @@ -318,6 +324,7 @@ def getDescr(fnm): # This one doesn't really import, just analyzes # If it *were* importing, it would be the one-and-only ImportManager # ie, the builtin import + UNTRIED = -1 imptyps = ['top-level', 'conditional', 'delayed', 'delayed, conditional'] @@ -538,6 +545,7 @@ class ImportTracker: # self.modules[fqname] = mod # here return mod + def getwarnings(self): warnings = self.warnings.keys() for nm,mod in self.modules.items(): @@ -545,6 +553,7 @@ class ImportTracker: for w in mod.warnings: warnings.append(w+' - %s (%s)' % (mod.__name__, mod.__file__)) return warnings + def getxref(self): mods = self.modules.items() # (nm, mod) mods.sort() @@ -563,6 +572,7 @@ class ImportTracker: class Module: _ispkg = 0 typ = 'UNKNOWN' + def __init__(self, nm): self.__name__ = nm self.__file__ = None @@ -570,28 +580,35 @@ class Module: self.imports = [] self.warnings = [] self._xref = {} + def ispackage(self): return self._ispkg + def doimport(self, nm): pass + def xref(self, nm): self._xref[nm] = 1 + def __str__(self): return "" % (self.__name__, self.__file__, self.imports) class BuiltinModule(Module): typ = 'BUILTIN' + def __init__(self, nm): Module.__init__(self, nm) class ExtensionModule(Module): typ = 'EXTENSION' + def __init__(self, nm, pth): Module.__init__(self, nm) self.__file__ = pth class PyModule(Module): typ = 'PYMODULE' + def __init__(self, nm, pth, co): Module.__init__(self, nm) self.co = co @@ -599,6 +616,7 @@ class PyModule(Module): if os.path.splitext(self.__file__)[1] == '.py': self.__file__ = self.__file__ + pyco() self.scancode() + def scancode(self): self.imports, self.warnings, allnms = scan_code(self.co) if allnms: @@ -606,23 +624,28 @@ class PyModule(Module): class PyScript(PyModule): typ = 'PYSOURCE' + def __init__(self, pth, co): Module.__init__(self, '__main__') self.co = co self.__file__ = pth self.scancode() + class PkgModule(PyModule): typ = 'PYMODULE' + def __init__(self, nm, pth, co): PyModule.__init__(self, nm, pth, co) self._ispkg = 1 pth = os.path.dirname(pth) self.__path__ = [ pth ] self._update_director(force=True) + def _update_director(self, force=False): if force or self.subimporter.path != self.__path__: self.subimporter = PathImportDirector(self.__path__) + def doimport(self, nm): self._update_director() mod = self.subimporter.getmod(nm) @@ -636,10 +659,12 @@ class PkgInPYZModule(PyModule): self._ispkg = 1 self.__path__ = [ str(pyzowner) ] self.owner = pyzowner + def doimport(self, nm): mod = self.owner.getmod(self.__name__ + '.' + nm) return mod + class PkgInZipModule(PyModule): typ = 'ZIPFILE' def __init__(self, nm, co, pyzowner): @@ -647,10 +672,12 @@ class PkgInZipModule(PyModule): self._ispkg = 0 self.__path__ = [ str(pyzowner) ] self.owner = pyzowner + def doimport(self, nm): mod = self.owner.getmod(self.__name__ + '.' + nm) return mod + #======================== Utility ================================# # Scan the code object for imports, __all__ and wierd stuff