/nose/selector.py
Python | 251 lines | 173 code | 23 blank | 55 comment | 60 complexity | 14d2c06bd1ad4a7d408d07560be08c7d MD5 | raw file
1""" 2Test Selection 3-------------- 4 5Test selection is handled by a Selector. The test loader calls the 6appropriate selector method for each object it encounters that it 7thinks may be a test. 8""" 9import logging 10import os 11import unittest 12from nose.config import Config 13from nose.util import split_test_name, src, getfilename, getpackage, ispackage 14 15log = logging.getLogger(__name__) 16 17__all__ = ['Selector', 'defaultSelector', 'TestAddress'] 18 19 20# for efficiency and easier mocking 21op_join = os.path.join 22op_basename = os.path.basename 23op_exists = os.path.exists 24op_splitext = os.path.splitext 25op_isabs = os.path.isabs 26op_abspath = os.path.abspath 27 28 29class Selector(object): 30 """Core test selector. Examines test candidates and determines whether, 31 given the specified configuration, the test candidate should be selected 32 as a test. 33 """ 34 def __init__(self, config): 35 if config is None: 36 config = Config() 37 self.configure(config) 38 39 def configure(self, config): 40 self.config = config 41 self.exclude = config.exclude 42 self.ignoreFiles = config.ignoreFiles 43 self.include = config.include 44 self.plugins = config.plugins 45 self.match = config.testMatch 46 47 def matches(self, name): 48 """Does the name match my requirements? 49 50 To match, a name must match config.testMatch OR config.include 51 and it must not match config.exclude 52 """ 53 return ((self.match.search(name) 54 or (self.include and 55 filter(None, 56 [inc.search(name) for inc in self.include]))) 57 and ((not self.exclude) 58 or not filter(None, 59 [exc.search(name) for exc in self.exclude]) 60 )) 61 62 def wantClass(self, cls): 63 """Is the class a wanted test class? 64 65 A class must be a unittest.TestCase subclass, or match test name 66 requirements. Classes that start with _ are always excluded. 67 """ 68 declared = getattr(cls, '__test__', None) 69 if declared is not None: 70 wanted = declared 71 else: 72 wanted = (not cls.__name__.startswith('_') 73 and (issubclass(cls, unittest.TestCase) 74 or self.matches(cls.__name__))) 75 76 plug_wants = self.plugins.wantClass(cls) 77 if plug_wants is not None: 78 log.debug("Plugin setting selection of %s to %s", cls, plug_wants) 79 wanted = plug_wants 80 log.debug("wantClass %s? %s", cls, wanted) 81 return wanted 82 83 def wantDirectory(self, dirname): 84 """Is the directory a wanted test directory? 85 86 All package directories match, so long as they do not match exclude. 87 All other directories must match test requirements. 88 """ 89 tail = op_basename(dirname) 90 if ispackage(dirname): 91 wanted = (not self.exclude 92 or not filter(None, 93 [exc.search(tail) for exc in self.exclude] 94 )) 95 else: 96 wanted = (self.matches(tail) 97 or (self.config.srcDirs 98 and tail in self.config.srcDirs)) 99 plug_wants = self.plugins.wantDirectory(dirname) 100 if plug_wants is not None: 101 log.debug("Plugin setting selection of %s to %s", 102 dirname, plug_wants) 103 wanted = plug_wants 104 log.debug("wantDirectory %s? %s", dirname, wanted) 105 return wanted 106 107 def wantFile(self, file): 108 """Is the file a wanted test file? 109 110 The file must be a python source file and match testMatch or 111 include, and not match exclude. Files that match ignore are *never* 112 wanted, regardless of plugin, testMatch, include or exclude settings. 113 """ 114 # never, ever load files that match anything in ignore 115 # (.* _* and *setup*.py by default) 116 base = op_basename(file) 117 ignore_matches = [ ignore_this for ignore_this in self.ignoreFiles 118 if ignore_this.search(base) ] 119 if ignore_matches: 120 log.debug('%s matches ignoreFiles pattern; skipped', 121 base) 122 return False 123 if not self.config.includeExe and os.access(file, os.X_OK): 124 log.info('%s is executable; skipped', file) 125 return False 126 dummy, ext = op_splitext(base) 127 pysrc = ext == '.py' 128 129 wanted = pysrc and self.matches(base) 130 plug_wants = self.plugins.wantFile(file) 131 if plug_wants is not None: 132 log.debug("plugin setting want %s to %s", file, plug_wants) 133 wanted = plug_wants 134 log.debug("wantFile %s? %s", file, wanted) 135 return wanted 136 137 def wantFunction(self, function): 138 """Is the function a test function? 139 """ 140 try: 141 if hasattr(function, 'compat_func_name'): 142 funcname = function.compat_func_name 143 else: 144 funcname = function.__name__ 145 except AttributeError: 146 # not a function 147 return False 148 declared = getattr(function, '__test__', None) 149 if declared is not None: 150 wanted = declared 151 else: 152 wanted = not funcname.startswith('_') and self.matches(funcname) 153 plug_wants = self.plugins.wantFunction(function) 154 if plug_wants is not None: 155 wanted = plug_wants 156 log.debug("wantFunction %s? %s", function, wanted) 157 return wanted 158 159 def wantMethod(self, method): 160 """Is the method a test method? 161 """ 162 try: 163 method_name = method.__name__ 164 except AttributeError: 165 # not a method 166 return False 167 if method_name.startswith('_'): 168 # never collect 'private' methods 169 return False 170 declared = getattr(method, '__test__', None) 171 if declared is not None: 172 wanted = declared 173 else: 174 wanted = self.matches(method_name) 175 plug_wants = self.plugins.wantMethod(method) 176 if plug_wants is not None: 177 wanted = plug_wants 178 log.debug("wantMethod %s? %s", method, wanted) 179 return wanted 180 181 def wantModule(self, module): 182 """Is the module a test module? 183 184 The tail of the module name must match test requirements. One exception: 185 we always want __main__. 186 """ 187 declared = getattr(module, '__test__', None) 188 if declared is not None: 189 wanted = declared 190 else: 191 wanted = self.matches(module.__name__.split('.')[-1]) \ 192 or module.__name__ == '__main__' 193 plug_wants = self.plugins.wantModule(module) 194 if plug_wants is not None: 195 wanted = plug_wants 196 log.debug("wantModule %s? %s", module, wanted) 197 return wanted 198 199defaultSelector = Selector 200 201 202class TestAddress(object): 203 """A test address represents a user's request to run a particular 204 test. The user may specify a filename or module (or neither), 205 and/or a callable (a class, function, or method). The naming 206 format for test addresses is: 207 208 filename_or_module:callable 209 210 Filenames that are not absolute will be made absolute relative to 211 the working dir. 212 213 The filename or module part will be considered a module name if it 214 doesn't look like a file, that is, if it doesn't exist on the file 215 system and it doesn't contain any directory separators and it 216 doesn't end in .py. 217 218 Callables may be a class name, function name, method name, or 219 class.method specification. 220 """ 221 def __init__(self, name, workingDir=None): 222 if workingDir is None: 223 workingDir = os.getcwd() 224 self.name = name 225 self.workingDir = workingDir 226 self.filename, self.module, self.call = split_test_name(name) 227 log.debug('Test name %s resolved to file %s, module %s, call %s', 228 name, self.filename, self.module, self.call) 229 if self.filename is None: 230 if self.module is not None: 231 self.filename = getfilename(self.module, self.workingDir) 232 if self.filename: 233 self.filename = src(self.filename) 234 if not op_isabs(self.filename): 235 self.filename = op_abspath(op_join(workingDir, 236 self.filename)) 237 if self.module is None: 238 self.module = getpackage(self.filename) 239 log.debug( 240 'Final resolution of test name %s: file %s module %s call %s', 241 name, self.filename, self.module, self.call) 242 243 def totuple(self): 244 return (self.filename, self.module, self.call) 245 246 def __str__(self): 247 return self.name 248 249 def __repr__(self): 250 return "%s: (%s, %s, %s)" % (self.name, self.filename, 251 self.module, self.call)