root/galaxy-central/eggs/nose-0.11.1-py2.6.egg/nose/plugins/doctests.py

リビジョン 3, 15.8 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1"""Use the Doctest plugin with ``--with-doctest`` or the NOSE_WITH_DOCTEST
2environment 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
5looks for them in the non-test packages it discovers in the working directory.
6
7Doctests may also be placed into files other than python modules, in which
8case they can be collected and executed by using the ``--doctest-extension``
9switch or NOSE_DOCTEST_EXTENSION environment variable to indicate which file
10extension(s) to load.
11
12When loading doctests from non-module files, use the ``--doctest-fixtures``
13switch to specify how to find modules containing fixtures for the tests. A
14module name will be produced by appending the value of that switch to the base
15name of each doctest file loaded. For example, a doctest file "widgets.rst"
16with the switch ``--doctest_fixtures=_fixt`` will load fixtures from the module
17``widgets_fixt.py``.
18
19A 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 
40Doctests are run like any other test, with the exception that output
41capture does not work; doctest does its own output capture while running a
42test.
43
44.. note ::
45
46   See :doc:`../doc_tests/test_doctest_fixtures/doctest_fixtures` for
47   additional documentation and examples.
48
49"""
50from __future__ import generators
51
52import logging
53import os
54import sys
55import unittest
56from inspect import getmodule
57from nose.plugins.base import Plugin
58from nose.suite import ContextList
59from nose.util import anyp, getpackage, test_address, resolve_name, \
60     src, tolist, isproperty
61try:
62    from cStringIO import StringIO
63except ImportError:
64    from StringIO import StringIO
65import sys
66import __builtin__
67
68log = logging.getLogger(__name__)
69
70try:
71    import doctest
72    doctest.DocTestCase
73    # system version of doctest is acceptable, but needs a monkeypatch
74except (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
89class 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)
103doctest._OutputRedirectingPdb = NoseOutputRedirectingPdb   
104
105
106class 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       
135class 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
325class 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__, 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__, self._result_var)
396
397
398class 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__, 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__, self._result_var)
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。