Hello community, here is the log from the commit of package python-rednose for openSUSE:Factory checked in at 2017-11-16 14:02:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-rednose (Old) and /work/SRC/openSUSE:Factory/.python-rednose.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-rednose" Thu Nov 16 14:02:53 2017 rev:2 rq:542116 version:1.2.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-rednose/python-rednose.changes 2015-06-12 20:30:18.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-rednose.new/python-rednose.changes 2017-11-16 14:02:58.361367394 +0100 @@ -1,0 +2,45 @@ +Wed Nov 15 08:32:40 UTC 2017 - [email protected] + +- update to version 1.2.3 + + Fix bug when switching between python 2 and 3 using node ids. + + Added stream flush after every write to make sure dots + are printed right after a test is executed. + +------------------------------------------------------------------- +Tue Oct 24 10:44:28 UTC 2017 - [email protected] + +- convert to single spec file + +------------------------------------------------------------------- +Tue Oct 24 10:31:57 UTC 2017 - [email protected] + +- add python-colorama to the Requires + +------------------------------------------------------------------- +Tue Oct 24 10:23:33 UTC 2017 - [email protected] + +- Update to version 1.2.2 + + Fix bug for skips raised in setUpClass (issue #9). +- Update to version 1.2.1 + + In python 2.7+ label skips as skip tests. + + Change skip test exception coloring to blue. +- Update to version 1.1.1 + + Fix for immediate broken with recent release when I switched API + ussage and removed an function. +- Update to version 1.1.0 + + Update tests for better reporting + + fix for errors during module setup (issue #1) + + Better support for skips + + Introduce proper printing for skipped tests as well as the + ability to supress them using --hide-skips + + Test with python 3.4 +- Update to version 1.1.0 + + !Major Changes! + + This release completely changes the way in which color test + results are printed. It now attmepts to override the code which + nose uses to print results rather than to supress those results + and print them seperatly. + + Package maintainer changes to JBKahn + + Use travis for testing + +------------------------------------------------------------------- Old: ---- rednose-0.4.1.tar.gz New: ---- rednose-1.2.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-rednose.spec ++++++ --- /var/tmp/diff_new_pack.JhFnA7/_old 2017-11-16 14:02:59.253335068 +0100 +++ /var/tmp/diff_new_pack.JhFnA7/_new 2017-11-16 14:02:59.261334778 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-rednose # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2012 Weberhofer GmbH, Austria # # All modifications and additions to the file contributed by third parties @@ -17,24 +17,25 @@ # +%{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-rednose -Version: 0.4.1 +Version: 1.2.3 Release: 0 Summary: Pretty output formatter for python-nosetests License: BSD-3-Clause Group: Development/Languages/Python Url: https://pypi.python.org/pypi/rednose/ -Source0: https://pypi.python.org/packages/source/r/rednose/rednose-%{version}.tar.gz -BuildRequires: python-devel -BuildRequires: python-setuptools +Source0: https://files.pythonhosted.org/packages/source/r/rednose/rednose-%{version}.tar.gz +BuildRequires: %{python_module devel} +BuildRequires: %{python_module setuptools} +BuildRequires: fdupes +BuildRequires: python-rpm-macros +Requires: python-colorama Requires: python-nose Requires: python-termstyle BuildRoot: %{_tmppath}/%{name}-%{version}-build -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%else BuildArch: noarch -%endif +%python_subpackages %description Rednose is a nosetests plugin for adding colour (and readability) to nosetest console results. @@ -43,13 +44,14 @@ %setup -q -n rednose-%{version} %build -python setup.py build +%python_build %install -python setup.py install --prefix=%{_prefix} --root=%{buildroot} +%python_install +%python_expand %fdupes %{buildroot}%{$python_sitelib} -%files +%files %{python_files} %defattr(-,root,root,-) -%{python_sitelib} +%{python_sitelib}/* %changelog ++++++ rednose-0.4.1.tar.gz -> rednose-1.2.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/PKG-INFO new/rednose-1.2.3/PKG-INFO --- old/rednose-0.4.1/PKG-INFO 2013-08-30 10:11:56.000000000 +0200 +++ new/rednose-1.2.3/PKG-INFO 2017-11-05 18:55:39.000000000 +0100 @@ -1,35 +1,34 @@ Metadata-Version: 1.1 Name: rednose -Version: 0.4.1 +Version: 1.2.3 Summary: coloured output for nosetests -Home-page: http://gfxmonk.net/dist/0install/rednose.xml +Home-page: https://github.com/JBKahn/rednose Author: UNKNOWN Author-email: UNKNOWN License: BSD -Description: - **Note**: This package has been built automatically by - `zero2pypi <http://gfxmonk.net/dist/0install/zero2pypi.xml>`_. - If possible, you should use the zero-install feed instead: - http://gfxmonk.net/dist/0install/rednose.xml - - ---------------- - - ========= +Description-Content-Type: UNKNOWN +Description: ========= rednose ========= rednose is a `nosetests`_ plugin for adding colour (and readability) to nosetest console results. + .. image:: rednose_example.png + :scale: 50 % + :align: center + Installation: ------------- :: - easy_install rednose + pip install rednose or from the source:: - ./setup.py develop + python setup.py install + + Rednose officially supports Python 2.7, 3.4, and 3.5. Usage: ------ @@ -51,6 +50,22 @@ (you can also control this by setting the environment variable NOSE_REDNOSE_COLOR to 'force' or 'no') + Rednose by default prints file paths relative to the working + directory. If you want the full path in the traceback then + use:: + + nosetests --rednose --full-file-path + + Rednose by default prints error style formating for skipped tests, + to supress this use:: + + nosetests --rednose --hide-skips + + Rednose supports printing the test results mid run as well as at + the end, to enable it use:: + + nosetests --rednose --immediate + .. _nosetests: http://somethingaboutorange.com/mrl/projects/nose/ Keywords: test nosetests nose nosetest output colour console diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/rednose.egg-info/PKG-INFO new/rednose-1.2.3/rednose.egg-info/PKG-INFO --- old/rednose-0.4.1/rednose.egg-info/PKG-INFO 2013-08-30 10:11:53.000000000 +0200 +++ new/rednose-1.2.3/rednose.egg-info/PKG-INFO 2017-11-05 18:55:39.000000000 +0100 @@ -1,35 +1,34 @@ Metadata-Version: 1.1 Name: rednose -Version: 0.4.1 +Version: 1.2.3 Summary: coloured output for nosetests -Home-page: http://gfxmonk.net/dist/0install/rednose.xml +Home-page: https://github.com/JBKahn/rednose Author: UNKNOWN Author-email: UNKNOWN License: BSD -Description: - **Note**: This package has been built automatically by - `zero2pypi <http://gfxmonk.net/dist/0install/zero2pypi.xml>`_. - If possible, you should use the zero-install feed instead: - http://gfxmonk.net/dist/0install/rednose.xml - - ---------------- - - ========= +Description-Content-Type: UNKNOWN +Description: ========= rednose ========= rednose is a `nosetests`_ plugin for adding colour (and readability) to nosetest console results. + .. image:: rednose_example.png + :scale: 50 % + :align: center + Installation: ------------- :: - easy_install rednose + pip install rednose or from the source:: - ./setup.py develop + python setup.py install + + Rednose officially supports Python 2.7, 3.4, and 3.5. Usage: ------ @@ -51,6 +50,22 @@ (you can also control this by setting the environment variable NOSE_REDNOSE_COLOR to 'force' or 'no') + Rednose by default prints file paths relative to the working + directory. If you want the full path in the traceback then + use:: + + nosetests --rednose --full-file-path + + Rednose by default prints error style formating for skipped tests, + to supress this use:: + + nosetests --rednose --hide-skips + + Rednose supports printing the test results mid run as well as at + the end, to enable it use:: + + nosetests --rednose --immediate + .. _nosetests: http://somethingaboutorange.com/mrl/projects/nose/ Keywords: test nosetests nose nosetest output colour console diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/rednose.egg-info/SOURCES.txt new/rednose-1.2.3/rednose.egg-info/SOURCES.txt --- old/rednose-0.4.1/rednose.egg-info/SOURCES.txt 2013-08-30 10:11:53.000000000 +0200 +++ new/rednose-1.2.3/rednose.egg-info/SOURCES.txt 2017-11-05 18:55:39.000000000 +0100 @@ -5,4 +5,11 @@ rednose.egg-info/dependency_links.txt rednose.egg-info/entry_points.txt rednose.egg-info/requires.txt -rednose.egg-info/top_level.txt \ No newline at end of file +rednose.egg-info/top_level.txt +test_files/__init__.py +test_files/basic_test_suite.py +test_files/class_test_failure.py +test_files/encoding_test.py +test_files/encoding_test_with_literals.py +test_files/new_tests.py +test_files/sample_test.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/rednose.egg-info/requires.txt new/rednose-1.2.3/rednose.egg-info/requires.txt --- old/rednose-0.4.1/rednose.egg-info/requires.txt 2013-08-30 10:11:53.000000000 +0200 +++ new/rednose-1.2.3/rednose.egg-info/requires.txt 2017-11-05 18:55:39.000000000 +0100 @@ -1,2 +1,3 @@ setuptools -python-termstyle >=0.1.7 \ No newline at end of file +termstyle>=0.1.7 +colorama diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/rednose.egg-info/top_level.txt new/rednose-1.2.3/rednose.egg-info/top_level.txt --- old/rednose-0.4.1/rednose.egg-info/top_level.txt 2013-08-30 10:11:53.000000000 +0200 +++ new/rednose-1.2.3/rednose.egg-info/top_level.txt 2017-11-05 18:55:39.000000000 +0100 @@ -1 +1,2 @@ rednose +test_files diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/rednose.py new/rednose-1.2.3/rednose.py --- old/rednose-0.4.1/rednose.py 2013-08-14 05:43:22.000000000 +0200 +++ new/rednose-1.2.3/rednose.py 2017-11-05 18:55:20.000000000 +0100 @@ -1,9 +1,9 @@ # Copyright (c) 2009, Tim Cuthbertson # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: -# +# # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above @@ -13,7 +13,7 @@ # * Neither the name of the organisation nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS @@ -32,356 +32,423 @@ import sys import linecache import re -import time import nose - import termstyle +PY3 = sys.version_info[0] >= 3 +if PY3: + to_unicode = str +else: + def to_unicode(s): + try: + return unicode(s) + except UnicodeDecodeError: + s = str(s) + try: + # try utf-8, the most likely case + return unicode(s, 'UTF-8') + except UnicodeDecodeError: + # Can't decode, just use `repr` + return unicode(repr(s)) + + failure = 'FAILED' error = 'ERROR' success = 'passed' skip = 'skipped' +expected_failure = 'expected failure' +unexpected_success = 'unexpected success' line_length = 77 -PY3 = sys.version_info[0] >= 3 -if PY3: - to_unicode = str -else: - def to_unicode(s): - try: - return unicode(s) - except UnicodeDecodeError: - return unicode(repr(str(s))) - -BLACKLISTED_WRITERS = [ - 'nose[\\/]result\\.pyc?$', - 'unittest[\\/]runner\\.pyc?$' -] -REDNOSE_DEBUG = False - class RedNose(nose.plugins.Plugin): - env_opt = 'NOSE_REDNOSE' - env_opt_color = 'NOSE_REDNOSE_COLOR' - score = 199 # just under the `coverage` module - - def __init__(self, *args): - super(RedNose, self).__init__(*args) - self.reports = [] - self.error = self.success = self.failure = self.skip = 0 - self.total = 0 - self.stream = None - self.verbose = False - self.enabled = False - self.tree = False - - def options(self, parser, env=os.environ): - global REDNOSE_DEBUG - rednose_on = bool(env.get(self.env_opt, False)) - rednose_color = env.get(self.env_opt_color, 'auto') - REDNOSE_DEBUG = bool(env.get('REDNOSE_DEBUG', False)) - - parser.add_option( - "--rednose", - action="store_true", - default=rednose_on, - dest="rednose", - help="enable colour output (alternatively, set $%s=1)" % (self.env_opt,) - ) - parser.add_option( - "--no-color", - action="store_false", - dest="rednose", - help="disable colour output" - ) - parser.add_option( - "--force-color", - action="store_const", - dest='rednose_color', - default=rednose_color, - const='force', - help="force colour output when not using a TTY (alternatively, set $%s=force)" % (self.env_opt_color,) - ) - parser.add_option( - "--immediate", - action="store_true", - default=False, - help="print errors and failures as they happen, as well as at the end" - ) - - def configure(self, options, conf): - if options.rednose: - self.enabled = True - termstyle_init = { - 'force': termstyle.enable, - 'off': termstyle.disable - }.get(options.rednose_color, termstyle.auto) - termstyle_init() - - self.immediate = options.immediate - self.verbose = options.verbosity >= 2 - - def begin(self): - self.start_time = time.time() - self._in_test = False - - def _format_test_name(self, test): - return test.shortDescription() or to_unicode(test) - - def prepareTestResult(self, result): - result.stream = FilteringStream(self.stream, BLACKLISTED_WRITERS) - - def beforeTest(self, test): - self._in_test = True - if self.verbose: - self._out(self._format_test_name(test) + ' ... ') - - def afterTest(self, test): - if self._in_test: - self.addSkip() - - def _print_test(self, type_, color): - self.total += 1 - if self.verbose: - self._outln(color(type_)) - else: - if type_ == failure: - short_ = 'F' - elif type_ == error: - short_ = 'X' - elif type_ == skip: - short_ = '-' - else: - short_ = '.' - self._out(color(short_)) - if self.total % line_length == 0: - self._outln() - self._in_test = False - - def _add_report(self, report): - failure_type, test, err = report - self.reports.append(report) - if self.immediate: - self._outln() - self._report_test(len(self.reports), *report) - - def addFailure(self, test, err): - self.failure += 1 - self._add_report((failure, test, err)) - self._print_test(failure, termstyle.red) - - def addError(self, test, err): - if err[0].__name__ == 'SkipTest': - self.addSkip(test, err) - return - self.error += 1 - self._add_report((error, test, err)) - self._print_test(error, termstyle.yellow) - - def addSuccess(self, test): - self.success += 1 - self._print_test(success, termstyle.green) - - def addSkip(self, test=None, err=None): - self.skip += 1 - self._print_test(skip, termstyle.blue) - - def setOutputStream(self, stream): - self.stream = stream - - def report(self, stream): - """report on all registered failures and errors""" - self._outln() - if self.immediate: - for x in range(0, 5): - self._outln() - report_num = 0 - if len(self.reports) > 0: - for report_num, report in enumerate(self.reports): - self._report_test(report_num + 1, *report) - self._outln() - - self._summarize() - - def _summarize(self): - """summarize all tests - the number of failures, errors and successes""" - self._line(termstyle.black) - self._out("%s test%s run in %0.1f seconds" % ( - self.total, - self._plural(self.total), - time.time() - self.start_time)) - if self.total > self.success: - self._outln(". ") - additionals = [] - if self.failure > 0: - additionals.append(termstyle.red("%s FAILED" % ( - self.failure,))) - if self.error > 0: - additionals.append(termstyle.yellow("%s error%s" % ( - self.error, - self._plural(self.error) ))) - if self.skip > 0: - additionals.append(termstyle.blue("%s skipped" % ( - self.skip))) - self._out(', '.join(additionals)) - - self._out(termstyle.green(" (%s test%s passed)" % ( - self.success, - self._plural(self.success) ))) - self._outln() - - def _report_test(self, report_num, type_, test, err): - """report the results of a single (failing or errored) test""" - self._line(termstyle.black) - self._out("%s) " % (report_num)) - if type_ == failure: - color = termstyle.red - self._outln(color('FAIL: %s' % (self._format_test_name(test),))) - else: - color = termstyle.yellow - self._outln(color('ERROR: %s' % (self._format_test_name(test),))) - - exc_type, exc_instance, exc_trace = err - - self._outln() - self._outln(self._fmt_traceback(exc_trace)) - self._out(color(' ', termstyle.bold(color(exc_type.__name__)), ": ")) - self._outln(self._fmt_message(exc_instance, color)) - self._outln() - - def _relative_path(self, path): - """ - If path is a child of the current working directory, the relative - path is returned surrounded by bold xterm escape sequences. - If path is not a child of the working directory, path is returned - """ - try: - here = os.path.abspath(os.path.realpath(os.getcwd())) - fullpath = os.path.abspath(os.path.realpath(path)) - except OSError: - return path - if fullpath.startswith(here): - return termstyle.bold(fullpath[len(here)+1:]) - return path - - def _file_line(self, tb): - """formats the file / lineno / function line of a traceback element""" - prefix = "file://" - prefix = "" - - f = tb.tb_frame - if '__unittest' in f.f_globals: - # this is the magical flag that prevents unittest internal - # code from junking up the stacktrace - return None - - filename = f.f_code.co_filename - lineno = tb.tb_lineno - linecache.checkcache(filename) - function_name = f.f_code.co_name - - line_contents = linecache.getline(filename, lineno, f.f_globals).strip() - - return " %s line %s in %s\n %s" % ( - termstyle.blue(prefix, self._relative_path(filename)), - lineno, - termstyle.cyan(function_name), - line_contents) - - def _fmt_traceback(self, trace): - """format a traceback""" - ret = [] - ret.append(termstyle.default(" Traceback (most recent call last):")) - current_trace = trace - while current_trace is not None: - line = self._file_line(current_trace) - if line is not None: - ret.append(line) - current_trace = current_trace.tb_next - return '\n'.join(ret) - - def _fmt_message(self, exception, color): - orig_message_lines = to_unicode(exception).splitlines() - - if len(orig_message_lines) == 0: - return '' - message_lines = [color(orig_message_lines[0])] - for line in orig_message_lines[1:]: - match = re.match('^---.* begin captured stdout.*----$', line) - if match: - color = None - message_lines.append('') - line = ' ' + line - message_lines.append(color(line) if color is not None else line) - return '\n'.join(message_lines) - - def _out(self, msg='', newline=False): - self.stream.write(msg) - if newline: - self.stream.write('\n') - - def _outln(self, msg=''): - self._out(msg, True) - - def _plural(self, num): - return '' if num == 1 else 's' - - def _line(self, color=termstyle.reset, char='-'): - """ - print a line of separator characters (default '-') - in the given colour (default black) - """ - self._outln(color(char * line_length)) - + env_opt = 'NOSE_REDNOSE' + env_opt_color = 'NOSE_REDNOSE_COLOR' -import traceback -import sys + def __init__(self, *args): + super(RedNose, self).__init__(*args) + self.enabled = False + + def options(self, parser, env=os.environ): + rednose_on = bool(env.get(self.env_opt, False)) + rednose_color = env.get(self.env_opt_color, 'auto') + + parser.add_option( + "--rednose", + action="store_true", + default=rednose_on, + dest="rednose", + help="enable colour output (alternatively, set $%s=1)" % (self.env_opt,) + ) + parser.add_option( + "--no-color", + action="store_false", + dest="rednose", + help="disable colour output" + ) + parser.add_option( + "--force-color", + action="store_const", + dest='rednose_color', + default=rednose_color, + const='force', + help="force colour output when not using a TTY (alternatively, set $%s=force)" % (self.env_opt_color,) + ) + parser.add_option( + "--immediate", + action="store_true", + default=False, + help="print errors and failures as they happen, as well as at the end" + ) + parser.add_option( + "--full-file-path", + action="store_true", + default=False, + help="print the full file path as opposed to the one relative to your directory (default)" + ) + parser.add_option( + "--hide-skips", + action="store_true", + default=False, + help="Hide the error printing for skip cases (default is to show them)" + ) + + def configure(self, options, conf): + if options.rednose: + self.enabled = True + termstyle_init = { + 'force': termstyle.enable, + 'off': termstyle.disable + }.get(options.rednose_color, termstyle.auto) + termstyle_init() + + self.immediate = options.immediate + self.verbose = options.verbosity >= 2 + self.full_file_path = options.full_file_path + self.hide_skips = options.hide_skips + + def prepareTestResult(self, result): # noqa + """Required to prevent others from monkey patching the add methods.""" + return result + + def prepareTestRunner(self, runner): # noqa + stream = runner.stream + if os.name == 'nt': + import colorama + stream = colorama.initialise.wrap_stream(stream, convert=True, strip=False, autoreset=False, wrap=True) + return ColourTestRunner(stream=stream, descriptions=runner.descriptions, verbosity=runner.verbosity, config=runner.config, immediate=self.immediate, use_relative_path=not self.full_file_path, hide_skips=self.hide_skips) + + +class ColourTestRunner(nose.core.TextTestRunner): + + def __init__(self, stream, descriptions, verbosity, config, immediate, use_relative_path, hide_skips): + super(ColourTestRunner, self).__init__(stream=stream, descriptions=descriptions, verbosity=verbosity, config=config) + self.immediate = immediate + self.use_relative_path = use_relative_path + self.hide_skips = hide_skips + + def _makeResult(self): # noqa + return ColourTextTestResult(self.stream, self.descriptions, self.verbosity, self.config, immediate=self.immediate, use_relative_path=self.use_relative_path, hide_skips=self.hide_skips) + + +class ColourTextTestResult(nose.result.TextTestResult): + """ + A test result class that prints colour formatted text results to the stream. + """ + + def __init__(self, stream, descriptions, verbosity, config, errorClasses=None, immediate=False, use_relative_path=False, hide_skips=False): # noqa + super(ColourTextTestResult, self).__init__(stream=stream, descriptions=descriptions, verbosity=verbosity, config=config, errorClasses=errorClasses) + self.has_test_ids = getattr(config.options, "enable_plugin_id", False) + if self.has_test_ids: + self.ids = self.get_test_ids(self.config.options.testIdFile) + self.total = 0 + self.immediate = immediate + self.use_relative_path = use_relative_path + self.hide_skips = hide_skips + self.test_failures_and_exceptions = [] + self.error = self.success = self.failure = self.skip = self.expected_failure = self.unexpected_success = 0 + self.verbose = config.verbosity >= 2 + self.short_status_map = { + failure: 'F', + error: 'E', + skip: '-', + expected_failure: "X", + unexpected_success: "U", + success: '.', + } + self.skips = [] + + def get_test_ids(self, test_id_file): + """Returns a mapping of test to id if one exists, else an empty dictionary.""" + try: + with open(test_id_file, 'rb') as fh: + try: + from cPickle import load + except ImportError: + from pickle import load + data = load(fh) + + return dict((address, _id) for _id, address in data["ids"].items()) + except (IOError, ValueError): + return {} + + def printSummary(self, start, stop): # noqa + """Summarize all tests - the number of failures, errors and successes.""" + self._line(termstyle.black) + self._out("%s test%s run in %0.3f seconds" % (self.total, self._plural(self.total), stop - start)) + if self.total > self.success: + self._outln(". ") + + additionals = [ + {"color": termstyle.red, "count": self.failure, "message": "%s FAILED"}, + {"color": termstyle.yellow, "count": self.error, "message": "%s error%s" % ("%s", self._plural(self.error))}, + {"color": termstyle.blue, "count": self.skip, "message": "%s skipped"}, + {"color": termstyle.green, "count": self.expected_failure, "message": "%s expected_failures"}, + {"color": termstyle.cyan, "count": self.unexpected_success, "message": "%s unexpected_successes"}, + ] + + additionals_to_print = [ + additional["color"](additional["message"] % (additional["count"])) for additional in additionals if additional["count"] > 0 + ] + + self._out(', '.join(additionals_to_print)) + + self._out(termstyle.green(" (%s test%s passed)" % (self.success, self._plural(self.success)))) + self._outln() + + def _plural(self, num): + return '' if num == 1 else 's' + + def _line(self, color=termstyle.reset, char='-'): + """ + Print a line of separator characters (default '-') in the given colour (default black). + """ + self._outln(color(char * line_length)) + + def _print_test(self, test, type_, color): + self.total += 1 + if self.verbose: + self._outln(color(type_)) + else: + short_ = self.short_status_map.get(type_, ".") + self._out(color(short_)) + if self.total % line_length == 0: + self._outln() + + def _out(self, msg='', newline=False): + try: + self.stream.write(msg) + self.stream.flush() + except UnicodeEncodeError: + self.stream.write(msg.encode('utf-8')) + self.stream.flush() + if newline: + self.stream.write('\n') + + def _outln(self, msg=''): + self._out(msg=msg, newline=True) + + def _generate_and_add_test_report(self, type_, test, err): + report = self._report_test(len(self.test_failures_and_exceptions), type_, test, err) + self.test_failures_and_exceptions.append(report) + + def addFailure(self, test, err): # noqa + self.failure += 1 + self._print_test(test, failure, termstyle.red) + self._generate_and_add_test_report(failure, test, err) + + def addError(self, test, err): # noqa + if err[0].__name__ == 'SkipTest': + self.addSkip(test, err) + return + self.error += 1 + self._print_test(test, error, termstyle.yellow) + self._generate_and_add_test_report(error, test, err) + + def addSuccess(self, test): # noqa + self.success += 1 + self._print_test(test, success, termstyle.green) + + def addSkip(self, test, err): # noqa + if isinstance(err, Exception): + err = (err.__class__, err, None) + elif self.verbose: + skip_message = "#{test_id} {test_location} ... ".format( + test_id=self._get_id(test), + test_location=getattr(test.context, "__file__", getattr(test.context, "__module__", None)) + ) + self._out(termstyle.reset(skip_message)) + self.skip += 1 + self._print_test(test, skip, termstyle.blue) + if not self.hide_skips: + self._generate_and_add_test_report(skip, test, err) + + def addExpectedFailure(self, test, err): # noqa + self.expected_failure += 1 + self._print_test(test, expected_failure, termstyle.green) + + def addUnexpectedSuccess(self, test): # noqa + self.unexpected_success += 1 + self._print_test(test, unexpected_success, termstyle.cyan) + + def _report_test(self, report_index_num, type_, test, err): # noqa + """report the results of a single (failing or errored) test""" + exc_type, exc_instance, exc_trace = err + + if type_ == failure: + color = termstyle.red + elif type_ == skip: + color = termstyle.blue + exc_type = nose.SkipTest + else: + color = termstyle.yellow + + colored_error_text = [ + ''.join(self.format_traceback(exc_trace)), + self._format_exception_message(exc_type, exc_instance, color) + ] + + if type_ == failure: + self.failures.append((test, colored_error_text)) + flavour = "FAIL" + elif type_ == skip: + self.skips.append((test, colored_error_text)) + flavour = "SKIP" + else: + self.errors.append((test, colored_error_text)) + flavour = "ERROR" + + test_id = self._get_id(test) + + if self.immediate: + self._outln() + self._printError(flavour, test, colored_error_text, test_id, True) + + return (test_id, flavour, test, colored_error_text) + + def _get_id(self, test): + report_index_num = len(self.test_failures_and_exceptions) + if self.has_test_ids: + try: + test_id = self.ids.get(test.address(), self.total) + except AttributeError: + test_id = report_index_num + 1 + else: + test_id = report_index_num + 1 + return test_id + + def format_traceback(self, tb): + if tb is not None: + ret = [termstyle.default(" Traceback (most recent call last):")] + else: + ret = [termstyle.default(" No Traceback")] + + current_trace = tb + while current_trace is not None: + line = self._format_traceback_line(current_trace) + if line is not None: + ret.append(line) + current_trace = current_trace.tb_next + return '\n'.join(ret) + + def _format_traceback_line(self, tb): + """ + Formats the file / lineno / function line of a traceback element. + + Returns None is the line is not relevent to the user i.e. inside the test runner. + """ + if self._is_relevant_tb_level(tb): + return None + + f = tb.tb_frame + filename = f.f_code.co_filename + lineno = tb.tb_lineno + linecache.checkcache(filename) + function_name = f.f_code.co_name + + line_contents = linecache.getline(filename, lineno, f.f_globals).strip() + + return " %s line %s in %s\n %s" % ( + termstyle.blue(self._relative_path(filename) if self.use_relative_path else filename), + termstyle.bold(termstyle.cyan(lineno)), + termstyle.cyan(function_name), + line_contents + ) + + def _format_exception_message(self, exception_type, exception_instance, message_color): + """Returns a colorized formatted exception message.""" + orig_message_lines = to_unicode(exception_instance).splitlines() + + if len(orig_message_lines) == 0: + return '' + exception_message = orig_message_lines[0] + + message_lines = [message_color(' ', termstyle.bold(message_color(exception_type.__name__)), ": ") + message_color(exception_message)] + for line in orig_message_lines[1:]: + match = re.match('^---.* begin captured stdout.*----$', line) + if match: + message_color = termstyle.magenta + message_lines.append('') + line = ' ' + line + message_lines.append(message_color(line)) + return '\n'.join(message_lines) + + def _relative_path(self, path): + """ + Returns the relative path of a file to the current working directory. + + If path is a child of the current working directory, the relative + path is returned surrounded. + If path is not a child of the working directory, path is returned + """ + try: + here = os.path.abspath(os.path.realpath(os.getcwd())) + fullpath = os.path.abspath(os.path.realpath(path)) + except OSError: + return path + if fullpath.startswith(here): + return fullpath[len(here) + 1:] + return path + + def printErrors(self): # noqa + if not self.verbose: + self._outln() + if self.immediate: + self._outln() + for x in range(0, 4): + self._outln() + + self._outln(termstyle.green("TEST RESULT OUTPUT:")) + + for (test_id, flavour, test, coloured_output_lines) in (self.test_failures_and_exceptions): + self._printError(flavour=flavour, test=test, coloured_output_lines=coloured_output_lines, test_id=test_id) + + # Copied from the parent function. + self._outln() + for cls in self.errorClasses.keys(): + storage, label, isfail = self.errorClasses[cls] + if isfail: + self.printErrorList(label, storage) + # Might get patched into a result with no config + if hasattr(self, 'config'): + self.config.plugins.report(self.stream) + + def _printError(self, flavour, test, coloured_output_lines, test_id, is_mid_test=False): # noqa + if flavour == "FAIL": + color = termstyle.red + elif flavour == "SKIP": + color = termstyle.blue + + else: + color = termstyle.yellow + + self._outln(color(self.separator1)) + self._outln(color("%s) %s: %s" % (test_id, flavour, self.getDescription(test)))) + self._outln(color(self.separator2)) + for err_line in coloured_output_lines: + self._outln("%s" % err_line) -class FilteringStream(object): - """ - A wrapper for a stream that will filter - calls to `write` and `writeln` to ignore calls - from blacklisted callers - (implemented as a regex on their filename, according - to traceback.extract_stack()) - - It's super hacky, but there seems to be no other way - to suppress nose's default output - """ - def __init__(self, stream, excludes): - self.__stream = stream - self.__excludes = list(map(re.compile, excludes)) - - def __should_filter(self): - try: - stack = traceback.extract_stack(limit=3)[0] - filename = stack[0] - pattern_matches_filename = lambda pattern: pattern.search(filename) - should_filter = any(map(pattern_matches_filename, self.__excludes)) - if REDNOSE_DEBUG: - print >> sys.stderr, "REDNOSE_DEBUG: got write call from %s, should_filter = %s" % ( - filename, should_filter) - return should_filter - except StandardError as e: - if REDNOSE_DEBUG: - print("\nError in rednose filtering: %s" % (e,), file=sys.stderr) - traceback.print_exc(sys.stderr) - return False - - def write(self, *a): - if self.__should_filter(): - return - return self.__stream.write(*a) - - def writeln(self, *a): - if self.__should_filter(): - return - return self.__stream.writeln(*a) - - # pass non-known methods through to self.__stream - def __getattr__(self, name): - if REDNOSE_DEBUG: - print("REDNOSE_DEBUG: getting attr %s" % (name,), file=sys.stderr) - return getattr(self.__stream, name) + if is_mid_test: + self._outln(color(self.separator2)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/setup.cfg new/rednose-1.2.3/setup.cfg --- old/rednose-0.4.1/setup.cfg 2013-08-30 10:11:56.000000000 +0200 +++ new/rednose-1.2.3/setup.cfg 2017-11-05 18:55:39.000000000 +0100 @@ -1,5 +1,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/setup.py new/rednose-1.2.3/setup.py --- old/rednose-0.4.1/setup.py 2013-08-30 10:11:05.000000000 +0200 +++ new/rednose-1.2.3/setup.py 2017-11-05 18:55:20.000000000 +0100 @@ -1,29 +1,34 @@ -#!/usr/bin/env python +from os import path +from setuptools import setup, find_packages -## NOTE: ## -## this setup.py was generated by zero2pypi: -## http://gfxmonk.net/dist/0install/zero2pypi.xml -from setuptools import * +def read(fname): + try: + return open(path.join(path.dirname(__file__), fname)).read() + except IOError: + return """A module for making nose pretty using colors.""" + setup( - packages = find_packages(exclude=['test', 'test.*']), - description='coloured output for nosetests', - entry_points={'nose.plugins.0.10': ['NOSETESTS_PLUGINS = rednose:RedNose']}, - install_requires=['setuptools', 'python-termstyle >=0.1.7'], - long_description="\n**Note**: This package has been built automatically by\n`zero2pypi <http://gfxmonk.net/dist/0install/zero2pypi.xml>`_.\nIf possible, you should use the zero-install feed instead:\nhttp://gfxmonk.net/dist/0install/rednose.xml\n\n----------------\n\n=========\nrednose\n=========\n\nrednose is a `nosetests`_\nplugin for adding colour (and readability) to nosetest console results.\n\nInstallation:\n-------------\n::\n\n\teasy_install rednose\n\t\nor from the source::\n\n\t./setup.py develop\n\nUsage:\n------\n::\n\n\tnosetests --rednose\n\nor::\n\n\texport NOSE_REDNOSE=1\n\tnosetests\n\nRednose by default uses auto-colouring, which will only use\ncolour if you're running it on a terminal (i.e not piping it\nto a file). To control colouring, use one of::\n\n\tnosetests --rednose --force-color\n\tnosetests --no-color\n\n(you can also control this by setting the environment variable NOSE_REDNOSE_COLOR to 'force' or 'no')\n\n.. _nosetests: http://somethingaboutorange.com/mrl/projects/nose/\n", - name='rednose', - py_modules=['rednose'], - url='http://gfxmonk.net/dist/0install/rednose.xml', - version='0.4.1', -classifiers=[ - "License :: OSI Approved :: BSD License", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Software Development :: Testing", - ], - keywords='test nosetests nose nosetest output colour console', - license='BSD', + packages=find_packages(exclude=['test', 'test.*']), + description='coloured output for nosetests', + entry_points={'nose.plugins.0.10': ['NOSETESTS_PLUGINS = rednose:RedNose']}, + install_requires=['setuptools', 'termstyle >=0.1.7', 'colorama'], + tests_require=['six==1.10.0'], + long_description=read('README.rst'), + name='rednose', + py_modules=['rednose'], + url='https://github.com/JBKahn/rednose', + version='1.2.3', + classifiers=[ + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Testing", + ], + keywords='test nosetests nose nosetest output colour console', + license='BSD', + test_suite='test_files.new_tests', ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/test_files/basic_test_suite.py new/rednose-1.2.3/test_files/basic_test_suite.py --- old/rednose-0.4.1/test_files/basic_test_suite.py 1970-01-01 01:00:00.000000000 +0100 +++ new/rednose-1.2.3/test_files/basic_test_suite.py 2017-11-05 18:55:20.000000000 +0100 @@ -0,0 +1,6 @@ +import unittest + + +class TC(unittest.TestCase): + def runTest(self): # noqa + raise ValueError("I hate fancy stuff") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/test_files/class_test_failure.py new/rednose-1.2.3/test_files/class_test_failure.py --- old/rednose-0.4.1/test_files/class_test_failure.py 1970-01-01 01:00:00.000000000 +0100 +++ new/rednose-1.2.3/test_files/class_test_failure.py 2017-11-05 18:55:20.000000000 +0100 @@ -0,0 +1,34 @@ +from __future__ import print_function +import unittest + + +def setup_module(): + raise unittest.SkipTest('RESI specific Nonius libs not present') + print(__name__, ': setup_module() ~~~~~~~~~~~~~~~~~~~~~~') + + +def teardown_module(): + print(__name__, ': teardown_module() ~~~~~~~~~~~~~~~~~~~') + + +class SomeSkippedTest(unittest.TestCase): + + @classmethod + def setup_class(cls): + print(__name__, ': TestClass.setup_class() ----------') + + @classmethod + def teardown_class(cls): + print(__name__, ': TestClass.teardown_class() -------') + + def setup(self): + print(__name__, ': TestClass.setup() - - - - - - - -') + + def teardown(self): + print(__name__, ': TestClass.teardown() - - - - - - -') + + def test_method_1(self): + print(__name__, ': TestClass.test_method_1()') + + def test_method_2(self): + print(__name__, ': TestClass.test_method_2()') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/test_files/encoding_test.py new/rednose-1.2.3/test_files/encoding_test.py --- old/rednose-0.4.1/test_files/encoding_test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/rednose-1.2.3/test_files/encoding_test.py 2017-11-05 18:55:20.000000000 +0100 @@ -0,0 +1,8 @@ +# vim: fileencoding=utf-8: + +# NOTE: this file does *not* import unicode_literals, +# so the assertion message is actually just utf-8 bytes + + +def test(): + assert False, "ä" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/test_files/encoding_test_with_literals.py new/rednose-1.2.3/test_files/encoding_test_with_literals.py --- old/rednose-0.4.1/test_files/encoding_test_with_literals.py 1970-01-01 01:00:00.000000000 +0100 +++ new/rednose-1.2.3/test_files/encoding_test_with_literals.py 2017-11-05 18:55:20.000000000 +0100 @@ -0,0 +1,9 @@ +# vim: fileencoding=utf-8: +from __future__ import unicode_literals + +import unittest + + +class EncodingTest(unittest.TestCase): + def test_utf8(self): + self.assertEqual('café', 'abc') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/test_files/new_tests.py new/rednose-1.2.3/test_files/new_tests.py --- old/rednose-0.4.1/test_files/new_tests.py 1970-01-01 01:00:00.000000000 +0100 +++ new/rednose-1.2.3/test_files/new_tests.py 2017-11-05 18:55:20.000000000 +0100 @@ -0,0 +1,324 @@ +# -*- coding: utf-8 -*- + +import os +import sys +import unittest + +import nose +from nose.plugins import PluginTester, testid +from six import PY2, PY3 + +from rednose import RedNose + + +try: + from unittest import skip, skipUnless +except ImportError: + def skip(f): + return lambda self: None + + def skipUnless(condition, reason): # noqa + if condition: + return lambda x: x + else: + return lambda x: None + + +class TestRedNoseWithId(PluginTester, unittest.TestCase): + activate = '--rednose' + plugins = [RedNose(), testid.TestId()] + args = ['--force-color', '--with-id'] + env = {} + + def test_colored_result(self): + expected_lines = [ + '\x1b[33mE\x1b[0m', + '\x1b[33m======================================================================\x1b[0m', + '\x1b[33m1) ERROR: runTest (test_files.basic_test_suite.TC)\x1b[0m', + '\x1b[33m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34mtest_files/basic_test_suite.py\x1b[0m line \x1b[1m\x1b[36m6\x1b[0m\x1b[0m in \x1b[36mrunTest\x1b[0m', + ' raise ValueError("I hate fancy stuff")', + '\x1b[33m \x1b[33m\x1b[1m\x1b[33mValueError\x1b[0m\x1b[0m\x1b[33m: \x1b[0m\x1b[33mI hate fancy stuff\x1b[0m', + '', + '\x1b[30m-----------------------------------------------------------------------------\x1b[0m', + '1 test run in', + '\x1b[33m1 error\x1b[0m\x1b[32m (0 tests passed)\x1b[0m', + '', + ] + for expected_line, actual_line in zip(expected_lines, str(self.output).split("\n")): + if expected_line not in actual_line: + print(expected_line) + print(actual_line) + print(self.output) + self.assertTrue(expected_line in actual_line) + + def makeSuite(self): # noqa + from test_files.basic_test_suite import TC + return [TC('runTest')] + + +class TestRedNose(PluginTester, unittest.TestCase): + activate = '--rednose' + plugins = [RedNose()] + args = ['--force-color'] + env = {} + + def test_colored_result(self): + expected_lines = [ + '\x1b[33mE\x1b[0m', + '\x1b[33m======================================================================\x1b[0m', + '\x1b[33m1) ERROR: runTest (test_files.basic_test_suite.TC)\x1b[0m', + '\x1b[33m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34mtest_files/basic_test_suite.py\x1b[0m line \x1b[1m\x1b[36m6\x1b[0m\x1b[0m in \x1b[36mrunTest\x1b[0m', + ' raise ValueError("I hate fancy stuff")', + '\x1b[33m \x1b[33m\x1b[1m\x1b[33mValueError\x1b[0m\x1b[0m\x1b[33m: \x1b[0m\x1b[33mI hate fancy stuff\x1b[0m', + '', + '\x1b[30m-----------------------------------------------------------------------------\x1b[0m', + '1 test run in', + '\x1b[33m1 error\x1b[0m\x1b[32m (0 tests passed)\x1b[0m', + '', + ] + for expected_line, actual_line in zip(expected_lines, str(self.output).split("\n")): + if expected_line not in actual_line: + print(expected_line) + print(actual_line) + print(self.output) + self.assertTrue(expected_line in actual_line) + + def makeSuite(self): # noqa + from test_files.basic_test_suite import TC + return [TC('runTest')] + + +@skipUnless(sys.version_info >= (2, 7), "python 2.6 not supported") +class TestRedNoseSkipInClass(PluginTester, unittest.TestCase): + activate = '--rednose' + plugins = [RedNose()] + args = ['--force-color'] + env = {} + suitepath = os.path.join(os.getcwd(), 'test_files', 'class_test_failure.py') + + def test_colored_result(self): + expected_lines = [ + '\x1b[34m-\x1b[0m', + '\x1b[34m======================================================================\x1b[0m', + "\x1b[34m1) SKIP: test suite for <module 'test_files.class_test_failure' from '{0}/test_files/class_test_failure.py".format(os.getcwd()), + '\x1b[34m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34m{0}/suite.py\x1b[0m line \x1b[1m\x1b[36m'.format(nose.__path__[0]), + ' self.setUp()', + ' \x1b[34m{0}/suite.py\x1b[0m line \x1b[1m\x1b[36m'.format(nose.__path__[0]), + ' self.setupContext(ancestor)', + ' \x1b[34m{0}/suite.py\x1b[0m line \x1b[1m\x1b[36m'.format(nose.__path__[0]), + ' try_run(context, names)', + ' \x1b[34m{0}/util.py\x1b[0m line \x1b[1m\x1b[36m'.format(nose.__path__[0]), + ' return func()', + ' \x1b[34mtest_files/class_test_failure.py\x1b[0m line \x1b[1m\x1b[36m6\x1b[0m\x1b[0m in \x1b[36msetup_module\x1b[0m', + " raise unittest.SkipTest('RESI specific Nonius libs not present')", + '\x1b[34m \x1b[34m\x1b[1m\x1b[34mSkipTest\x1b[0m\x1b[0m\x1b[34m: \x1b[0m\x1b[34mRESI specific Nonius libs not present\x1b[0m', + '', + '\x1b[30m-----------------------------------------------------------------------------\x1b[0m', + '1 test run in ', + '\x1b[34m1 skipped\x1b[0m\x1b[32m (0 tests passed)\x1b[0m', + '', + ] + for expected_line, actual_line in zip(expected_lines, str(self.output).split("\n")): + if expected_line not in actual_line: + print(expected_line) + print(actual_line) + print(self.output) + self.assertTrue(expected_line in actual_line) + + +@skipUnless(sys.version_info >= (2, 7), "python 2.6 not supported") +class TestRedNoseSampleTests(PluginTester, unittest.TestCase): + activate = '--rednose' + plugins = [RedNose()] + args = ['--force-color'] + env = {} + suitepath = os.path.join(os.getcwd(), 'test_files', 'sample_test.py') + + def test_colored_result(self): + expected_lines = [ + '\x1b[33mE\x1b[0m\x1b[31mF\x1b[0m\x1b[34m-\x1b[0m\x1b[34m-\x1b[0m\x1b[32m.\x1b[0m\x1b[31mF\x1b[0m', + '\x1b[33m======================================================================\x1b[0m', + '\x1b[33m1) ERROR: test_error (test_files.sample_test.SomeTest)\x1b[0m', + '\x1b[33m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34mtest_files/sample_test.py\x1b[0m line \x1b[1m\x1b[36m20\x1b[0m\x1b[0m in \x1b[36mtest_error\x1b[0m', + ' raise RuntimeError("things went south\\nand here\'s a second line!")', + '\x1b[33m \x1b[33m\x1b[1m\x1b[33mRuntimeError\x1b[0m\x1b[0m\x1b[33m: \x1b[0m\x1b[33mthings went south\x1b[0m', + "\x1b[33m and here's a second line!\x1b[0m", + '\x1b[31m======================================================================\x1b[0m', + '\x1b[31m2) FAIL: test_fail (test_files.sample_test.SomeTest)\x1b[0m', + '\x1b[31m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34mtest_files/sample_test.py\x1b[0m line \x1b[1m\x1b[36m14\x1b[0m\x1b[0m in \x1b[36mtest_fail\x1b[0m', + " delay_fail(lambda: self.fail('no dice'))", + ' \x1b[34mtest_files/sample_test.py\x1b[0m line \x1b[1m\x1b[36m8\x1b[0m\x1b[0m in \x1b[36mdelay_fail\x1b[0m', + ' f() # fail it!', + ' \x1b[34mtest_files/sample_test.py\x1b[0m line \x1b[1m\x1b[36m14\x1b[0m\x1b[0m in \x1b[36m<lambda>\x1b[0m', + " delay_fail(lambda: self.fail('no dice'))", + '\x1b[31m \x1b[31m\x1b[1m\x1b[31mAssertionError\x1b[0m\x1b[0m\x1b[31m: \x1b[0m\x1b[31mno dice\x1b[0m', + '\x1b[34m======================================================================\x1b[0m', + '\x1b[34m3) SKIP: test_skip (test_files.sample_test.SomeTest)\x1b[0m', + '\x1b[34m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m No Traceback\x1b[0m', + '', + '\x1b[34m======================================================================\x1b[0m', + '\x1b[34m4) SKIP: test_skip_with_reason (test_files.sample_test.SomeTest)\x1b[0m', + '\x1b[34m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m No Traceback\x1b[0m', + "\x1b[34m \x1b[34m\x1b[1m\x1b[34mSkipTest\x1b[0m\x1b[0m\x1b[34m: \x1b[0m\x1b[34mLook at me, I'm skipping for a reason!!\x1b[0m", + '\x1b[31m======================================================================\x1b[0m', + "\x1b[31m5) FAIL: It's got a long description, you see?.\x1b[0m", + '\x1b[31m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34mtest_files/sample_test.py\x1b[0m line \x1b[1m\x1b[36m32\x1b[0m\x1b[0m in \x1b[36mtest_with_long_description\x1b[0m', + ' self.fail()', '\x1b[31m \x1b[31m\x1b[1m\x1b[31mAssertionError\x1b[0m\x1b[0m\x1b[31m: \x1b[0m\x1b[31mNone\x1b[0m', + '', + "\x1b[34m6) SKIP: test suite for <class 'test_files.sample_test.TestBug'>\x1b[0m", + '\x1b[34m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + 'nose/suite.py\x1b[0m line', + ' self.setUp()', + 'nose/suite.py\x1b[0m line', + ' self.setupContext(ancestor)', + 'nose/suite.py\x1b[0m line', + ' try_run(context, names)', + 'nose/util.py\x1b[0m line', + ' return func()', + ' \x1b[34mtest_files/sample_test.py\x1b[0m line \x1b[1m\x1b[36m39\x1b[0m\x1b[0m in \x1b[36msetUpClass\x1b[0m', + ' raise nose.SkipTest("SKIPPING!")', + '\x1b[34m \x1b[34m\x1b[1m\x1b[34mSkipTest\x1b[0m\x1b[0m\x1b[34m: \x1b[0m\x1b[34mSKIPPING!\x1b[0m', + '', + '\x1b[30m-----------------------------------------------------------------------------\x1b[0m', + '7 tests run in ', + '\x1b[31m2 FAILED\x1b[0m, \x1b[33m1 error\x1b[0m, \x1b[34m3 skipped\x1b[0m\x1b[32m (1 test passed)\x1b[0m', + '' + ] + if PY2: + import sys + if sys.version_info[1] == 6: + expected_lines = expected_lines[:8] + expected_lines[10:] + + for expected_line, actual_line in zip(expected_lines, str(self.output).split("\n")): + if expected_line not in actual_line: + print(expected_line) + print(actual_line) + print(self.output) + self.assertTrue(expected_line in actual_line) + + +class TestRedNoseEncoding(PluginTester, unittest.TestCase): + activate = '--rednose' + plugins = [RedNose()] + args = ['--force-color'] + env = {} + suitepath = os.path.join(os.getcwd(), 'test_files', 'encoding_test.py') + + def setUp(self): + import sys + self.old_encoding = sys.getdefaultencoding() + if PY2: + reload(sys) + sys.setdefaultencoding('utf8') + super(TestRedNoseEncoding, self).setUp() + + def tearDown(self): + import sys + if PY2: + reload(sys) + sys.setdefaultencoding(self.old_encoding) + super(TestRedNoseEncoding, self).tearDown() + + def test_colored_result(self): + expected_lines = [ + '\x1b[31mF\x1b[0m', + '\x1b[31m======================================================================\x1b[0m', + '\x1b[31m1) FAIL: test_files.encoding_test.test\x1b[0m', + '\x1b[31m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34m{0}/case.py\x1b[0m line \x1b[1m\x1b[36m'.format(nose.__path__[0]), + ' self.test(*self.arg)', + ' \x1b[34mtest_files/encoding_test.py\x1b[0m line \x1b[1m\x1b[36m8\x1b[0m\x1b[0m in \x1b[36mtest\x1b[0m', + ' assert False, "\xc3\xa4"', + '\x1b[31m \x1b[31m\x1b[1m\x1b[31mAssertionError\x1b[0m\x1b[0m\x1b[31m: \x1b[0m\x1b[31m\xc3\xa4\x1b[0m', + '', + '\x1b[30m-----------------------------------------------------------------------------\x1b[0m', + '1 test run in ', + '\x1b[31m1 FAILED\x1b[0m\x1b[32m (0 tests passed)\x1b[0m', + '' + ] + + if PY3: + pass + expected_lines[8] = ' assert False, "ä"' + expected_lines[9] = '\x1b[31m \x1b[31m\x1b[1m\x1b[31mAssertionError\x1b[0m\x1b[0m\x1b[31m: \x1b[0m\x1b[31mä\x1b[0m' + + for expected_line, actual_line in zip(expected_lines, str(self.output).split("\n")): + if expected_line not in actual_line: + print(expected_line) + print(actual_line) + print(self.output) + self.assertTrue(expected_line in actual_line) + + +class TestRedNoseEncodingWithLiterals(PluginTester, unittest.TestCase): + activate = '--rednose' + plugins = [RedNose()] + args = ['--force-color'] + env = {} + suitepath = os.path.join(os.getcwd(), 'test_files', 'encoding_test_with_literals.py') + + def setUp(self): + import sys + self.old_encoding = sys.getdefaultencoding() + if PY2: + reload(sys) + sys.setdefaultencoding('utf8') + super(TestRedNoseEncodingWithLiterals, self).setUp() + + def tearDown(self): + import sys + if PY2: + reload(sys) + sys.setdefaultencoding(self.old_encoding) + super(TestRedNoseEncodingWithLiterals, self).tearDown() + + def test_colored_result(self): + expected_lines = [ + '\x1b[31mF\x1b[0m', + '\x1b[31m======================================================================\x1b[0m', + '\x1b[31m1) FAIL: test_utf8 (test_files.encoding_test_with_literals.EncodingTest)\x1b[0m', + '\x1b[31m----------------------------------------------------------------------\x1b[0m', + '\x1b[0m Traceback (most recent call last):\x1b[0m', + ' \x1b[34mtest_files/encoding_test_with_literals.py\x1b[0m line \x1b[1m\x1b[36m9\x1b[0m\x1b[0m in \x1b[36mtest_utf8\x1b[0m', + " self.assertEqual('caf\xc3\xa9', 'abc')", + "\x1b[31m \x1b[31m\x1b[1m\x1b[31mAssertionError\x1b[0m\x1b[0m\x1b[31m: \x1b[0m\x1b[31mu'caf\\xe9' != u'abc'\x1b[0m", + '\x1b[31m - caf\xc3\xa9\x1b[0m', + '\x1b[31m + abc\x1b[0m', + '', + '\x1b[30m-----------------------------------------------------------------------------\x1b[0m', + '1 test run in ', + '\x1b[31m1 FAILED\x1b[0m\x1b[32m (0 tests passed)\x1b[0m', + '' + ] + + if PY3: + expected_lines[6] = " self.assertEqual('café', 'abc')" + expected_lines[7] = "\x1b[31m \x1b[31m\x1b[1m\x1b[31mAssertionError\x1b[0m\x1b[0m\x1b[31m: \x1b[0m\x1b[31m'café' != 'abc'\x1b[0m" + expected_lines[8] = "\x1b[31m - café\x1b[0m" + elif PY2: + import sys + if sys.version_info[1] == 6: + expected_lines = expected_lines[:8] + expected_lines[10:] + + for expected_line, actual_line in zip(expected_lines, str(self.output).split("\n")): + if expected_line not in actual_line: + print(expected_line) + print(actual_line) + print(self.output) + self.assertTrue(expected_line in actual_line) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rednose-0.4.1/test_files/sample_test.py new/rednose-1.2.3/test_files/sample_test.py --- old/rednose-0.4.1/test_files/sample_test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/rednose-1.2.3/test_files/sample_test.py 2017-11-05 18:55:20.000000000 +0100 @@ -0,0 +1,42 @@ +# vim: set fileencoding=utf-8 : +from __future__ import print_function +from __future__ import unicode_literals +import unittest + + +def delay_fail(f): + f() # fail it! + + +class SomeTest(unittest.TestCase): + def test_fail(self): + print("oh noes, it's gonna blow!") + delay_fail(lambda: self.fail('no dice')) + + def test_success(self): + self.assertEqual(True, True) + + def test_error(self): + raise RuntimeError("things went south\nand here's a second line!") + + def test_skip(self): + import nose + raise nose.SkipTest + + def test_skip_with_reason(self): + import nose + raise nose.SkipTest("Look at me, I'm skipping for a reason!!") + + def test_with_long_description(self): + """It's got a long description, you see?.""" + self.fail() + + +class TestBug(unittest.TestCase): + @classmethod + def setUpClass(cls): + import nose + raise nose.SkipTest("SKIPPING!") + + def test_bug(self): + pass
