Changeset 748

Show
Ignore:
Timestamp:
07/16/07 20:38:22 (1 year ago)
Author:
robin
Message:

--

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • commando/trunk/commandolite.py

    r747 r748  
    44import signal 
    55import traceback 
     6import inspect 
     7import imp 
    68import logging 
    79import optparse 
    810 
    9 from os.path import abspath, normpath, join, expanduser, isabs, exists, isfile 
     11from os.path import abspath, normpath, join, expanduser, expandvars, dirname 
     12from os.path import isabs, exists, isfile, isdir 
     13 
     14from runpy import get_loader, _get_filename, _run_module_code 
    1015 
    1116log = logging.getLogger(__name__) 
     
    147152# files, file names, paths 
    148153def abs_normpath(path, *parts): 
    149     if parts: 
    150         return normpath( 
    151                 join(abspath(expanduser(path)), expanduser(join(*parts))) 
    152                 ) 
    153     else: 
    154         return normpath( 
    155             join(abspath(expanduser(path))) 
    156             ) 
     154    if not parts: 
     155        return normpath(abspath(expanduser(expandvars(path)))) 
     156    return normpath(join(abspath(expanduser(expandvars(path))), 
     157        expanduser(join(*map(expandvars, parts))))) 
    157158 
    158159def relative_read(filename, *rnames): 
     
    166167    else: 
    167168        log.debug('Directory "%s" already exists' % path) 
     169 
     170 
     171def path_moduleinfo(path, allowmtypes=(imp.PY_SOURCE, imp.PY_COMPILED)): 
     172    """Get extended module info for `path` 
     173 
     174    If path identifies a legitemate python file (as determined by 
     175    inspect.getmoduleinfo) then return a 4 element tuple: 
     176 
     177    (absoloute *parent* of `path`, modname, ext, mode, mtype) 
     178 
     179    modname, ext, mode and mtype are obtained using `inspect.getmoduleinfo` 
     180    Note that for a legitemate path:: 
     181 
     182        path_moduleinfo(path)[1:] == inspect.moduleinfo(path) 
     183 
     184    """ 
     185    v = inspect.getmoduleinfo(path) 
     186    if not v: 
     187        return 
     188    modname, ext, mode, mtype = v 
     189    if mtype not in allowmtypes: 
     190        return None 
     191    abs_path = dirname(normpath(abspath(expanduser(path)))) 
     192    return (abs_path, modname, ext, mode, mtype) 
     193 
     194# from distutils.util, because fools at debian think its a good idea to remove 
     195# distutils from the standard distribution. 
     196def convert_path (pathname): 
     197    """Return 'pathname' as a name that will work on the native filesystem, 
     198    i.e. split it on '/' and put it back together again using the current 
     199    directory separator.  Needed because filenames in the setup script are 
     200    always supplied in Unix style, and have to be converted to the local 
     201    convention before we can actually use them in the filesystem.  Raises 
     202    ValueError on non-Unix-ish systems if 'pathname' either starts or 
     203    ends with a slash. 
     204    """ 
     205    if os.sep == '/': 
     206        return pathname 
     207    if not pathname: 
     208        return pathname 
     209    if pathname[0] == '/': 
     210        raise ValueError, "path '%s' cannot be absolute" % pathname 
     211    if pathname[-1] == '/': 
     212        raise ValueError, "path '%s' cannot end with '/'" % pathname 
     213 
     214    paths = string.split(pathname, '/') 
     215    while '.' in paths: 
     216        paths.remove('.') 
     217    if not paths: 
     218        return os.curdir 
     219    return apply(os.path.join, paths) 
     220 
     221# find_packages from setuptools 
     222def find_packages(where='.', exclude=()): 
     223    """Return a list all Python packages found within directory 'where' 
     224 
     225    'where' should be supplied as a "cross-platform" (i.e. URL-style) path; it 
     226    will be converted to the appropriate local path syntax.  'exclude' is a 
     227    sequence of package names to exclude; '*' can be used as a wildcard in the 
     228    names, such that 'foo.*' will exclude all subpackages of 'foo' (but not 
     229    'foo' itself). 
     230    """ 
     231    out = [] 
     232    stack=[(convert_path(where), '')] 
     233    while stack: 
     234        where,prefix = stack.pop(0) 
     235        for name in os.listdir(where): 
     236            fn = os.path.join(where,name) 
     237            if ('.' not in name and os.path.isdir(fn) and 
     238                os.path.isfile(os.path.join(fn,'__init__.py')) 
     239            ): 
     240                out.append(prefix+name); stack.append((fn,prefix+name+'.')) 
     241    for pat in list(exclude)+['ez_setup']: 
     242        from fnmatch import fnmatchcase 
     243        out = [item for item in out if not fnmatchcase(item,pat)] 
     244    return out 
     245 
     246 
     247def find_top_packages(where='.'): 
     248    tops={} 
     249    out = [] 
     250    stack=[convert_path(where)] 
     251    while stack: 
     252        where = stack.pop(0) 
     253        for name in os.listdir(where): 
     254            fn = join(where,name) 
     255            if isdir(fn): 
     256                if ('.' not in name and isfile(join(fn,'__init__.py'))): 
     257                    tops.setdefault(where, {})[name]=fn 
     258                else: 
     259                    stack.append(fn) 
     260    return tops 
    168261 
    169262#----------------------------------------------------------------------------- 
     
    350443 
    351444#----------------------------------------------------------------------------- 
    352 # main entry point wrappers 
     445# main entry point wrappers and helpers 
     446 
     447def get_module_code(mod_name): 
     448    """like runpy.run_module but dont run.""" 
     449    loader = get_loader(mod_name) 
     450    if loader is None: 
     451        raise ImportError("No module named " + mod_name) 
     452    code = loader.get_code(mod_name) 
     453    if code is None: 
     454        raise ImportError("No code object available for " + mod_name) 
     455    filename = _get_filename(loader, mod_name) 
     456    return filename, code, loader 
     457 
     458 
     459def _path_adder(add_path, added, p, e=None, loginfo=log.info): 
     460    if e is None: 
     461        save_path = (p, sys.path[:]) 
     462        loginfo and loginfo('Adding path: %s' % p) 
     463        add_path(p) 
     464        added.add(p) 
     465        return save_path 
     466    else: 
     467        p, save_path = p 
     468        loginfo and loginfo('Undoing add path: %s' % p) 
     469        added.remove(p) 
     470        sys.path[:] = save_path[:] 
     471 
     472 
     473def pth_addeggs(basedir, add_pathitem, allow_links=True): 
     474    pth = glob(abs_normpath(basedir, '-py'+sys.version[:3]+'*.egg')) 
     475    if allow_links: 
     476        pth[0:0] = glob(abs_normpath(basedir, '*.egg-link')) 
     477    for p in pth: 
     478        add_pathitem(p) 
     479    return pth 
     480 
     481 
     482def pth_import(modulename, fallback_paths, promiscuous_eggpaths=True, 
     483        code_getter=get_module_code, path_adder=None, 
     484        projectversion=False, pth_filename='pyrun.pth', loginfo=log.info): 
     485    """Attempt to obtain the module code for modulename. 
     486 
     487    The following heuristic is used to attempt the import from a variety of 
     488    fallback locations **if the initial get fails**: 
     489 
     490    If any step is successful break out immediately and compute the 
     491    return path. 
     492 
     493    1. Make the first attempt without modifying the path. 
     494 
     495    2. If pth_filename file exists in fallback_paths[0] then extend the 
     496    path, via ``site.addsitedir`` with the directories listed in that file. 
     497 
     498    3. Attempt again. 
     499 
     500    4. If the import failed AND projectversion is not False, 
     501        contstruct a glob 
     502        pattern like this:: 
     503 
     504            abs_normpath(fallback_path_item, 
     505                projectversion+'-py'+sys.version[:3]+'*.egg') 
     506 
     507        and sort the results **in lexically ascending order**. If the result is non 
     508        empty add it to the path and try again 
     509 
     510    repeat 2., 3., 4. for every remaining path in fallback_paths 
     511 
     512    """ 
     513    if not path_adder: 
     514        import site 
     515        # don't want to muck around with site._init_pathinfo and known_paths 
     516        added = set([]) 
     517        def path_adder(p, e=None): 
     518            return _path_adder(site.addsitedir, added, p, e=e, loginfo=loginfo) 
     519 
     520    try: 
     521        modcode = code_getter(modulename) 
     522        return modcode 
     523    except ImportError: 
     524        pass 
     525    for p in fallback_paths: 
     526        if is_zipfile(p) or isdir(p): 
     527            adder_key = path_adder(p) 
     528        try: 
     529            modcode = code_getter(modulename) 
     530            return modcode 
     531        except ImportError, e: 
     532            path_adder(adder_key, e) 
     533            if not projectversion and isdir(p): 
     534                continue 
     535        # glob patterns only apply when a projectversion is supplied and 
     536        # the fallback path is a directory. 
     537        pattern = abs_normpath(p, projectversion+'-py'+sys.version[:3]+'*.egg') 
     538        loginfo and loginfo('egg glob pattern: %s', pattern) 
     539        projecteggs = glob(pattern) 
     540        if not projecteggs or eggpaths: 
     541            continue 
     542        projecteggs.sort() 
     543        adder_key = path_adder(projecteggs[-1]) 
     544        try: 
     545            modcode = code_getter(modulename) 
     546            return modcode 
     547        except ImportError, e: 
     548            path_adder(adder_key, e) 
     549            continue 
     550    raise ImportError('No module named '+modulename) 
     551 
     552 
     553def module_enter(modulename, argv=None, ns=None, program_name=None): 
     554 
     555    if type(modulename) == types.ModuleType: 
     556        mod=modulename 
     557        modulename=mod.__name__ 
     558    else: 
     559        ns=ns or globals() 
     560        mod = __import__( 
     561                modulename, ns, locals(), 
     562                modulename.split('.')[-1]) 
     563    if program_name is None: 
     564        program_name = modulename 
     565    log=logging.getLogger(modulename) 
    353566 
    354567