Source code for nltk.test.doctest_nose_plugin

# -*- coding: utf-8 -*-
from __future__ import print_function
from nose.suite import ContextList
import re
import sys
import os
import codecs
import doctest
from nose.plugins.base import Plugin
from nose.util import tolist, anyp
from nose.plugins.doctests import Doctest, log, DocFileCase

ALLOW_UNICODE = doctest.register_optionflag('ALLOW_UNICODE')


class _UnicodeOutputChecker(doctest.OutputChecker):
    _literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)

    def _remove_u_prefixes(self, txt):
        return re.sub(self._literal_re, r'\1\2', txt)

    def check_output(self, want, got, optionflags):
        res = doctest.OutputChecker.check_output(self, want, got, optionflags)
        if res:
            return True
        if not (optionflags & ALLOW_UNICODE):
            return False

        # ALLOW_UNICODE is active and want != got
        cleaned_want = self._remove_u_prefixes(want)
        cleaned_got = self._remove_u_prefixes(got)
        res = doctest.OutputChecker.check_output(self, cleaned_want, cleaned_got, optionflags)
        return res


_checker = _UnicodeOutputChecker()


[docs]class DoctestPluginHelper(object): """ This mixin adds print_function future import to all test cases. It also adds support for: '#doctest +ALLOW_UNICODE' option that makes DocTestCase think u'foo' == 'foo'. '#doctest doctestencoding=utf-8' option that changes the encoding of doctest files """ OPTION_BY_NAME = ('doctestencoding',)
[docs] def loadTestsFromFileUnicode(self, filename): if self.extension and anyp(filename.endswith, self.extension): name = os.path.basename(filename) dh = codecs.open(filename, 'r', self.options.get('doctestencoding')) try: doc = dh.read() finally: dh.close() fixture_context = None globs = {'__file__': filename} if self.fixtures: base, ext = os.path.splitext(name) dirname = os.path.dirname(filename) sys.path.append(dirname) fixt_mod = base + self.fixtures try: fixture_context = __import__( fixt_mod, globals(), locals(), ["nop"]) except ImportError as e: log.debug( "Could not import %s: %s (%s)", fixt_mod, e, sys.path) log.debug("Fixture module %s resolved to %s", fixt_mod, fixture_context) if hasattr(fixture_context, 'globs'): globs = fixture_context.globs(globs) parser = doctest.DocTestParser() test = parser.get_doctest( doc, globs=globs, name=name, filename=filename, lineno=0) if test.examples: case = DocFileCase( test, optionflags=self.optionflags, setUp=getattr(fixture_context, 'setup_test', None), tearDown=getattr(fixture_context, 'teardown_test', None), result_var=self.doctest_result_var) if fixture_context: yield ContextList((case,), context=fixture_context) else: yield case else: yield False # no tests to load
[docs] def loadTestsFromFile(self, filename): cases = self.loadTestsFromFileUnicode(filename) for case in cases: if isinstance(case, ContextList): yield ContextList([self._patchTestCase(c) for c in case], case.context) else: yield self._patchTestCase(case)
[docs] def loadTestsFromModule(self, module): """Load doctests from the module. """ for suite in super(DoctestPluginHelper, self).loadTestsFromModule(module): cases = [self._patchTestCase(case) for case in suite._get_tests()] yield self.suiteClass(cases, context=module, can_split=False)
def _patchTestCase(self, case): if case: case._dt_test.globs['print_function'] = print_function case._dt_checker = _checker return case
[docs] def configure(self, options, config): # it is overriden in order to fix doctest options discovery Plugin.configure(self, options, config) self.doctest_result_var = options.doctest_result_var self.doctest_tests = options.doctest_tests self.extension = tolist(options.doctestExtension) self.fixtures = options.doctestFixtures self.finder = doctest.DocTestFinder() # super(DoctestPluginHelper, self).configure(options, config) self.optionflags = 0 self.options = {} if options.doctestOptions: stroptions = ",".join(options.doctestOptions).split(',') for stroption in stroptions: try: if stroption.startswith('+'): self.optionflags |= doctest.OPTIONFLAGS_BY_NAME[stroption[1:]] continue elif stroption.startswith('-'): self.optionflags &= ~doctest.OPTIONFLAGS_BY_NAME[stroption[1:]] continue try: key, value = stroption.split('=') except ValueError: pass else: if not key in self.OPTION_BY_NAME: raise ValueError() self.options[key] = value continue except (AttributeError, ValueError, KeyError): raise ValueError("Unknown doctest option {}".format(stroption)) else: raise ValueError("Doctest option is not a flag or a key/value pair: {} ".format(stroption))
[docs]class DoctestFix(DoctestPluginHelper, Doctest): pass