Changeset 792

Show
Ignore:
Timestamp:
08/19/07 15:06:23 (1 year ago)
Author:
robin
Message:

exclusion directory prefixes and arbitrary (post discovery) prunes; and use logging for notification

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • pyrun/trunk/ChangeLog

    r791 r792  
    33 
    440.1.1: 
     5  * Added support for directory exclusions and path prunes. 
     6     exclusion prevents discovery descending into a directory if that 
     7      directory startswith an element in the exclusion set (see new option -x). 
     8     prune operates on the result of the discovery. Any path which 
     9      contains one of the strings specified by a prune is removed from the 
     10      discovered path. 
     11     exclusion hides directories from the discovery process, prune removes 
     12     results after the fact. 
     13     . 
     14     exclusions are enabled by -x 
     15     prunes are enabled by -X 
     16     empty strings are *always* removed from -x and -X. 
     17     . 
     18     Note that no mechanism is provided for adding a path back in *under* 
     19     and excluded directory. 
     20  * Decided to use logging instead of print for notification, I had avoided 
     21    this previously because I did not want to polute the logging configuration 
     22    of the target app. I consider this change provisional, if it causes to 
     23    much trouble I will revert to print 
    524  * Added support for including .pth files in the discovery phase. This 
    625    makes it possible to insert paths to directories which do not contain 
  • pyrun/trunk/pyrun.py

    r791 r792  
    77from os.path import join, dirname, basename, isfile, isdir, exists 
    88from os.path import splitext 
     9 
     10import logging 
     11log = logging.getLogger(__name__) 
    912 
    1013have_runpy=False 
     
    269272 
    270273    pthset = set(kw.pop('pth', [])) 
     274    exclude = kw.pop('exclude', []) 
    271275    pth = [] 
    272276 
    273     evpp = lambda p,name='': evaluate_packagepath(p) 
     277    evpp = lambda p, name='': evaluate_packagepath(p) 
     278 
     279    def allow_descent(path): 
     280        for e in exclude: 
     281            if path.startswith(e): 
     282                log.info('Excluding: "%s" as it startswith "%s" %s' % ( 
     283                    path, e, type(exclude) 
     284                    )) 
     285                return False 
     286        return isdir(path) and not isegg_path(path) 
    274287 
    275288    for rp in rootpaths: 
    276289        ep = evpp(rp) 
     290 
     291        # Don't apply exclude to explicitly listed python files. 
    277292        if ep and ep not in pthset: 
    278293            pthset.add(ep) 
     
    282297            continue 
    283298        for top in find_top_packages(rp, 
    284                 evaluate_packagelocation=evpp 
     299                evaluate_packagelocation=evpp, 
     300                allow_descent=allow_descent 
    285301                ): 
    286302            for p in top[1]: 
     
    303319 
    304320 
    305 def discover_path(offset, *args): 
     321def discover_path(exclude, offset, *args): 
    306322 
    307323    """Discover a python path. 
     
    342358    """ 
    343359 
     360    if exclude is None: 
     361        exclude = frozenset([]) 
    344362    doesnotexist = [] 
    345363    minfos = [] 
     
    369387        elif isfile(a) and splitext(a)[1] == '.pth': 
    370388            if findpaths: 
    371                 newpaths = find_package_paths(pth=pthset, 
     389                newpaths = find_package_paths( 
     390                    pth=pthset, exclude=exclude, 
    372391                    *findpaths 
    373392                    ) 
     
    400419            findpaths.append(a) 
    401420 
    402     newpaths = find_package_paths(pth=pthset, 
     421    newpaths = find_package_paths( 
     422        pth=pthset, exclude=exclude, 
    403423        *findpaths 
    404424        ) 
     
    408428 
    409429 
    410 def discover_and_run(argv=None, run_module=True, modify_sys=True): 
     430def discover_and_run(argv=None, run_module=True, modify_sys=True, 
     431        exclude=frozenset([])): 
    411432    """Discover package paths and run the last module listed in argv. 
    412433 
     
    444465    argv = argv or sys.argv[:] 
    445466 
    446     pthextend, minfos, ia, doesnotexist = discover_path(1, *argv) 
     467    pthextend, minfos, ia, doesnotexist = discover_path(exclude, 1, *argv) 
    447468 
    448469    # We are running the module, eat the artificial `--` delimiter 
     
    570591the sys.argv the module sees.""" 
    571592 
     593def int_log_level(level): 
     594    """Coerce a log level to an integer. 
     595 
     596    In a manner cognizant of run time configured level names.""" 
     597 
     598    try: 
     599        return int(level) 
     600    except ValueError: 
     601        try: 
     602            return getattr(logging, level) 
     603        except AttributeError: 
     604            level = logging.getLevelName(level) 
     605            level = logging.getLevelName(level) 
     606            assert isinstance(level, int) 
     607            return level 
     608 
     609 
    572610def runex(argv=None): 
    573611    """Provides Extened `pyrun` features on the command line.""" 
     
    587625    argv.insert(0, None) 
    588626 
     627    logging.basicConfig( 
     628            level=int_log_level(getattr(opts, 'log_level', 'WARNING')), 
     629            format='%(message)s' 
     630            ) 
     631 
     632    exclude = [] 
     633    if opts.x: 
     634        for e in opts.x.split(os.pathsep): 
     635            if not e: 
     636                log.warning( 
     637                'Warning: empty path found in (and removed from) your ' 
     638                'exclusion path (-x)' 
     639                ) 
     640                continue 
     641            exclude.append(e) 
     642 
     643    prune = [] 
     644    for p in opts.X: 
     645        if not p: 
     646            log.warning( 
     647            'Warning: empty path found in (and removed from) your ' 
     648            'prune list (-X)' 
     649            ) 
     650            continue 
     651        prune.append(p) 
     652 
    589653    try: 
    590654        source = False 
    591655        sourcefile = None 
    592656        if opts.c and opts.C and not opts.q: 
    593             print striplines((''' 
     657            log.warning(striplines((''' 
    594658            Warning: -c and -C can not be used together. Ignoring "-C %s" 
    595             ''' % opts.C) 
     659            ''' % opts.C)) 
    596660            ) 
    597661 
     
    605669 
    606670        pthextend, minfos, ia, doesnotexist = discover_path( 
    607                 1, *argv) 
     671                exclude, 1, *argv) 
    608672 
    609673        if not opts.q and doesnotexist: 
    610             print striplines('''\ 
     674            log.warning(striplines('''\ 
    611675            Warning: your discovery path arguments referenced the following 
    612676            files or directories which do not exist on the file system: 
    613677            ''') 
    614             print '\t' + '\n\t'.join(doesnotexist) 
     678            ) 
     679            log.warning('\t' + '\n\t'.join(doesnotexist)) 
    615680 
    616681 
     
    668733 
    669734        if opts.c and opts.C and not opts.q: 
    670             print
     735            log.warning(
    671736            'Warning: -c and -C can not be used together. Ignoring "-C %s"' 
    672737            ) % opts.C 
     738            ) 
    673739 
    674740        if opts.C: 
     
    681747        modname = not source and (opts.m or (minfos and minfos[0][1]) or '') 
    682748 
     749        # prune and paths which contain *non empty* strings spefcified by -X 
     750        for X in prune: 
     751            if not X: 
     752                log.warning( 
     753                'Warning: An empty string was specified using -X, ' 
     754                'as this would prune *all* paths it will be ignored.' 
     755                ) 
     756                continue 
     757            pthextend[:] = [p for p in pthextend if X not in p] 
     758 
    683759        # Allways update the sys path. pthextend is the record of what we have 
    684760        # done. The record only matters for interative mode in cases where you 
     
    696772        def run(): 
    697773            if opts.n: 
    698                 print 'execution of module disabled by user options' 
     774                log.critical('execution of module disabled by user options') 
    699775                return 0 
    700776            if not target_argv: 
    701                 print 'argv is empty' 
     777                log.critical('argv is empty') 
    702778                return 0 
    703779            sys.argv[:] = target_argv[:] 
     
    808884 
    809885OPTIONS_runex=[ 
     886('--log-level', dict(default=False)), 
    810887('-q', dict(default=False, action='store_true', metavar='QUIET', help= 
    811888"""Suppress all warnings about missing paths etc. Useful when you are 
     
    849926('-c', dict(default=False, metavar='STATEMENT', help= 
    850927"""Update sys.argv and sys.path then execute the statement in a new, clean, 
    851 module context.""")) 
     928module context.""")), 
     929 
     930('-x', dict(default="", metavar='EXCLUDE', help= 
     931"""Exclude one or more directorys, seperated by "%s", from the discovery 
     932path.""" % os.pathsep)), 
     933('-X', dict(default=[], metavar='PRUNE', action="append", type="string", help= 
     934"""Prune all paths which contain this value from the set of paths which *were* 
     935discovered. Specify multiple -X options if you whish too prune based on 
     936more than one string.""")) 
    852937 
    853938    ]