Changeset 119

Show
Ignore:
Timestamp:
Wed Nov 15 13:24:21 2006
Author:
jpellerin
Message:

Work in progress on new loader/selector

Files:

Legend:

Unmodified
Added
Removed
Modified
  • branches/new_loader/nose/selector.py

    r116 r119  
    59 59         self.match = conf.testMatch         
    60 60         self.tests = conf.tests  
      61  
      62     def fileInTests(self, tests):  
      63         if tests is None:  
      64             def in_tests(file):  
      65                 return True  
      66         else:  
      67             def in_tests(file):  
      68                 return filter(None,  
      69                               [ t.matches_file(file) for t in tests ])  
      70         return in_tests  
    61 71                        
    62       def fileInTests(self, file):  
      72     def _fileInTests(self, file):  
    62 72         orig = file  
    63 73         if not os.path.isabs(file):  
     
    144 154                                    [exc.search(name) for exc in self.exclude])  
    145 155                  ))  
      156  
      157     def methodInTests(self, tests):  
      158         if tests is None:  
      159             def in_tests(method):  
      160                 return True  
      161         else:  
      162             def in_tests(method):  
      163                 return filter(None,  
      164                               [ t.matches_method(method) for t in tests ])  
      165         return in_tests  
    146 166      
    147       def methodInTests(self, method):  
      167     def _methodInTests(self, method):  
    147 167         """Determine if a method is listed in the requested tests. To  
    148 168         be consideed a match, the method's class must be in the class  
     
    163 183         return self.anytest(match)  
    164 184  
    165       def moduleInTests(self, module, either=False):  
      185     def moduleInTests(self, tests, either=False):  
      186         """Return a function that can tell whether a module is in this  
      187         batch of tests.  
      188  
      189         FIXME: it would be good to memoize this  
      190         """         
      191         if tests is None:  
      192             def in_tests(module):  
      193                 return True  
      194         else:  
      195             def in_tests(module):  
      196                 return filter(None,  
      197                               [ t.matches_module(module, either)  
      198                                 for t in tests ])  
      199         return in_tests  
      200  
      201     def _moduleInTests(self, module, either=False):  
    166 202         def match(filename, modname, funcname, module=module, either=either):  
    167 203             log.debug("Checking module %s in test %s:%s (either: %s)",  
     
    187 223         return res  
    188 224      
    189       def wantClass(self, cls):  
      225     def wantClass(self, cls, tests=None):  
    189 225         """Is the class a wanted test class?  
    190 226  
     
    206 242             log.debug("Plugin setting selection of %s to %s", cls, plug_wants)  
    207 243             wanted = plug_wants  
    208           return wanted and self.classInTests(cls)  
      244         return wanted and self.classInTests(tests)(cls)  
    208 244  
    209       def wantDirectory(self, dirname):  
      245     def wantDirectory(self, dirname, tests=None):  
    209 245         """Is the directory a wanted test directory?  
    210 246  
     
    214 250         All other directories must match test requirements.  
    215 251         """  
      252         log.debug("Want directory %s (%s)?", dirname, tests)  
      253  
    216 254         init = os.path.join(dirname, '__init__.py')  
    217           tail = os.path.basename(dirname)                  
      255         tail = os.path.basename(dirname)     
    217 255         if os.path.exists(init):  
    218 256             wanted = (not self.exclude  
     
    229 267         if plug_wants is not None:  
    230 268             wanted = plug_wants  
    231           # FIXME in tests?  
    232           return wanted  
      269         in_tests = self.fileInTests(tests)(dirname)  
      270         log.debug("wantDirectory wanted %s, in_tests %s", wanted, in_tests)  
      271         return wanted and in_tests  
    233 272      
    234       def wantFile(self, file, package=None):  
      273     def wantFile(self, file, package=None, tests=None):  
    234 273         """Is the file a wanted test file?  
    235 274  
     
    255 294             log.info('%s is executable; skipped', file)  
    256 295             return False  
    257           in_tests = self.fileInTests(file)  
      296         in_tests = self.fileInTests(tests)(file)  
    257 296         if not in_tests:  
    258 297             return False  
     
    268 307         return wanted or (pysrc and self.tests and in_tests)  
    269 308  
    270       def wantFunction(self, function):  
      309     def wantFunction(self, function, tests=None):  
    270 309         """Is the function a test function?  
    271 310  
     
    280 319             # not a function  
    281 320             return False  
    282           in_tests = self.funcInTests(function)  
      321         in_tests = self.funcInTests(tests)(function)  
    282 321         if not in_tests:  
    283 322             return False     
     
    289 328         return wanted  
    290 329  
    291       def wantMethod(self, method):  
      330     def wantMethod(self, method, tests=None):  
    291 330         """Is the method a test method?  
    292 331                  
     
    304 343             # never collect 'private' methods  
    305 344             return False  
    306           in_tests = self.methodInTests(method)  
      345         in_tests = self.methodInTests(tests)(method)  
    306 345         if not in_tests:  
    307 346             return False         
     
    313 352         return wanted  
    314 353      
    315       def wantModule(self, module):  
      354     def wantModule(self, module, tests=None):  
    315 354         """Is the module a test module?  
    316 355  
     
    323 362         modules where wantModuleTests() is true.  
    324 363         """  
    325           in_tests = self.moduleInTests(module, either=True)  
      364         in_tests = self.moduleInTests(tests, either=True)(module)  
    325 364         if not in_tests:  
    326 365             return False         
     
    332 371         return wanted or (self.tests and in_tests)  
    333 372  
    334       def wantModuleTests(self, module):  
      373     def wantModuleTests(self, module, tests=None):  
    334 373         """Collect tests from this module?  
    335 374  
     
    343 382         tests, but instead cause the standard collector to collect tests.  
    344 383         """  
    345           in_tests = self.moduleInTests(module)  
      384         in_tests = self.moduleInTests(tests)(module)  
    345 384         if not in_tests:  
    346 385             return False  
     
    358 397 defaultSelector = Selector         
    359 398  
      399  
      400 class TestAddress(object):  
      401     """A test address represents a user's request to run a particular  
      402     test. The user may specify a filename or module (or neither),  
      403     and/or a callable (a class, function, or method). The naming  
      404     format for test addresses is:  
      405  
      406     filename_or_module:callable  
      407  
      408     Filenames that are not absolute will be made absolute relative to  
      409     the working dir.  
      410  
      411     The filename or module part will be considered a module name if it  
      412     doesn't look like a file, that is, if it doesn't exist on the file  
      413     system and it doesn't contain any directory separators and it  
      414     doesn't end in .py.  
      415  
      416     Callables may be a class name, function name, method name, or  
      417     class.method specification.  
      418     """  
      419     def __init__(self, name, working_dir):  
      420         self.name = name  
      421         self.working_dir = working_dir  
      422         self.filename, self.module, self.call = split_test_name(name)  
      423         if not self.filename is None and not os.path.isabs(self.filename):  
      424             self.filename = os.path.abspath(os.path.join(working_dir,  
      425                                                          self.filename))  
      426  
      427     def __str__(self):  
      428         return self.name  
      429  
      430     def __repr__(self):  
      431         return "%s: (%s, %s, %s)" % (self.name, self.filename,  
      432                                      self.module, self.call)  
      433  
      434     def matches_class(self, cls):  
      435         """Does the class match my call part?  
      436         """  
      437         if self.call is None:  
      438             return True  
      439          
      440     def matches_file(self, filename):  
      441         fn = self.filename  
      442         if fn is None:  
      443             return self.matches_file_as_module(filename)  
      444         if fn.endswith('__init__.py'):  
      445             dn = os.path.dn(fn)  
      446         elif os.path.isdir(fn):  
      447             dn = fn  
      448         else:  
      449             dn = None  
      450         if os.path.isdir(filename):  
      451             dirname = filename  
      452         else:  
      453             dirname = None  
      454         # filename might be a directory and fn a file in that directory  
      455         # if so the directory has to match for us to continue on?  
      456         return (fn == filename  
      457                 or (dn is not None  
      458                     and (filename.startswith(dn)  
      459                          and len(filename) > len(dn)  
      460                          and filename[len(dn)] == os.path.sep)  
      461                     or (filename == dn))  
      462                 or (dirname is not None  
      463                     and (dirname == fn  
      464                          or (fn.startswith(dirname)  
      465                              and len(fn) > len(dirname)  
      466                              and fn[len(dirname)] == os.path.sep))))  
      467  
      468     def matches_file_as_module(self, filename):  
      469         """Match filename vs our module part. Convert our module into  
      470         a path fragment, and return True if the filename contains that  
      471         path fragment. This method should only be called when self.filename  
      472         is None.  
      473         """         
      474         mn = self.module  
      475         if mn is None:  
      476             # No filename or modname part; so we match any module, because  
      477             # the only part we have defined is the call, which could be  
      478             # in any module  
      479             return True  
      480         mpath = os.path.sep.join(mn.split('.'))  
      481         return mpath in os.path.splitext(filename)[0]  
      482  
      483     def matches_function(self, function):  
      484         """Does the function match my call part?  
      485         """  
      486         if self.call is None:  
      487             return True  
      488      
      489     def matches_method(self, method):  
      490         """Does the method match my call part?  
      491         """  
      492         if self.call is None:  
      493             return True  
      494      
      495     def matches_module(self, module, either=False):  
      496         """Either = either my module can be a child of module or  
      497         module can be a child of my module. Without either, the  
      498         match is valid only if module is a child of my module.  
      499         """  
      500         pass  
      501  
    360 502 # Helpers  
    361 503  
  • branches/new_loader/work.py

    r118 r119  
    2 2 import re  
    3 3 from imp import load_source  
    4   from nose.selector import Selector  
      4 from nose.selector import Selector, TestAddress  
    4 4 from nose.config import Config  
    5 5 from nose.importer import _import  
     
    8 8  
    9 9 import logging  
    10   logging.basicConfig()  
    11   logging.getLogger('').setLevel(0)  
      10 # logging.basicConfig()  
      11 # logging.getLogger('').setLevel(0)  
    12 12  
    13 13 conf = Config()  
    14 14 selector = Selector(conf)  
    15 15  
      16  
    16 17 def ispackage(dirname):  
    17 18     return os.path.exists(os.path.join(dirname, '__init__.py'))  
     
    31 32  
    32 33  
    33   class TestAddress:  
    34       def __init__(self, name, working_dir):  
    35           self.name = name  
    36           self.working_dir = working_dir  
    37           self.filename, self.module, self.call = split_test_name(name)  
    38           if not self.filename is None and not os.path.isabs(self.filename):  
    39               self.filename = os.path.abspath(os.path.join(working_dir,  
    40                                                            self.filename))  
    41    
    42       def __str__(self):  
    43           return self.name  
    44    
    45       def __repr__(self):  
    46           return "%s: (%s, %s, %s)" % (self.name, self.filename,  
    47                                        self.module, self.call)  
    48            
    49       def matches_file(self, filename):  
    50           fn = self.filename  
    51           if fn is None:  
    52               return self.matches_file_as_module(filename)  
    53           if fn.endswith('__init__.py'):  
    54               dn = os.path.dn(fn)  
    55           elif os.path.isdir(fn):  
    56               dn = fn  
    57           else:  
    58               dn = None  
    59           if os.path.isdir(filename):  
    60               dirname = filename  
    61           else:  
    62               dirname = None  
    63           # filename might be a directory and fn a file in that directory  
    64           # if so the directory has to match for us to continue on?  
    65           return (fn == filename  
    66                   or (dn is not None  
    67                       and (filename.startswith(dn)  
    68                            and len(filename) > len(dn)  
    69                            and filename[len(dn)] == os.path.sep)  
    70                       or (filename == dn))  
    71                   or (dirname is not None  
    72                       and (dirname == fn  
    73                            or (fn.startswith(dirname)  
    74                                and len(fn) > len(dirname)  
    75                                and fn[len(dirname)] == os.path.sep))))  
    76    
    77       def matches_file_as_module(self, filename):  
    78           """Match filename vs our module. Convert our module into  
    79           a path fragment, and return True if the filename contains that  
    80           path fragment.  
    81           """         
    82           mn = self.module  
    83           if mn is None:  
    84               return False  
    85           mpath = os.path.sep.join(mn.split('.'))  
    86           return mpath in os.path.splitext(filename)[0]  
    87                
    88    
    89 34 class ModuleSuite:  
    90       def __init__(self, name, path, loader, working_dir, wanted):  
      35     def __init__(self, name, path, loader, working_dir, tests):  
    90 35         self.name = name  
    91 36         self.path = path  
     
    94 39         self.loader = loader  
    95 40         self.working_dir = working_dir  
    96           self.wanted = wanted  
      41         self.tests = tests  
      42         self._collected = False  
    97 43         self._tests = []  
    98 44  
     
    118 64  
    119 65     def collectTests(self):  
    120           if self._tests:  
      66         # print "Collect Tests %s" % self  
      67         if self._collected or self._tests:  
    121 68             return  
      69         self._collected = True  
    122 70         self._tests = []  
    123 71         if self.module is None:  
     
    126 74             # if it's a package) to sys.path first, though  
    127 75             self.module = load_source(self.name, self.path)  
    128           for test in self.loader.loadTestsFromModule(self.module, self.wanted):  
      76         for test in self.loader.loadTestsFromModule(self.module, self.tests):  
    128 76             self.addTest(test)  
    129 77          
    130 78     def run(self, result):  
    131 79         self.collectTests()  
    132           if not self._tests:  
      80         if not self:  
    132 80             return  
    133 81         # FIXME this needs to be a real run() with exc handling  
     
    144 92     def tearDown(self):  
    145 93         print "TEARDOWN %s" % self  
    146    
    147 94          
    148 95          
     
    155 102         if names:  
    156 103             tests = [ TestAddress(n, working_dir) for n in names ]  
    157           if tests is not None:  
    158               def intests(filename):  
    159                   return filter(None,  
    160                                 [ t.matches_file(filename) for t in tests ])  
    161           else:  
    162               def intests(filename):  
    163                   return True  
    164           return self.findTests(working_dir, wanted=intests)  
      104         return self.findTests(working_dir, tests=tests)  
    165 105      
    166       def findTests(self, working_dir, wanted=None, package=None):  
      106     def findTests(self, working_dir, tests=None, package=None):  
    166 106         for dirpath, dirnames, filenames in os.walk(working_dir):  
    167 107  
     
    178 118                 remove = True  
    179 119                 ldir = os.path.join(dirpath, dirname)  
    180                   pack = ispackage(ldir)  
    181                   if ((pack or conf.testMatch.search(dirname))  
    182                       and wanted(ldir)):  
    183                       if pack:  
      120                 if selector.wantDirectory(ldir, tests=tests):  
      121                     if ispackage(ldir):  
    184 122                         remove = True  
    185                           # print "**",ldir  
    186                           # FIXME track this, we'll yield a ModuleSuite later  
      123                         # we'll yield a ModuleSuite later  
    187 124                         packages.append((dirname,  
    188 125                                          os.path.join(ldir, '__init__.py')))  
    189 126                     else:  
    190 127                         remove = False  
      128                         # print "Continue into %s" % ldir  
    191 129                 if remove:  
    192 130                     to_remove.add(dirname)  
     
    194 132                 dirnames.remove(dirname)  
    195 133  
    196               # FIXME store dirs that we're going to yield as ModuleSuites  
    197               # FIXME we want to yield the files in this dir first  
    198    
    199 134             # Process files after dirs so that any lib dirs will  
    200 135             # already be in sys.path before we start importing files  
     
    202 137             for filename in filenames:  
    203 138                 lname = os.path.join(dirpath, filename)  
    204                   if (filename.endswith('.py')  
    205                       and conf.testMatch.search(filename)  
    206                       and wanted(lname)):  
      139                 if selector.wantFile(lname, package=package, tests=tests):  
    207 140                     # print "**", lname  
    208 141                     yield ModuleSuite(  
     
    210 143                         path=lname, loader=self,  
    211 144                         working_dir=working_dir,  
    212                           wanted=wanted)  
      145                         tests=tests)  
    212 145                     # FIXME yield a ModuleSuite if it's a python module  
    213 146                     # FIXME yield a FileSuite if it's not  
    214               # FIXME yield ModuleSuites for all module dirs  
      147             # yield ModuleSuites for all packages  
    214 147             for name, path in packages:  
    215 148                 yield ModuleSuite(  
     
    219 152                     path=path, loader=self,  
    220 153                     working_dir=working_dir,  
    221                       wanted=wanted)  
      154                     tests=tests)  
    221 154             # At this point we're diving into directories that aren't packages  
    222 155             # so if we think we are in a package, we have to forget the  
     
    226 159             package = None  
    227 160                  
    228       def loadTestsFromModule(self, module, wanted=None):  
      161     def loadTestsFromModule(self, module, tests=None):  
    228 161         """Construct a TestSuite containing all of the tests in  
    229 162         the module, including tests in the package if it is a package  
    230 163         """  
      164         # print "loadTestsFromModule %s" % module  
    231 165         if ispackageinit(module):  
    232 166             path = os.path.dirname(module.__file__)  
    233               for test in self.findTests(path, wanted, package=module.__name__):  
      167             for test in self.findTests(path, tests, package=module.__name__):  
    233 167                 # FIXME  
    234 168                 print "  ", test  
     
    254 188 #'test-dir' => 'support/test-dir/test.py'  
    255 189 #'test-dir/' => 'support/test-dir/test.py'  
    256    
      190 # 'test' => 'support/test.py', 'support/test-dir/test.py' -- not foo  
    256 190  
    257 191