Imported Upstream version 1.1.2
[platform/upstream/python-nose.git] / nose / plugins / doctests.py
1 """Use the Doctest plugin with ``--with-doctest`` or the NOSE_WITH_DOCTEST
2 environment variable to enable collection and execution of :mod:`doctests
3 <doctest>`.  Because doctests are usually included in the tested package
4 (instead of being grouped into packages or modules of their own), nose only
5 looks for them in the non-test packages it discovers in the working directory.
6
7 Doctests may also be placed into files other than python modules, in which
8 case they can be collected and executed by using the ``--doctest-extension``
9 switch or NOSE_DOCTEST_EXTENSION environment variable to indicate which file
10 extension(s) to load.
11
12 When loading doctests from non-module files, use the ``--doctest-fixtures``
13 switch to specify how to find modules containing fixtures for the tests. A
14 module name will be produced by appending the value of that switch to the base
15 name of each doctest file loaded. For example, a doctest file "widgets.rst"
16 with the switch ``--doctest_fixtures=_fixt`` will load fixtures from the module
17 ``widgets_fixt.py``.
18
19 A fixtures module may define any or all of the following functions:
20
21 * setup([module]) or setup_module([module])
22    
23   Called before the test runs. You may raise SkipTest to skip all tests.
24   
25 * teardown([module]) or teardown_module([module])
26
27   Called after the test runs, if setup/setup_module did not raise an
28   unhandled exception.
29
30 * setup_test(test)
31
32   Called before the test. NOTE: the argument passed is a
33   doctest.DocTest instance, *not* a unittest.TestCase.
34   
35 * teardown_test(test)
36  
37   Called after the test, if setup_test did not raise an exception. NOTE: the
38   argument passed is a doctest.DocTest instance, *not* a unittest.TestCase.
39   
40 Doctests are run like any other test, with the exception that output
41 capture does not work; doctest does its own output capture while running a
42 test.
43
44 .. note ::
45
46    See :doc:`../doc_tests/test_doctest_fixtures/doctest_fixtures` for
47    additional documentation and examples.
48
49 """
50 from __future__ import generators
51
52 import logging
53 import os
54 import sys
55 import unittest
56 from inspect import getmodule
57 from nose.plugins.base import Plugin
58 from nose.suite import ContextList
59 from nose.util import anyp, getpackage, test_address, resolve_name, \
60      src, tolist, isproperty
61 try:
62     from cStringIO import StringIO
63 except ImportError:
64     from StringIO import StringIO
65 import sys
66 import __builtin__ as builtin_mod
67
68 log = logging.getLogger(__name__)
69
70 try:
71     import doctest
72     doctest.DocTestCase
73     # system version of doctest is acceptable, but needs a monkeypatch
74 except (ImportError, AttributeError):
75     # system version is too old
76     import nose.ext.dtcompat as doctest
77
78
79 #
80 # Doctest and coverage don't get along, so we need to create
81 # a monkeypatch that will replace the part of doctest that
82 # interferes with coverage reports.
83 #
84 # The monkeypatch is based on this zope patch:
85 # http://svn.zope.org/Zope3/trunk/src/zope/testing/doctest.py?rev=28679&r1=28703&r2=28705
86 #
87 _orp = doctest._OutputRedirectingPdb
88
89 class NoseOutputRedirectingPdb(_orp):
90     def __init__(self, out):
91         self.__debugger_used = False
92         _orp.__init__(self, out)
93
94     def set_trace(self):
95         self.__debugger_used = True
96         _orp.set_trace(self, sys._getframe().f_back)
97
98     def set_continue(self):
99         # Calling set_continue unconditionally would break unit test 
100         # coverage reporting, as Bdb.set_continue calls sys.settrace(None).
101         if self.__debugger_used:
102             _orp.set_continue(self)
103 doctest._OutputRedirectingPdb = NoseOutputRedirectingPdb    
104
105
106 class DoctestSuite(unittest.TestSuite):
107     """
108     Doctest suites are parallelizable at the module or file level only,
109     since they may be attached to objects that are not individually
110     addressable (like properties). This suite subclass is used when
111     loading doctests from a module to ensure that behavior.
112
113     This class is used only if the plugin is not fully prepared;
114     in normal use, the loader's suiteClass is used.
115     
116     """
117     can_split = False
118     
119     def __init__(self, tests=(), context=None, can_split=False):
120         self.context = context
121         self.can_split = can_split
122         unittest.TestSuite.__init__(self, tests=tests)
123
124     def address(self):
125         return test_address(self.context)
126
127     def __iter__(self):
128         # 2.3 compat
129         return iter(self._tests)
130
131     def __str__(self):
132         return str(self._tests)
133
134         
135 class Doctest(Plugin):
136     """
137     Activate doctest plugin to find and run doctests in non-test modules.
138     """
139     extension = None
140     suiteClass = DoctestSuite
141     
142     def options(self, parser, env):
143         """Register commmandline options.
144         """
145         Plugin.options(self, parser, env)
146         parser.add_option('--doctest-tests', action='store_true',
147                           dest='doctest_tests',
148                           default=env.get('NOSE_DOCTEST_TESTS'),
149                           help="Also look for doctests in test modules. "
150                           "Note that classes, methods and functions should "
151                           "have either doctests or non-doctest tests, "
152                           "not both. [NOSE_DOCTEST_TESTS]")
153         parser.add_option('--doctest-extension', action="append",
154                           dest="doctestExtension",
155                           metavar="EXT",
156                           help="Also look for doctests in files with "
157                           "this extension [NOSE_DOCTEST_EXTENSION]")
158         parser.add_option('--doctest-result-variable',
159                           dest='doctest_result_var',
160                           default=env.get('NOSE_DOCTEST_RESULT_VAR'),
161                           metavar="VAR",
162                           help="Change the variable name set to the result of "
163                           "the last interpreter command from the default '_'. "
164                           "Can be used to avoid conflicts with the _() "
165                           "function used for text translation. "
166                           "[NOSE_DOCTEST_RESULT_VAR]")
167         parser.add_option('--doctest-fixtures', action="store",
168                           dest="doctestFixtures",
169                           metavar="SUFFIX",
170                           help="Find fixtures for a doctest file in module "
171                           "with this name appended to the base name "
172                           "of the doctest file")
173         # Set the default as a list, if given in env; otherwise
174         # an additional value set on the command line will cause
175         # an error.
176         env_setting = env.get('NOSE_DOCTEST_EXTENSION')
177         if env_setting is not None:
178             parser.set_defaults(doctestExtension=tolist(env_setting))
179
180     def configure(self, options, config):
181         """Configure plugin.
182         """
183         Plugin.configure(self, options, config)
184         self.doctest_result_var = options.doctest_result_var
185         self.doctest_tests = options.doctest_tests
186         self.extension = tolist(options.doctestExtension)
187         self.fixtures = options.doctestFixtures
188         self.finder = doctest.DocTestFinder()
189         
190     def prepareTestLoader(self, loader):
191         """Capture loader's suiteClass.
192
193         This is used to create test suites from doctest files.
194         
195         """
196         self.suiteClass = loader.suiteClass
197
198     def loadTestsFromModule(self, module):
199         """Load doctests from the module.
200         """
201         log.debug("loading from %s", module)
202         if not self.matches(module.__name__):
203             log.debug("Doctest doesn't want module %s", module)
204             return
205         try:
206             tests = self.finder.find(module)
207         except AttributeError:
208             log.exception("Attribute error loading from %s", module)
209             # nose allows module.__test__ = False; doctest does not and throws
210             # AttributeError
211             return
212         if not tests:
213             log.debug("No tests found in %s", module)
214             return
215         tests.sort()
216         module_file = src(module.__file__)
217         # FIXME this breaks the id plugin somehow (tests probably don't
218         # get wrapped in result proxy or something)
219         cases = []
220         for test in tests:
221             if not test.examples:
222                 continue
223             if not test.filename:
224                 test.filename = module_file
225             cases.append(DocTestCase(test, result_var=self.doctest_result_var))
226         if cases:
227             yield self.suiteClass(cases, context=module, can_split=False)
228             
229     def loadTestsFromFile(self, filename):
230         """Load doctests from the file.
231
232         Tests are loaded only if filename's extension matches
233         configured doctest extension.
234
235         """
236         if self.extension and anyp(filename.endswith, self.extension):
237             name = os.path.basename(filename)
238             dh = open(filename)
239             try:
240                 doc = dh.read()
241             finally:
242                 dh.close()
243
244             fixture_context = None
245             globs = {'__file__': filename}
246             if self.fixtures:
247                 base, ext = os.path.splitext(name)
248                 dirname = os.path.dirname(filename)
249                 sys.path.append(dirname)
250                 fixt_mod = base + self.fixtures
251                 try:
252                     fixture_context = __import__(
253                         fixt_mod, globals(), locals(), ["nop"])
254                 except ImportError, e:
255                     log.debug(
256                         "Could not import %s: %s (%s)", fixt_mod, e, sys.path)
257                 log.debug("Fixture module %s resolved to %s",
258                           fixt_mod, fixture_context)
259                 if hasattr(fixture_context, 'globs'):
260                     globs = fixture_context.globs(globs)                    
261             parser = doctest.DocTestParser()
262             test = parser.get_doctest(
263                 doc, globs=globs, name=name,
264                 filename=filename, lineno=0)
265             if test.examples:
266                 case = DocFileCase(
267                     test,
268                     setUp=getattr(fixture_context, 'setup_test', None),
269                     tearDown=getattr(fixture_context, 'teardown_test', None),
270                     result_var=self.doctest_result_var)
271                 if fixture_context:
272                     yield ContextList((case,), context=fixture_context)
273                 else:
274                     yield case
275             else:
276                 yield False # no tests to load
277             
278     def makeTest(self, obj, parent):
279         """Look for doctests in the given object, which will be a
280         function, method or class.
281         """
282         name = getattr(obj, '__name__', 'Unnammed %s' % type(obj))
283         doctests = self.finder.find(obj, module=getmodule(parent), name=name)
284         if doctests:
285             for test in doctests:
286                 if len(test.examples) == 0:
287                     continue
288                 yield DocTestCase(test, obj=obj,
289                                   result_var=self.doctest_result_var)
290     
291     def matches(self, name):
292         # FIXME this seems wrong -- nothing is ever going to
293         # fail this test, since we're given a module NAME not FILE
294         if name == '__init__.py':
295             return False
296         # FIXME don't think we need include/exclude checks here?
297         return ((self.doctest_tests or not self.conf.testMatch.search(name)
298                  or (self.conf.include 
299                      and filter(None,
300                                 [inc.search(name)
301                                  for inc in self.conf.include])))
302                 and (not self.conf.exclude 
303                      or not filter(None,
304                                    [exc.search(name)
305                                     for exc in self.conf.exclude])))
306     
307     def wantFile(self, file):
308         """Override to select all modules and any file ending with
309         configured doctest extension.
310         """
311         # always want .py files
312         if file.endswith('.py'):
313             return True
314         # also want files that match my extension
315         if (self.extension
316             and anyp(file.endswith, self.extension)
317             and (not self.conf.exclude
318                  or not filter(None, 
319                                [exc.search(file)
320                                 for exc in self.conf.exclude]))):
321             return True
322         return None
323
324
325 class DocTestCase(doctest.DocTestCase):
326     """Overrides DocTestCase to
327     provide an address() method that returns the correct address for
328     the doctest case. To provide hints for address(), an obj may also
329     be passed -- this will be used as the test object for purposes of
330     determining the test address, if it is provided.
331     """
332     def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
333                  checker=None, obj=None, result_var='_'):
334         self._result_var = result_var
335         self._nose_obj = obj
336         super(DocTestCase, self).__init__(
337             test, optionflags=optionflags, setUp=setUp, tearDown=tearDown,
338             checker=checker)
339     
340     def address(self):
341         if self._nose_obj is not None:
342             return test_address(self._nose_obj)
343         obj = resolve_name(self._dt_test.name)
344
345         if isproperty(obj):
346             # properties have no connection to the class they are in
347             # so we can't just look 'em up, we have to first look up
348             # the class, then stick the prop on the end
349             parts = self._dt_test.name.split('.')
350             class_name = '.'.join(parts[:-1])
351             cls = resolve_name(class_name)
352             base_addr = test_address(cls)
353             return (base_addr[0], base_addr[1],
354                     '.'.join([base_addr[2], parts[-1]]))
355         else:
356             return test_address(obj)
357     
358     # doctests loaded via find(obj) omit the module name
359     # so we need to override id, __repr__ and shortDescription
360     # bonus: this will squash a 2.3 vs 2.4 incompatiblity
361     def id(self):
362         name = self._dt_test.name
363         filename = self._dt_test.filename
364         if filename is not None:
365             pk = getpackage(filename)
366             if not name.startswith(pk):
367                 name = "%s.%s" % (pk, name)
368         return name
369     
370     def __repr__(self):
371         name = self.id()
372         name = name.split('.')
373         return "%s (%s)" % (name[-1], '.'.join(name[:-1]))
374     __str__ = __repr__
375
376     def shortDescription(self):
377         return 'Doctest: %s' % self.id()
378
379     def setUp(self):
380         if self._result_var is not None:
381             self._old_displayhook = sys.displayhook
382             sys.displayhook = self._displayhook
383         super(DocTestCase, self).setUp()
384
385     def _displayhook(self, value):
386         if value is None:
387             return
388         setattr(builtin_mod, self._result_var,  value)
389         print repr(value)
390
391     def tearDown(self):
392         super(DocTestCase, self).tearDown()
393         if self._result_var is not None:
394             sys.displayhook = self._old_displayhook
395             delattr(builtin_mod, self._result_var)
396
397
398 class DocFileCase(doctest.DocFileCase):
399     """Overrides to provide address() method that returns the correct
400     address for the doc file case.
401     """
402     def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
403                  checker=None, result_var='_'):
404         self._result_var = result_var
405         super(DocFileCase, self).__init__(
406             test, optionflags=optionflags, setUp=setUp, tearDown=tearDown,
407             checker=None)
408
409     def address(self):
410         return (self._dt_test.filename, None, None)
411
412     def setUp(self):
413         if self._result_var is not None:
414             self._old_displayhook = sys.displayhook
415             sys.displayhook = self._displayhook
416         super(DocFileCase, self).setUp()
417
418     def _displayhook(self, value):
419         if value is None:
420             return
421         setattr(builtin_mod, self._result_var, value)
422         print repr(value)
423
424     def tearDown(self):
425         super(DocFileCase, self).tearDown()
426         if self._result_var is not None:
427             sys.displayhook = self._old_displayhook
428             delattr(builtin_mod, self._result_var)