Imported Upstream version 1.1.2
[platform/upstream/python-nose.git] / nose / selector.py
1 """
2 Test Selection
3 --------------
4
5 Test selection is handled by a Selector. The test loader calls the
6 appropriate selector method for each object it encounters that it
7 thinks may be a test.
8 """
9 import logging
10 import os
11 import unittest
12 from nose.config import Config
13 from nose.util import split_test_name, src, getfilename, getpackage, ispackage
14
15 log = logging.getLogger(__name__)
16
17 __all__ = ['Selector', 'defaultSelector', 'TestAddress']
18
19
20 # for efficiency and easier mocking
21 op_join = os.path.join
22 op_basename = os.path.basename
23 op_exists = os.path.exists
24 op_splitext = os.path.splitext
25 op_isabs = os.path.isabs
26 op_abspath = os.path.abspath
27
28
29 class 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         
199 defaultSelector = Selector        
200
201
202 class 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)