diff --git a/python-nose-r708-through-r111-py27-fixes.patch b/python-nose-r708-through-r111-py27-fixes.patch new file mode 100644 index 0000000..b94af65 --- /dev/null +++ b/python-nose-r708-through-r111-py27-fixes.patch @@ -0,0 +1,316 @@ +diff -r 1b69f8a7f836 -r 7168c74ebb2e functional_tests/doc_tests/test_init_plugin/init_plugin.rst +--- a/functional_tests/doc_tests/test_init_plugin/init_plugin.rst Fri Mar 05 15:31:57 2010 -0500 ++++ b/functional_tests/doc_tests/test_init_plugin/init_plugin.rst Wed Jul 07 10:31:01 2010 -0400 +@@ -24,6 +24,7 @@ + + >>> import unittest + >>> class TestConfigurableWidget(unittest.TestCase): ++ ... longMessage = False + ... def setUp(self): + ... self.widget = ConfigurableWidget() + ... def test_can_frobnicate(self): +diff -r 1b69f8a7f836 -r 7168c74ebb2e functional_tests/doc_tests/test_xunit_plugin/test_skips.rst +--- a/functional_tests/doc_tests/test_xunit_plugin/test_skips.rst Fri Mar 05 15:31:57 2010 -0500 ++++ b/functional_tests/doc_tests/test_xunit_plugin/test_skips.rst Wed Jul 07 10:31:01 2010 -0400 +@@ -37,4 +37,4 @@ + FAILED (SKIP=1, errors=1, failures=1) + + >>> open(outfile, 'r').read() # doctest: +ELLIPSIS +-'.........' ++'.........' +diff -r 1b69f8a7f836 -r 7168c74ebb2e functional_tests/test_collector.py +--- a/functional_tests/test_collector.py Fri Mar 05 15:31:57 2010 -0500 ++++ b/functional_tests/test_collector.py Wed Jul 07 10:31:01 2010 -0400 +@@ -13,7 +13,7 @@ + self.result = _TextTestResult( + self.stream, self.descriptions, self.verbosity) + return self.result +- ++ + + class TestNoseTestCollector(unittest.TestCase): + +@@ -27,7 +27,7 @@ + warnings.filterwarnings(action='ignore', + category=RuntimeWarning, + module='nose.plugins.manager') +- ++ + try: + os.chdir(os.path.join(support, 'issue038')) + unittest.TestProgram( +diff -r 1b69f8a7f836 -r 7168c74ebb2e nose/plugins/manager.py +--- a/nose/plugins/manager.py Fri Mar 05 15:31:57 2010 -0500 ++++ b/nose/plugins/manager.py Wed Jul 07 10:31:01 2010 -0400 +@@ -182,7 +182,7 @@ + """Null Plugin manager that has no plugins.""" + interface = IPluginInterface + def __init__(self): +- self.plugins = () ++ self._plugins = self.plugins = () + + def __iter__(self): + return () +diff -r 1b69f8a7f836 -r 7168c74ebb2e nose/plugins/multiprocess.py +--- a/nose/plugins/multiprocess.py Fri Mar 05 15:31:57 2010 -0500 ++++ b/nose/plugins/multiprocess.py Wed Jul 07 10:31:01 2010 -0400 +@@ -459,7 +459,7 @@ + log.debug("Active plugins worker %s: %s", ix, config.plugins._plugins) + loader = loaderClass(config=config) + loader.suiteClass.suiteClass = NoSharedFixtureContextSuite +- ++ + def get(): + case = testQueue.get(timeout=config.multiprocess_timeout) + return case +diff -r 1b69f8a7f836 -r 7168c74ebb2e nose/result.py +--- a/nose/result.py Fri Mar 05 15:31:57 2010 -0500 ++++ b/nose/result.py Wed Jul 07 10:31:01 2010 -0400 +@@ -76,6 +76,13 @@ + test.passed = False + self.printLabel('ERROR') + ++ # override to bypass changes in 2.7 ++ def getDescription(self, test): ++ if self.descriptions: ++ return test.shortDescription() or str(test) ++ else: ++ return str(test) ++ + def printLabel(self, label, err=None): + # Might get patched into a streamless result + stream = getattr(self, 'stream', None) +diff -r 1b69f8a7f836 -r 7168c74ebb2e nose/suite.py +--- a/nose/suite.py Fri Mar 05 15:31:57 2010 -0500 ++++ b/nose/suite.py Wed Jul 07 10:31:01 2010 -0400 +@@ -50,22 +50,30 @@ + """Initialize the suite. tests may be an iterable or a generator + """ + self._set_tests(tests) +- ++ + def __iter__(self): + return iter(self._tests) +- ++ + def __repr__(self): + return "<%s tests=generator (%s)>" % ( + _strclass(self.__class__), id(self)) + + def __hash__(self): + return object.__hash__(self) +- ++ + __str__ = __repr__ + + def addTest(self, test): + self._precache.append(test) + ++ # added to bypass run changes in 2.7's unittest ++ def run(self, result): ++ for test in self._tests: ++ if result.shouldStop: ++ break ++ test(result) ++ return result ++ + def __nonzero__(self): + log.debug("tests in %s?", id(self)) + if self._precache: +@@ -108,7 +116,7 @@ + "Access the tests in this suite. Access is through a " + "generator, so iteration may not be repeatable.") + +- ++ + class ContextSuite(LazySuite): + """A suite with context. + +@@ -118,7 +126,7 @@ + The context may be explicitly passed. If it is not, a context (or + nested set of contexts) will be constructed by examining the tests + in the suite. +- """ ++ """ + failureException = unittest.TestCase.failureException + was_setup = False + was_torndown = False +@@ -133,7 +141,7 @@ + packageSetup = ('setup_package', 'setupPackage', 'setUpPackage') + packageTeardown = ('teardown_package', 'teardownPackage', + 'tearDownPackage') +- ++ + def __init__(self, tests=(), context=None, factory=None, + config=None, resultProxy=None, can_split=True): + log.debug("Context suite for %s (%s) (%s)", tests, context, id(self)) +@@ -159,7 +167,7 @@ + return '%s:%s' % (repr(self), self.error_context) + else: + return repr(self) +- ++ + def __hash__(self): + return object.__hash__(self) + +@@ -171,7 +179,7 @@ + """Hook for replacing error tuple output + """ + return sys.exc_info() +- ++ + def _exc_info(self): + """Bottleneck to fix up IronPython string exceptions + """ +@@ -189,6 +197,9 @@ + """Run tests in suite inside of suite fixtures. + """ + # proxy the result for myself ++ log.debug("suite %s (%s) run called, tests: %s", id(self), self, self._tests) ++ #import pdb ++ #pdb.set_trace() + if self.resultProxy: + result, orig = self.resultProxy(result, self), result + else: +@@ -252,7 +263,7 @@ + if ctx_callback is None: + return fixt + return ctx_callback(context, fixt) +- ++ + def setUp(self): + log.debug("suite %s setUp called, tests: %s", id(self), self._tests) + if not self: +@@ -339,7 +350,7 @@ + self.teardownContext(ancestor) + else: + self.teardownContext(context) +- ++ + def teardownContext(self, context): + log.debug("%s teardown context %s", self, context) + if self.factory: +@@ -413,7 +424,7 @@ + except MixedContextError: + return self.makeSuite(self.mixedSuites(tests), None, **kw) + return self.makeSuite(tests, context, **kw) +- ++ + def ancestry(self, context): + """Return the ancestry of the context (that is, all of the + packages and modules containing the context), in order of +@@ -436,7 +447,7 @@ + raise TypeError("%s has no ancestors?" % context) + while ancestors: + log.debug(" %s ancestors %s", context, ancestors) +- yield resolve_name('.'.join(ancestors)) ++ yield resolve_name('.'.join(ancestors)) + ancestors.pop() + + def findContext(self, tests): +@@ -508,7 +519,7 @@ + continue + if test_ctx is ancestor: + common.append(test) +- continue ++ continue + for test_ancestor in self.ancestry(test_ctx): + if test_ancestor is ancestor: + common.append(test) +@@ -520,7 +531,7 @@ + suite = self.makeSuite(common, ancestor) + tail = remain + return [suite] + self.mixedSuites(tail) +- ++ + def wrapTests(self, tests): + log.debug("wrap %s", tests) + if callable(tests) or isinstance(tests, unittest.TestSuite): +@@ -557,7 +568,7 @@ + """Wraps suite and calls final function after suite has + executed. Used to call final functions in cases (like running in + the standard test runner) where test running is not under nose's +- control. ++ control. + """ + def __init__(self, suite, finalize): + self.suite = suite +@@ -566,6 +577,10 @@ + def __call__(self, *arg, **kw): + return self.run(*arg, **kw) + ++ # 2.7 compat ++ def __iter__(self): ++ return iter(self.suite) ++ + def run(self, *arg, **kw): + try: + return self.suite(*arg, **kw) +diff -r 1b69f8a7f836 -r 7168c74ebb2e unit_tests/test_logcapture_plugin.py +--- a/unit_tests/test_logcapture_plugin.py Fri Mar 05 15:31:57 2010 -0500 ++++ b/unit_tests/test_logcapture_plugin.py Wed Jul 07 10:31:01 2010 -0400 +@@ -1,4 +1,3 @@ +- + import sys + from optparse import OptionParser + from nose.config import Config +@@ -8,6 +7,11 @@ + from logging import StreamHandler + import unittest + ++if sys.version_info >= (2, 7): ++ py27 = True ++else: ++ py27 = False ++ + class TestLogCapturePlugin(object): + + def test_enabled_by_default(self): +@@ -81,25 +85,30 @@ + options, args = parser.parse_args(['--logging-clear-handlers']) + c.configure(options, Config()) + eq_(c.clear, True) +- +- def mktest(): ++ ++ def mktest(): + class TC(unittest.TestCase): + def runTest(self): + pass + test = TC() + return test +- ++ + logging.getLogger().addHandler(StreamHandler(sys.stdout)) + log = logging.getLogger("dummy") + log.addHandler(StreamHandler(sys.stdout)) +- ++ + c.start() + c.beforeTest(mktest()) + c.end() +- +- eq_([str(c.__class__) for c in logging.getLogger().handlers], +- ['nose.plugins.logcapture.MyMemoryHandler']) +- eq_([str(c.__class__) for c in logging.getLogger("dummy").handlers], ++ ++ ++ if py27: ++ expect = [""] ++ else: ++ expect = ['nose.plugins.logcapture.MyMemoryHandler'] ++ eq_([str(c.__class__) for c in logging.getLogger().handlers], ++ expect) ++ eq_([str(c.__class__) for c in logging.getLogger("dummy").handlers], + []) + + def test_custom_formatter(self): +@@ -112,7 +121,7 @@ + records = c.formatLogRecords() + eq_(1, len(records)) + eq_("++Hello++", records[0]) +- ++ + def test_logging_filter(self): + env = {'NOSE_LOGFILTER': 'foo,bar'} + c = LogCapture() diff --git a/python-nose.spec b/python-nose.spec index 527c9b3..1018124 100644 --- a/python-nose.spec +++ b/python-nose.spec @@ -5,9 +5,12 @@ %global upstream_name nose +# Enable building without docs to avoid a circular dependency between this and python-sphinx +%global with_docs 0 + Name: python-nose Version: 0.11.3 -Release: 4%{?dist} +Release: 5%{?dist} Summary: A discovery-based unittest extension for Python Group: Development/Languages @@ -16,6 +19,12 @@ URL: http://somethingaboutorange.com/mrl/projects/nose/ Source0: http://somethingaboutorange.com/mrl/projects/nose/nose-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +# 2.7 compatibility fixes +# Extracted from upstream scm using: +# hg diff -r 708 -r 711 +# and eliminating the hunk relating to test.sh +Patch0: python-nose-r708-through-r111-py27-fixes.patch + BuildArch: noarch BuildRequires: python2-devel %if 0%{?fedora} && 0%{?fedora} < 13 @@ -24,6 +33,7 @@ BuildRequires: python-setuptools-devel BuildRequires: python-setuptools %endif BuildRequires: dos2unix +BuildRequires: python-coverage Requires: python-setuptools %description @@ -42,6 +52,7 @@ plugins. Plugins included with nose provide support for doctest, code coverage and profiling, flexible attribute-based test selection, output capture and more. +%if 0%{?with_docs} %package docs Summary: Nose Documentation Group: Documentation @@ -49,10 +60,11 @@ BuildRequires: python-sphinx %description docs Documentation for Nose - +%endif # with_docs %prep %setup -q -n %{upstream_name}-%{version} +%patch0 -p1 dos2unix examples/attrib_plugin.py @@ -65,13 +77,15 @@ rm -rf %{buildroot} %{__python} setup.py install --skip-build --root %{buildroot} \ --install-data=%{_datadir} +%if 0%{?with_docs} pushd doc make html -rm -rf .build/html/.buildinfo .build/html/_sources +]rm -rf .build/html/.buildinfo .build/html/_sources mv .build/html .. rm -rf .build popd cp -a doc reST +%endif # with_docs %check @@ -84,17 +98,26 @@ rm -rf %{buildroot} %files %defattr(-,root,root,-) -%doc AUTHORS CHANGELOG html lgpl.txt NEWS README.txt +%doc AUTHORS CHANGELOG lgpl.txt NEWS README.txt %{_bindir}/nosetests %{_bindir}/nosetests-%{python_version} %{_mandir}/man1/nosetests.1.gz %{python_sitelib}/nose* +%if 0%{?with_docs} %files docs %defattr(-,root,root,-) %doc html reST examples +%endif # with_docs %changelog +* Wed Jul 21 2010 David Malcolm - 0.11.3-5 +- add support for building without docs, to avoid a circular build-time +dependency between this and python-sphinx; disable docs subpackage for now +- add (apparently) missing BR on python-coverage (appears to be needed +for %%check) +- cherrypick upstream compatibility fixes for 2.7 + * Wed Jul 21 2010 David Malcolm - 0.11.3-4 - Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild