summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjpellerin <devnull@localhost>2009-12-02 17:51:50 -0500
committerjpellerin <devnull@localhost>2009-12-02 17:51:50 -0500
commite2df9e6b038d8e45dd7f9623618d6dfcb38313a5 (patch)
treee690d700b4eea086c8b5a281d7dcc64e0477a863
parent7c8482f9a40face2a343c5840ef0e21ea718c0bd (diff)
downloadnose-e2df9e6b038d8e45dd7f9623618d6dfcb38313a5.tar.gz
Improved compatibility with 2.7 builtin skip
-rw-r--r--nose/plugins/errorclass.py26
-rw-r--r--nose/plugins/skip.py11
-rw-r--r--nose/proxy.py28
-rw-r--r--nose/result.py53
-rw-r--r--unit_tests/test_skip_plugin.py13
5 files changed, 90 insertions, 41 deletions
diff --git a/nose/plugins/errorclass.py b/nose/plugins/errorclass.py
index 51b20ed..d327194 100644
--- a/nose/plugins/errorclass.py
+++ b/nose/plugins/errorclass.py
@@ -29,7 +29,7 @@ into the tuples used by the error handling and reporting functions in
the result. This is an internal format and subject to change; you
should always use the declarative syntax for attaching ErrorClasses to
an ErrorClass plugin.
-
+
>>> TodoError.errorClasses # doctest: +ELLIPSIS
((<class ...Todo...>, ('todo', 'TODO', True)),)
@@ -42,7 +42,7 @@ Let's see the plugin in action. First some boilerplate.
... from unittest.runner import _WritelnDecorator
... except ImportError:
... from unittest import _WritelnDecorator
- ...
+ ...
>>> buf = _WritelnDecorator(sys.stdout)
Now define a test case that raises a Todo.
@@ -154,6 +154,7 @@ class ErrorClassPlugin(Plugin):
result.errorClasses[cls] = (storage, label, isfail)
def patchResult(self, result):
+ result.printLabel = print_label_patch(result)
result._orig_addError, result.addError = \
result.addError, add_error_patch(result)
result._orig_wasSuccessful, result.wasSuccessful = \
@@ -161,6 +162,9 @@ class ErrorClassPlugin(Plugin):
if hasattr(result, 'printErrors'):
result._orig_printErrors, result.printErrors = \
result.printErrors, print_errors_patch(result)
+ if hasattr(result, 'addSkip'):
+ result._orig_addSkip, result.addSkip = \
+ result.addSkip, add_skip_patch(result)
result.errorClasses = {}
@@ -181,6 +185,14 @@ def print_errors_patch(result):
TextTestResult.printErrors.im_func, result, result.__class__)
+def print_label_patch(result):
+ """Create a new printLabel method that prints errorClasses items
+ as well.
+ """
+ return instancemethod(
+ TextTestResult.printLabel.im_func, result, result.__class__)
+
+
def wassuccessful_patch(result):
"""Create a new wasSuccessful method that checks errorClasses for
exceptions that were put into other slots than error or failure
@@ -189,7 +201,15 @@ def wassuccessful_patch(result):
return instancemethod(
TextTestResult.wasSuccessful.im_func, result, result.__class__)
-
+
+def add_skip_patch(result):
+ """Create a new addSkip method to patch into a result instance
+ that delegates to addError.
+ """
+ return instancemethod(
+ TextTestResult.addSkip.im_func, result, result.__class__)
+
+
if __name__ == '__main__':
import doctest
doctest.testmod()
diff --git a/nose/plugins/skip.py b/nose/plugins/skip.py
index 3b2ff1c..27e5162 100644
--- a/nose/plugins/skip.py
+++ b/nose/plugins/skip.py
@@ -9,9 +9,14 @@ is enabled by default but may be disabled with the ``--no-skip`` option.
from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin
-class SkipTest(Exception):
- """Raise this exception to mark a test as skipped.
- """
+try:
+ # 2.7
+ from unittest.case import SkipTest
+except ImportError:
+ # 2.6 and below
+ class SkipTest(Exception):
+ """Raise this exception to mark a test as skipped.
+ """
pass
diff --git a/nose/proxy.py b/nose/proxy.py
index c2c99cb..ba5b638 100644
--- a/nose/proxy.py
+++ b/nose/proxy.py
@@ -72,8 +72,8 @@ class ResultProxy(object):
the wrapped test case) as each result call is made. Finally, the
real result method is called, also with the nose.case.Test
instance as the test parameter.
-
- """
+
+ """
def __init__(self, result, test, config=None):
if config is None:
config = Config()
@@ -90,12 +90,12 @@ class ResultProxy(object):
# .test's .test. or my .test.test's .case
case = getattr(self.test, 'test', None)
- assert (test is self.test
- or test is case
- or test is getattr(case, '_nose_case', None)), (
- "ResultProxy for %r (%s) was called with test %r (%s)"
+ assert (test is self.test
+ or test is case
+ or test is getattr(case, '_nose_case', None)), (
+ "ResultProxy for %r (%s) was called with test %r (%s)"
% (self.test, id(self.test), test, id(test)))
-
+
def afterTest(self, test):
self.assertMyTest(test)
self.plugins.afterTest(self.test)
@@ -137,7 +137,15 @@ class ResultProxy(object):
self.result.addFailure(self.test, err)
if self.config.stopOnError:
self.shouldStop = True
-
+
+ def addSkip(self, test, reason):
+ # 2.7 compat shim
+ from nose.plugins.skip import SkipTest
+ self.assertMyTest(test)
+ plugins = self.plugins
+ plugins.addError(self.test, (SkipTest, reason, None))
+ self.result.addSkip(self.test, reason)
+
def addSuccess(self, test):
self.assertMyTest(test)
self.plugins.addSuccess(self.test)
@@ -147,10 +155,10 @@ class ResultProxy(object):
self.assertMyTest(test)
self.plugins.startTest(self.test)
self.result.startTest(self.test)
-
+
def stop(self):
self.result.stop()
-
+
def stopTest(self, test):
self.assertMyTest(test)
self.plugins.stopTest(self.test)
diff --git a/nose/result.py b/nose/result.py
index da1369d..9fd90d6 100644
--- a/nose/result.py
+++ b/nose/result.py
@@ -32,23 +32,30 @@ class TextTestResult(_TextTestResult):
"""Text test result that extends unittest's default test result
support for a configurable set of errorClasses (eg, Skip,
Deprecated, TODO) that extend the errors/failures/success triad.
- """
+ """
def __init__(self, stream, descriptions, verbosity, config=None,
- errorClasses=None):
+ errorClasses=None):
if errorClasses is None:
errorClasses = {}
self.errorClasses = errorClasses
if config is None:
- config = Config()
+ config = Config()
self.config = config
_TextTestResult.__init__(self, stream, descriptions, verbosity)
-
+
+ def addSkip(self, test, reason):
+ # 2.7 skip compat
+ from nose.plugins.skip import SkipTest
+ if SkipTest in self.errorClasses:
+ storage, label, isfail = self.errorClasses[SkipTest]
+ storage.append((test, reason))
+ self.printLabel(label, (SkipTest, reason, None))
+
def addError(self, test, err):
"""Overrides normal addError to add support for
errorClasses. If the exception is a registered class, the
error will be added to the list for that class, not errors.
"""
- stream = getattr(self, 'stream', None)
ec, ev, tb = err
try:
exc_info = self._exc_info_to_string(err, test)
@@ -56,28 +63,32 @@ class TextTestResult(_TextTestResult):
# 2.3 compat
exc_info = self._exc_info_to_string(err)
for cls, (storage, label, isfail) in self.errorClasses.items():
+ #if 'Skip' in cls.__name__ or 'Skip' in ec.__name__:
+ # from nose.tools import set_trace
+ # set_trace()
if isclass(ec) and issubclass(ec, cls):
if isfail:
test.passed = False
storage.append((test, exc_info))
- # Might get patched into a streamless result
- if stream is not None:
- if self.showAll:
- message = [label]
- detail = _exception_detail(err[1])
- if detail:
- message.append(detail)
- stream.writeln(": ".join(message))
- elif self.dots:
- stream.write(label[:1])
+ self.printLabel(label, err)
return
self.errors.append((test, exc_info))
test.passed = False
+ self.printLabel('ERROR')
+
+ def printLabel(self, label, err=None):
+ # Might get patched into a streamless result
+ stream = getattr(self, 'stream', None)
if stream is not None:
if self.showAll:
- self.stream.writeln('ERROR')
+ message = [label]
+ if err:
+ detail = _exception_detail(err[1])
+ if detail:
+ message.append(detail)
+ stream.writeln(": ".join(message))
elif self.dots:
- stream.write('E')
+ stream.write(label[:1])
def printErrors(self):
"""Overrides to print all errorClasses errors as well.
@@ -100,7 +111,7 @@ class TextTestResult(_TextTestResult):
taken = float(stop - start)
run = self.testsRun
plural = run != 1 and "s" or ""
-
+
writeln(self.separator2)
writeln("Ran %s test%s in %.3fs" % (run, plural, taken))
writeln()
@@ -161,6 +172,10 @@ class TextTestResult(_TextTestResult):
self.stream.write('E')
def _exc_info_to_string(self, err, test=None):
+ # 2.7 skip compat
+ from nose.plugins.skip import SkipTest
+ if issubclass(err[0], SkipTest):
+ return str(err[1])
# 2.3/2.4 -- 2.4 passes test, 2.3 does not
try:
return _TextTestResult._exc_info_to_string(self, err, test)
@@ -175,5 +190,5 @@ def ln(*arg, **kw):
"from nose.result in a future release. Please update your imports ",
DeprecationWarning)
return _ln(*arg, **kw)
-
+
diff --git a/unit_tests/test_skip_plugin.py b/unit_tests/test_skip_plugin.py
index e84bcec..c1dccee 100644
--- a/unit_tests/test_skip_plugin.py
+++ b/unit_tests/test_skip_plugin.py
@@ -18,7 +18,7 @@ class TestSkipPlugin(unittest.TestCase):
sk = Skip()
sk.addOptions
sk.configure
- sk.prepareTestResult
+ sk.prepareTestResult
def test_prepare_patches_result(self):
stream = _WritelnDecorator(StringIO())
@@ -60,13 +60,13 @@ class TestSkipPlugin(unittest.TestCase):
class NoPatch(unittest.TestResult):
def __init__(self):
self.errorClasses = {}
-
+
res = NoPatch()
sk = Skip()
sk.prepareTestResult(res)
assert not hasattr(res, '_orig_addError'), \
"Skip patched a result class it didn't need to patch"
-
+
def test_skip_output(self):
class TC(unittest.TestCase):
@@ -81,10 +81,11 @@ class TestSkipPlugin(unittest.TestCase):
test = TC('test')
test(res)
assert not res.errors, "Skip was not caught: %s" % res.errors
- assert res.skipped
+ assert res.skipped
res.printErrors()
out = stream.getvalue()
+ print out
assert out
assert out.strip() == "S"
assert res.wasSuccessful()
@@ -94,7 +95,7 @@ class TestSkipPlugin(unittest.TestCase):
class TC(unittest.TestCase):
def test(self):
raise SkipTest('skip me too')
-
+
stream = _WritelnDecorator(StringIO())
res = _TextTestResult(stream, 0, verbosity=2)
sk = Skip()
@@ -102,7 +103,7 @@ class TestSkipPlugin(unittest.TestCase):
test = TC('test')
test(res)
assert not res.errors, "Skip was not caught: %s" % res.errors
- assert res.skipped
+ assert res.skipped
res.printErrors()
out = stream.getvalue()