diff --git a/.gitignore b/.gitignore index 93a31a9..2cb3a71 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1 @@ -nose-0.11.3.tar.gz -nose-0.11.4.tar.gz -/nose-1.0.0.tar.gz -/nose-1.1.1.tar.gz -/nose-1.1.2.tar.gz -/nose-1.2.0.tar.gz -/nose-1.2.1.tar.gz -/nose-1.3.0.tar.gz -/nose-1.3.1.tar.gz -/nose-1.3.2.tar.gz -/nose-1.3.4.tar.gz -/nose-1.3.6.tar.gz -/nose-1.3.7.tar.gz +SOURCES/nose-1.3.7.tar.gz diff --git a/.python-nose.metadata b/.python-nose.metadata new file mode 100644 index 0000000..fe4012e --- /dev/null +++ b/.python-nose.metadata @@ -0,0 +1 @@ +97f2a04c9d43b29ddf4794a1a1d1ba803f1074c6 SOURCES/nose-1.3.7.tar.gz diff --git a/SOURCES/python-nose-2to3.patch b/SOURCES/python-nose-2to3.patch new file mode 100644 index 0000000..5f9f9a5 --- /dev/null +++ b/SOURCES/python-nose-2to3.patch @@ -0,0 +1,4538 @@ +From e0e9dc173237bc56815e30e0c7d3de0d79b46f82 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Wed, 18 Oct 2023 13:01:21 +0200 +Subject: [PATCH] Run 2to3 on the code base and docs + + $ 2to3 --write --nobackups --no-diffs . + $ 2to3 --write --nobackups --no-diffs -d $(find -name '*.rst') + + $ rpm -qf /usr/bin/2to3 + python3-devel-3.11.6-1.fc37.x86_64 +--- + distribute_setup.py | 2 +- + doc/conf.py | 8 +- + doc/docstring.py | 2 +- + examples/attrib_plugin.py | 12 +-- + .../test_init_plugin/init_plugin.rst | 3 +- + .../test_issue097/plugintest_environment.rst | 13 +-- + .../test_issue107/plugin_exceptions.rst | 5 +- + .../doc_tests/test_issue119/empty_plugin.rst | 15 +-- + .../doc_tests/test_issue119/test_zeronine.py | 2 +- + .../test_issue145/imported_tests.rst | 3 +- + .../support/package1/__init__.py | 2 +- + .../support/package2c/__init__.py | 2 +- + .../support/package2f/__init__.py | 2 +- + .../support/test_can_split.py | 4 +- + .../support/test_not_shared.py | 4 +- + .../test_multiprocess/support/test_shared.py | 4 +- + .../restricted_plugin_options.rst | 3 +- + .../test_selector_plugin/selector_plugin.rst | 3 +- + functional_tests/support/coverage/blah.py | 4 +- + functional_tests/support/coverage2/blah.py | 4 +- + functional_tests/support/coverage2/moo.py | 2 +- + functional_tests/support/fdp/test_fdp.py | 2 +- + functional_tests/support/gen/test.py | 2 +- + functional_tests/support/ipt/test1/ipthelp.py | 4 +- + functional_tests/support/ipt/test1/tests.py | 4 +- + functional_tests/support/ipt/test2/ipthelp.py | 4 +- + functional_tests/support/ipt/test2/tests.py | 4 +- + functional_tests/support/issue072/test.py | 2 +- + functional_tests/support/issue134/test.py | 2 +- + functional_tests/support/issue649/test.py | 2 +- + functional_tests/support/issue680/test.py | 2 +- + functional_tests/support/issue720/test.py | 2 +- + .../support/package2/test_pak/__init__.py | 2 +- + .../support/package2/test_pak/test_mod.py | 8 +- + .../support/xunit/test_xunit_as_suite.py | 2 +- + functional_tests/test_attribute_plugin.py | 6 +- + functional_tests/test_buggy_generators.py | 4 +- + functional_tests/test_collector.py | 2 +- + functional_tests/test_commands.py | 6 +- + functional_tests/test_coverage_plugin.py | 2 +- + functional_tests/test_doctest_plugin.py | 4 +- + functional_tests/test_failure.py | 10 +- + functional_tests/test_failuredetail_plugin.py | 18 ++-- + functional_tests/test_generator_fixtures.py | 8 +- + functional_tests/test_id_plugin.py | 36 +++---- + functional_tests/test_importer.py | 4 +- + functional_tests/test_isolate_plugin.py | 4 +- + functional_tests/test_issue_072.py | 20 ++-- + functional_tests/test_issue_082.py | 8 +- + functional_tests/test_issue_649.py | 2 +- + .../test_load_tests_from_test_case.py | 8 +- + functional_tests/test_loader.py | 44 ++++----- + .../support/fake_nosetest.py | 2 +- + .../test_keyboardinterrupt.py | 20 ++-- + .../test_multiprocessing/test_nameerror.py | 2 +- + functional_tests/test_namespace_pkg.py | 2 +- + functional_tests/test_plugin_api.py | 6 +- + functional_tests/test_plugins.py | 4 +- + functional_tests/test_plugintest.py | 2 +- + functional_tests/test_program.py | 20 ++-- + functional_tests/test_result.py | 6 +- + functional_tests/test_string_exception.py | 10 +- + functional_tests/test_success.py | 4 +- + functional_tests/test_suite.py | 2 +- + functional_tests/test_xunit.py | 24 ++--- + nose/case.py | 2 +- + nose/commands.py | 2 +- + nose/config.py | 36 +++---- + nose/core.py | 24 ++--- + nose/ext/dtcompat.py | 80 +++++++-------- + nose/failure.py | 4 +- + nose/inspector.py | 6 +- + nose/loader.py | 11 +-- + nose/plugins/attrib.py | 4 +- + nose/plugins/base.py | 2 +- + nose/plugins/capture.py | 18 ++-- + nose/plugins/cover.py | 12 +-- + nose/plugins/doctests.py | 29 +++--- + nose/plugins/errorclass.py | 7 +- + nose/plugins/isolate.py | 2 +- + nose/plugins/logcapture.py | 10 +- + nose/plugins/manager.py | 8 +- + nose/plugins/multiprocess.py | 16 +-- + nose/plugins/plugintest.py | 8 +- + nose/plugins/testid.py | 4 +- + nose/plugins/xunit.py | 28 +++--- + nose/pyversion.py | 18 ++-- + nose/result.py | 10 +- + nose/selector.py | 10 +- + nose/suite.py | 8 +- + nose/tools/nontrivial.py | 2 +- + nose/twistedtools.py | 4 +- + nose/util.py | 16 +-- + patch.py | 4 +- + unit_tests/mock.py | 16 +-- + unit_tests/support/issue135/tests.py | 2 +- + unit_tests/support/script.py | 2 +- + unit_tests/test_bug105.py | 8 +- + unit_tests/test_capture_plugin.py | 14 +-- + unit_tests/test_cases.py | 9 +- + unit_tests/test_config_defaults.rst | 11 ++- + unit_tests/test_core.py | 10 +- + unit_tests/test_deprecated_plugin.py | 4 +- + unit_tests/test_doctest_munging.rst | 25 ++--- + unit_tests/test_id_plugin.py | 2 +- + unit_tests/test_inspector.py | 12 +-- + unit_tests/test_issue135.py | 2 +- + unit_tests/test_issue155.rst | 9 +- + unit_tests/test_issue_006.py | 10 +- + unit_tests/test_issue_227.py | 2 +- + unit_tests/test_issue_230.py | 2 +- + unit_tests/test_loader.py | 97 +++++++++---------- + unit_tests/test_logcapture_plugin.py | 10 +- + unit_tests/test_ls_tree.rst | 5 +- + unit_tests/test_multiprocess_runner.py | 12 +-- + unit_tests/test_pdb_plugin.py | 2 +- + unit_tests/test_plugin_manager.py | 2 +- + unit_tests/test_plugins.py | 16 +-- + unit_tests/test_result_proxy.py | 8 +- + unit_tests/test_selector.py | 4 +- + unit_tests/test_skip_plugin.py | 6 +- + unit_tests/test_suite.py | 12 +-- + unit_tests/test_tools.py | 16 +-- + unit_tests/test_twisted.py | 2 +- + unit_tests/test_utils.py | 11 +-- + unit_tests/test_xunit.py | 16 +-- + 126 files changed, 587 insertions(+), 588 deletions(-) + +diff --git a/distribute_setup.py b/distribute_setup.py +index a447f7e..8d13a7e 100644 +--- a/distribute_setup.py ++++ b/distribute_setup.py +@@ -190,7 +190,7 @@ def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + try: + from urllib.request import urlopen + except ImportError: +- from urllib2 import urlopen ++ from urllib.request import urlopen + tgz_name = "distribute-%s.tar.gz" % version + url = download_base + tgz_name + saveto = os.path.join(to_dir, tgz_name) +diff --git a/doc/conf.py b/doc/conf.py +index 34ea147..f2c2e4f 100644 +--- a/doc/conf.py ++++ b/doc/conf.py +@@ -49,8 +49,8 @@ source_suffix = '.rst' + master_doc = 'index' + + # General information about the project. +-project = u'nose' +-copyright = u'2009, Jason Pellerin' ++project = 'nose' ++copyright = '2009, Jason Pellerin' + + # The version info for the project you're documenting, acts as replacement for + # |version| and |release|, also used in various other places throughout the +@@ -213,8 +213,8 @@ html_theme = 'default' + # Grouping the document tree into LaTeX files. List of tuples + # (source start file, target name, title, author, document class [howto/manual]). + latex_documents = [ +- ('index', 'nose.tex', ur'nose Documentation', +- ur'Jason Pellerin', 'manual'), ++ ('index', 'nose.tex', r'nose Documentation', ++ r'Jason Pellerin', 'manual'), + ] + + # The name of an image file (relative to this directory) to place at the top of +diff --git a/doc/docstring.py b/doc/docstring.py +index 5652bd2..af9ef15 100644 +--- a/doc/docstring.py ++++ b/doc/docstring.py +@@ -9,7 +9,7 @@ def docstring_directive(dirname, arguments, options, content, lineno, + obj = resolve_name(obj_name) + rst = ViewList() + rst.append(obj.__doc__, '') +- print "CALLED", obj_name, obj, rst ++ print("CALLED", obj_name, obj, rst) + node = nodes.section() + surrounding_title_styles = state.memo.title_styles + surrounding_section_level = state.memo.section_level +diff --git a/examples/attrib_plugin.py b/examples/attrib_plugin.py +index c1f8458..7c94111 100644 +--- a/examples/attrib_plugin.py ++++ b/examples/attrib_plugin.py +@@ -41,7 +41,7 @@ def attr(**kwargs): + # test function with single attribute + @attr(priority = 1) + def test_dummy(): +- print "dummy" ++ print("dummy") + + # test function with multiple attributes + @attr(status = "stable", # simple string attribute +@@ -51,11 +51,11 @@ def test_dummy(): + tags = ["http", "pop", "imap"]) # will be run if any of the list items + # matches + def test_foobar(): +- print "foobar" ++ print("foobar") + + # another way of adding attributes... + def test_fluffy(): +- print "fluffy" ++ print("fluffy") + test_fluffy.status = "unstable" + test_fluffy.slow = True + test_fluffy.priority = 2 +@@ -64,7 +64,7 @@ test_fluffy.priority = 2 + class TestSomething: + @attr(status = "stable", priority = 2) + def test_xyz(self): +- print "xyz" ++ print("xyz") + + # class methods "inherit" attributes from the class but can override them + class TestOverride: +@@ -74,9 +74,9 @@ class TestOverride: + @attr(value = "method") + def test_override(self): + # run with "nosetests -a value=method" +- print "override" ++ print("override") + + def test_inherit(self): + # run with "nosetests -a value=class" +- print "inherit" ++ print("inherit") + +diff --git a/functional_tests/doc_tests/test_init_plugin/init_plugin.rst b/functional_tests/doc_tests/test_init_plugin/init_plugin.rst +index d89bfa4..bdc3fd2 100644 +--- a/functional_tests/doc_tests/test_init_plugin/init_plugin.rst ++++ b/functional_tests/doc_tests/test_init_plugin/init_plugin.rst +@@ -130,7 +130,7 @@ specify a configuration file on the command line: + ... def begin(self): + ... ConfigurableWidget.cfg = self.cfg + ... def load_config(self, path): +- ... from ConfigParser import ConfigParser ++ ... from configparser import ConfigParser + ... p = ConfigParser() + ... p.read([path]) + ... self.cfg = dict(p.items('DEFAULT')) +@@ -164,3 +164,4 @@ resetting the widget system to an unconfigured state. + + .. _Pylons: http://pylonshq.com/ + .. _Django: http://www.djangoproject.com/ ++ +diff --git a/functional_tests/doc_tests/test_issue097/plugintest_environment.rst b/functional_tests/doc_tests/test_issue097/plugintest_environment.rst +index 99b37cf..5cb9f4f 100644 +--- a/functional_tests/doc_tests/test_issue097/plugintest_environment.rst ++++ b/functional_tests/doc_tests/test_issue097/plugintest_environment.rst +@@ -20,16 +20,16 @@ environment it's given by nose. + + >>> class PrintEnvPlugin(Plugin): + ... name = "print-env" +- ... ++ ... + ... # no command line arg needed to activate plugin + ... enabled = True + ... def configure(self, options, conf): + ... if not self.can_configure: + ... return + ... self.conf = conf +- ... ++ ... + ... def options(self, parser, env={}): +- ... print "env:", env ++ ... print("env:", env) + + To test the argv, we use a config class that prints the argv it's + given by nose. We need to monkeypatch nose.config.Config, so that we +@@ -37,9 +37,9 @@ can test the cases where that is used as the default. + + >>> old_config = nose.config.Config + >>> class PrintArgvConfig(old_config): +- ... ++ ... + ... def configure(self, argv=None, doc=None): +- ... print "argv:", argv ++ ... print("argv:", argv) + ... old_config.configure(self, argv, doc) + >>> nose.config.Config = PrintArgvConfig + +@@ -52,7 +52,7 @@ subclassing. + ... FailureDetail(), + ... Capture(), + ... ] +- ... ++ ... + ... def makeSuite(self): + ... return unittest.TestSuite(tests=[]) + +@@ -158,3 +158,4 @@ Clean up. + >>> os.environ = old_environ + >>> sys.argv = old_argv + >>> nose.config.Config = old_config ++ +diff --git a/functional_tests/doc_tests/test_issue107/plugin_exceptions.rst b/functional_tests/doc_tests/test_issue107/plugin_exceptions.rst +index 2c595f0..2a2e775 100644 +--- a/functional_tests/doc_tests/test_issue107/plugin_exceptions.rst ++++ b/functional_tests/doc_tests/test_issue107/plugin_exceptions.rst +@@ -19,9 +19,9 @@ AttributeError in beforeTest and afterTest. + + >>> class EnabledPlugin(Plugin): + ... """Plugin that takes no command-line arguments""" +- ... ++ ... + ... enabled = True +- ... ++ ... + ... def configure(self, options, conf): + ... pass + ... def options(self, parser, env={}): +@@ -147,3 +147,4 @@ following test would crash nose: + Ran 1 test in ...s + + FAILED (errors=1) ++ +diff --git a/functional_tests/doc_tests/test_issue119/empty_plugin.rst b/functional_tests/doc_tests/test_issue119/empty_plugin.rst +index 6194c19..8a82e15 100644 +--- a/functional_tests/doc_tests/test_issue119/empty_plugin.rst ++++ b/functional_tests/doc_tests/test_issue119/empty_plugin.rst +@@ -6,14 +6,14 @@ by nose.plugins.base. They do not have to derive from + nose.plugins.Plugin. + + >>> class NullPlugin(object): +- ... ++ ... + ... enabled = True + ... name = "null" + ... score = 100 +- ... ++ ... + ... def options(self, parser, env): + ... pass +- ... ++ ... + ... def configure(self, options, conf): + ... pass + >>> import unittest +@@ -31,19 +31,19 @@ name. + >>> import os + >>> from nose.plugins import Plugin + >>> class DerivedNullPlugin(Plugin): +- ... ++ ... + ... name = "derived-null" + + Enabled plugin that's otherwise empty + + >>> class EnabledDerivedNullPlugin(Plugin): +- ... ++ ... + ... enabled = True + ... name = "enabled-derived-null" +- ... ++ ... + ... def options(self, parser, env=os.environ): + ... pass +- ... ++ ... + ... def configure(self, options, conf): + ... if not self.can_configure: + ... return +@@ -55,3 +55,4 @@ Enabled plugin that's otherwise empty + Ran 0 tests in ...s + + OK ++ +diff --git a/functional_tests/doc_tests/test_issue119/test_zeronine.py b/functional_tests/doc_tests/test_issue119/test_zeronine.py +index 6a4f450..5c09c13 100644 +--- a/functional_tests/doc_tests/test_issue119/test_zeronine.py ++++ b/functional_tests/doc_tests/test_issue119/test_zeronine.py +@@ -18,7 +18,7 @@ class TestEmptyPlugin(PluginTester, unittest.TestCase): + suitepath = os.path.join(here, 'empty_plugin.rst') + + def test_empty_zero_nine_does_not_crash(self): +- print self.output ++ print(self.output) + assert "'EmptyPlugin' object has no attribute 'loadTestsFromPath'" \ + not in self.output + +diff --git a/functional_tests/doc_tests/test_issue145/imported_tests.rst b/functional_tests/doc_tests/test_issue145/imported_tests.rst +index caad752..87113e3 100644 +--- a/functional_tests/doc_tests/test_issue145/imported_tests.rst ++++ b/functional_tests/doc_tests/test_issue145/imported_tests.rst +@@ -11,7 +11,7 @@ For example, consider this collection of packages: + >>> import os + >>> support = os.path.join(os.path.dirname(__file__), 'support') + >>> from nose.util import ls_tree +- >>> print ls_tree(support) # doctest: +REPORT_NDIFF ++ >>> print(ls_tree(support)) # doctest: +REPORT_NDIFF + |-- package1 + | |-- __init__.py + | `-- test_module.py +@@ -115,3 +115,4 @@ command-line. + Ran 1 test in ...s + + OK ++ +diff --git a/functional_tests/doc_tests/test_issue145/support/package1/__init__.py b/functional_tests/doc_tests/test_issue145/support/package1/__init__.py +index c715fdb..18aef31 100644 +--- a/functional_tests/doc_tests/test_issue145/support/package1/__init__.py ++++ b/functional_tests/doc_tests/test_issue145/support/package1/__init__.py +@@ -1,2 +1,2 @@ + def setup(): +- print 'package1 setup' ++ print('package1 setup') +diff --git a/functional_tests/doc_tests/test_issue145/support/package2c/__init__.py b/functional_tests/doc_tests/test_issue145/support/package2c/__init__.py +index 106401f..0162765 100644 +--- a/functional_tests/doc_tests/test_issue145/support/package2c/__init__.py ++++ b/functional_tests/doc_tests/test_issue145/support/package2c/__init__.py +@@ -1,2 +1,2 @@ + def setup(): +- print 'package2c setup' ++ print('package2c setup') +diff --git a/functional_tests/doc_tests/test_issue145/support/package2f/__init__.py b/functional_tests/doc_tests/test_issue145/support/package2f/__init__.py +index fc203eb..d8886da 100644 +--- a/functional_tests/doc_tests/test_issue145/support/package2f/__init__.py ++++ b/functional_tests/doc_tests/test_issue145/support/package2f/__init__.py +@@ -1,2 +1,2 @@ + def setup(): +- print 'package2f setup' ++ print('package2f setup') +diff --git a/functional_tests/doc_tests/test_multiprocess/support/test_can_split.py b/functional_tests/doc_tests/test_multiprocess/support/test_can_split.py +index a7ae6e7..08bb9e3 100644 +--- a/functional_tests/doc_tests/test_multiprocess/support/test_can_split.py ++++ b/functional_tests/doc_tests/test_multiprocess/support/test_can_split.py +@@ -4,12 +4,12 @@ called = [] + _multiprocess_can_split_ = 1 + + def setup(): +- print >> sys.stderr, "setup called" ++ print("setup called", file=sys.stderr) + called.append('setup') + + + def teardown(): +- print >> sys.stderr, "teardown called" ++ print("teardown called", file=sys.stderr) + called.append('teardown') + + +diff --git a/functional_tests/doc_tests/test_multiprocess/support/test_not_shared.py b/functional_tests/doc_tests/test_multiprocess/support/test_not_shared.py +index 8542109..03016dd 100644 +--- a/functional_tests/doc_tests/test_multiprocess/support/test_not_shared.py ++++ b/functional_tests/doc_tests/test_multiprocess/support/test_not_shared.py +@@ -4,12 +4,12 @@ called = [] + _multiprocess_ = 1 + + def setup(): +- print >> sys.stderr, "setup called" ++ print("setup called", file=sys.stderr) + called.append('setup') + + + def teardown(): +- print >> sys.stderr, "teardown called" ++ print("teardown called", file=sys.stderr) + called.append('teardown') + + +diff --git a/functional_tests/doc_tests/test_multiprocess/support/test_shared.py b/functional_tests/doc_tests/test_multiprocess/support/test_shared.py +index d798aac..b847751 100644 +--- a/functional_tests/doc_tests/test_multiprocess/support/test_shared.py ++++ b/functional_tests/doc_tests/test_multiprocess/support/test_shared.py +@@ -28,12 +28,12 @@ def logged(): + + + def setup(): +- print >> sys.stderr, "setup called" ++ print("setup called", file=sys.stderr) + _log('setup') + + + def teardown(): +- print >> sys.stderr, "teardown called" ++ print("teardown called", file=sys.stderr) + _clear() + + +diff --git a/functional_tests/doc_tests/test_restricted_plugin_options/restricted_plugin_options.rst b/functional_tests/doc_tests/test_restricted_plugin_options/restricted_plugin_options.rst +index 6a08eaf..53609cb 100644 +--- a/functional_tests/doc_tests/test_restricted_plugin_options/restricted_plugin_options.rst ++++ b/functional_tests/doc_tests/test_restricted_plugin_options/restricted_plugin_options.rst +@@ -18,7 +18,7 @@ method. + >>> from nose.plugins.manager import RestrictedPluginManager + >>> class StartPlugin(Plugin): + ... def startTest(self, test): +- ... print "started %s" % test ++ ... print("started %s" % test) + + .. Note :: + +@@ -87,3 +87,4 @@ error is raised. + Traceback (most recent call last): + ... + SystemExit: 2 ++ +diff --git a/functional_tests/doc_tests/test_selector_plugin/selector_plugin.rst b/functional_tests/doc_tests/test_selector_plugin/selector_plugin.rst +index 5463cf1..b7b7acb 100644 +--- a/functional_tests/doc_tests/test_selector_plugin/selector_plugin.rst ++++ b/functional_tests/doc_tests/test_selector_plugin/selector_plugin.rst +@@ -19,7 +19,7 @@ In this example, the project to be tested consists of a module and + package and associated tests, laid out like this:: + + >>> from nose.util import ls_tree +- >>> print ls_tree(support) ++ >>> print(ls_tree(support)) + |-- mymodule.py + |-- mypackage + | |-- __init__.py +@@ -117,3 +117,4 @@ project's tests will be collected. + Ran 4 tests in ...s + + OK ++ +diff --git a/functional_tests/support/coverage/blah.py b/functional_tests/support/coverage/blah.py +index ef6657c..721a2b1 100644 +--- a/functional_tests/support/coverage/blah.py ++++ b/functional_tests/support/coverage/blah.py +@@ -1,6 +1,6 @@ + def dostuff(): +- print 'hi' ++ print('hi') + + + def notcov(): +- print 'not covered' ++ print('not covered') +diff --git a/functional_tests/support/coverage2/blah.py b/functional_tests/support/coverage2/blah.py +index ef6657c..721a2b1 100644 +--- a/functional_tests/support/coverage2/blah.py ++++ b/functional_tests/support/coverage2/blah.py +@@ -1,6 +1,6 @@ + def dostuff(): +- print 'hi' ++ print('hi') + + + def notcov(): +- print 'not covered' ++ print('not covered') +diff --git a/functional_tests/support/coverage2/moo.py b/functional_tests/support/coverage2/moo.py +index 7ad09bf..2e3d4ce 100644 +--- a/functional_tests/support/coverage2/moo.py ++++ b/functional_tests/support/coverage2/moo.py +@@ -1,2 +1,2 @@ + def moo(): +- print 'covered' ++ print('covered') +diff --git a/functional_tests/support/fdp/test_fdp.py b/functional_tests/support/fdp/test_fdp.py +index bcaab0d..61d7778 100644 +--- a/functional_tests/support/fdp/test_fdp.py ++++ b/functional_tests/support/fdp/test_fdp.py +@@ -2,7 +2,7 @@ def test_err(): + raise TypeError("I can't type") + + def test_fail(): +- print "Hello" ++ print("Hello") + a = 2 + assert a == 4, "a is not 4" + +diff --git a/functional_tests/support/gen/test.py b/functional_tests/support/gen/test.py +index 13a0c3e..5d6dc62 100644 +--- a/functional_tests/support/gen/test.py ++++ b/functional_tests/support/gen/test.py +@@ -7,6 +7,6 @@ def test1(): + def func(_l, _n): + eq_(len(_l), _n) + l = [] +- for i in xrange(5): ++ for i in range(5): + yield func, l, i + l.append(None) +diff --git a/functional_tests/support/ipt/test1/ipthelp.py b/functional_tests/support/ipt/test1/ipthelp.py +index fdbe2e4..e7020cf 100644 +--- a/functional_tests/support/ipt/test1/ipthelp.py ++++ b/functional_tests/support/ipt/test1/ipthelp.py +@@ -1,4 +1,4 @@ +-print "1help imported" ++print("1help imported") + def help(): +- print "1help called" ++ print("1help called") + pass +diff --git a/functional_tests/support/ipt/test1/tests.py b/functional_tests/support/ipt/test1/tests.py +index a9595f7..fe9592e 100644 +--- a/functional_tests/support/ipt/test1/tests.py ++++ b/functional_tests/support/ipt/test1/tests.py +@@ -1,7 +1,7 @@ + import sys +-print 'ipthelp', sys.modules.get('ipthelp') ++print('ipthelp', sys.modules.get('ipthelp')) + import ipthelp +-print ipthelp ++print(ipthelp) + + def test1(): + ipthelp.help() +diff --git a/functional_tests/support/ipt/test2/ipthelp.py b/functional_tests/support/ipt/test2/ipthelp.py +index cafd917..3731981 100644 +--- a/functional_tests/support/ipt/test2/ipthelp.py ++++ b/functional_tests/support/ipt/test2/ipthelp.py +@@ -1,5 +1,5 @@ +-print "2help imported" ++print("2help imported") + + def help(a): +- print "2 help %s" % 1 ++ print("2 help %s" % 1) + pass +diff --git a/functional_tests/support/ipt/test2/tests.py b/functional_tests/support/ipt/test2/tests.py +index 1c95896..875a0c7 100644 +--- a/functional_tests/support/ipt/test2/tests.py ++++ b/functional_tests/support/ipt/test2/tests.py +@@ -1,8 +1,8 @@ + import sys + +-print 'ipthelp', sys.modules.get('ipthelp') ++print('ipthelp', sys.modules.get('ipthelp')) + import ipthelp +-print ipthelp ++print(ipthelp) + + def test2(): + ipthelp.help(1) +diff --git a/functional_tests/support/issue072/test.py b/functional_tests/support/issue072/test.py +index 2aab0bd..d9f49e2 100644 +--- a/functional_tests/support/issue072/test.py ++++ b/functional_tests/support/issue072/test.py +@@ -1,4 +1,4 @@ + def test(): +- print "something" ++ print("something") + a = 4 + assert a == 2 +diff --git a/functional_tests/support/issue134/test.py b/functional_tests/support/issue134/test.py +index 78e1e22..f2da19d 100644 +--- a/functional_tests/support/issue134/test.py ++++ b/functional_tests/support/issue134/test.py +@@ -1,3 +1,3 @@ + def test(): +- print "something" ++ print("something") + raise IOError(42, "test") +diff --git a/functional_tests/support/issue649/test.py b/functional_tests/support/issue649/test.py +index ebc6f91..51b07c7 100644 +--- a/functional_tests/support/issue649/test.py ++++ b/functional_tests/support/issue649/test.py +@@ -5,5 +5,5 @@ import unittest + class TestUnicodeInAssertion(unittest.TestCase): + + def test_unicodeInAssertion(self): +- print "Wurst!" ++ print("Wurst!") + raise ValueError("Käse!") +diff --git a/functional_tests/support/issue680/test.py b/functional_tests/support/issue680/test.py +index d0d43b4..def96da 100644 +--- a/functional_tests/support/issue680/test.py ++++ b/functional_tests/support/issue680/test.py +@@ -1,3 +1,3 @@ + # coding: utf-8 + def test_foo(): +- print(u"abc€") ++ print("abc€") +diff --git a/functional_tests/support/issue720/test.py b/functional_tests/support/issue720/test.py +index 0a194fd..4a0df53 100644 +--- a/functional_tests/support/issue720/test.py ++++ b/functional_tests/support/issue720/test.py +@@ -2,5 +2,5 @@ + import unittest + class Test(unittest.TestCase): + def test(self): +- print u"Unicöde" ++ print("Unicöde") + assert 1 == 2 +diff --git a/functional_tests/support/package2/test_pak/__init__.py b/functional_tests/support/package2/test_pak/__init__.py +index b65d6c0..9cc0374 100644 +--- a/functional_tests/support/package2/test_pak/__init__.py ++++ b/functional_tests/support/package2/test_pak/__init__.py +@@ -1,4 +1,4 @@ +-print "*** test_pak imported" ++print("*** test_pak imported") + state = [] + + def setup(): +diff --git a/functional_tests/support/package2/test_pak/test_mod.py b/functional_tests/support/package2/test_pak/test_mod.py +index 09dc9e5..cd46c97 100644 +--- a/functional_tests/support/package2/test_pak/test_mod.py ++++ b/functional_tests/support/package2/test_pak/test_mod.py +@@ -1,14 +1,14 @@ +-print "test_mod imported!" ++print("test_mod imported!") + + import maths + from test_pak import state + + def setup(): +- print "MOD setup called", state, id(state) ++ print("MOD setup called", state, id(state)) + state.append('test_pak.test_mod.setup') + + def test_add(): +- print "MOD.test_add called", state, id(state) ++ print("MOD.test_add called", state, id(state)) + state.append('test_pak.test_mod.test_add') + assert maths.add(1, 2) == 3 + +@@ -16,5 +16,5 @@ def test_minus(): + state.append('test_pak.test_mod.test_minus') + + def teardown(): +- print "MOD teardown called", state, id(state) ++ print("MOD teardown called", state, id(state)) + state.append('test_pak.test_mod.teardown') +diff --git a/functional_tests/support/xunit/test_xunit_as_suite.py b/functional_tests/support/xunit/test_xunit_as_suite.py +index ec256b5..9109907 100644 +--- a/functional_tests/support/xunit/test_xunit_as_suite.py ++++ b/functional_tests/support/xunit/test_xunit_as_suite.py +@@ -15,7 +15,7 @@ class TestForXunit(unittest.TestCase): + raise TypeError("oops, wrong type") + + def test_non_ascii_error(self): +- raise Exception(u"日本") ++ raise Exception("日本") + + def test_output(self): + sys.stdout.write("test-generated output\n") +diff --git a/functional_tests/test_attribute_plugin.py b/functional_tests/test_attribute_plugin.py +index df2cfd3..406ace8 100644 +--- a/functional_tests/test_attribute_plugin.py ++++ b/functional_tests/test_attribute_plugin.py +@@ -17,9 +17,9 @@ class AttributePluginTester(PluginTester, unittest.TestCase): + activate = '-v' + + def runTest(self): +- print '*' * 70 +- print str(self.output) +- print '*' * 70 ++ print('*' * 70) ++ print(str(self.output)) ++ print('*' * 70) + self.verify() + + def verify(self): +diff --git a/functional_tests/test_buggy_generators.py b/functional_tests/test_buggy_generators.py +index 9e6e168..4ce70af 100644 +--- a/functional_tests/test_buggy_generators.py ++++ b/functional_tests/test_buggy_generators.py +@@ -1,6 +1,6 @@ + import os + import unittest +-from cStringIO import StringIO ++from io import StringIO + from nose.core import TestProgram + from nose.config import Config + from nose.result import _TextTestResult +@@ -27,7 +27,7 @@ class TestBuggyGenerators(unittest.TestCase): + config=Config(), + exit=False) + res = runner.result +- print stream.getvalue() ++ print(stream.getvalue()) + self.assertEqual(res.testsRun, 12, + "Expected to run 12 tests, ran %s" % res.testsRun) + assert not res.wasSuccessful() +diff --git a/functional_tests/test_collector.py b/functional_tests/test_collector.py +index c3b9dca..5739eaf 100644 +--- a/functional_tests/test_collector.py ++++ b/functional_tests/test_collector.py +@@ -2,7 +2,7 @@ import os + import sys + import unittest + import warnings +-from cStringIO import StringIO ++from io import StringIO + from nose.result import _TextTestResult + here = os.path.dirname(__file__) + support = os.path.join(here, 'support') +diff --git a/functional_tests/test_commands.py b/functional_tests/test_commands.py +index 682af04..9323e26 100644 +--- a/functional_tests/test_commands.py ++++ b/functional_tests/test_commands.py +@@ -3,7 +3,7 @@ import sys + import unittest + from nose.plugins.skip import SkipTest + from nose import commands +-from StringIO import StringIO ++from io import StringIO + + support = os.path.join( + os.path.dirname(__file__), 'support', 'issue191') +@@ -32,12 +32,12 @@ class TestCommands(unittest.TestCase): + 'package_dir': {'issue191': support}})) + cmd.finalize_options() + ## FIXME why doesn't Config see the chdir above? +- print cmd._nosetests__config.workingDir ++ print(cmd._nosetests__config.workingDir) + cmd._nosetests__config.workingDir = support + cmd._nosetests__config.stream = buf + try: + cmd.run() +- except SystemExit, e: ++ except SystemExit as e: + self.assertFalse(e.args[0], buf.getvalue()) + else: + self.fail("cmd.run() did not exit") +diff --git a/functional_tests/test_coverage_plugin.py b/functional_tests/test_coverage_plugin.py +index eb465e8..dbe7268 100644 +--- a/functional_tests/test_coverage_plugin.py ++++ b/functional_tests/test_coverage_plugin.py +@@ -40,7 +40,7 @@ class TestCoveragePlugin(PluginTester, unittest.TestCase): + super(TestCoveragePlugin, self).setUp() + + def runTest(self): +- print(self.output) ++ print((self.output)) + self.assertTrue( + # Coverage < 4.0 + ("blah 4 3 25% 1" in self.output) or +diff --git a/functional_tests/test_doctest_plugin.py b/functional_tests/test_doctest_plugin.py +index c91ecc5..441fffd 100644 +--- a/functional_tests/test_doctest_plugin.py ++++ b/functional_tests/test_doctest_plugin.py +@@ -12,7 +12,7 @@ class TestDoctestPlugin(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'dtt') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + + assert 'Doctest: some_mod ... ok' in self.output + assert 'Doctest: some_mod.foo ... ok' in self.output +@@ -27,7 +27,7 @@ class TestDoctestFiles(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'dtt', 'docs') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + + expect = [ + 'Doctest: doc.txt ... ok', +diff --git a/functional_tests/test_failure.py b/functional_tests/test_failure.py +index e9d17e9..93ca0b4 100644 +--- a/functional_tests/test_failure.py ++++ b/functional_tests/test_failure.py +@@ -15,11 +15,11 @@ class TestPrintedTraceback(PluginTester, unittest.TestCase): + return None + + def test_correct_exception_raised(self): +- print +- print '!' * 70 +- print str(self.output) +- print '!' * 70 +- print ++ print() ++ print('!' * 70) ++ print(str(self.output)) ++ print('!' * 70) ++ print() + + # Look for the line in the traceback causing the failure + assert "raise '\\xf1'.encode('ASCII')" in str(self.output) +diff --git a/functional_tests/test_failuredetail_plugin.py b/functional_tests/test_failuredetail_plugin.py +index 8484461..847c415 100644 +--- a/functional_tests/test_failuredetail_plugin.py ++++ b/functional_tests/test_failuredetail_plugin.py +@@ -14,9 +14,9 @@ class TestFailureDetail(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'fdp') + + def runTest(self): +- print '*' * 70 +- print str(self.output) +- print '*' * 70 ++ print('*' * 70) ++ print(str(self.output)) ++ print('*' * 70) + + expect = \ + 'AssertionError: a is not 4\n' +@@ -34,9 +34,9 @@ class TestFailureDetailWithCapture(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'fdp/test_fdp_no_capt.py') + + def runTest(self): +- print '*' * 70 +- print str(self.output) +- print '*' * 70 ++ print('*' * 70) ++ print(str(self.output)) ++ print('*' * 70) + + expect = \ + 'AssertionError: a is not 4\n' +@@ -53,9 +53,9 @@ class TestFailureDetailWithUnicodeAndCapture(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue720') + + def runTest(self): +- print '*' * 70 +- print str(self.output) +- print '*' * 70 ++ print('*' * 70) ++ print(str(self.output)) ++ print('*' * 70) + + assert 'UnicodeDecodeError' not in self.output + assert 'UnicodeEncodeError' not in self.output +diff --git a/functional_tests/test_generator_fixtures.py b/functional_tests/test_generator_fixtures.py +index 3240141..8d357a3 100644 +--- a/functional_tests/test_generator_fixtures.py ++++ b/functional_tests/test_generator_fixtures.py +@@ -35,21 +35,21 @@ check.teardown = inner_teardown + + class TestClass(object): + def setup(self): +- print "setup called in", self ++ print("setup called in", self) + self.called = ['setup'] + + def teardown(self): +- print "teardown called in", self ++ print("teardown called in", self) + eq_(self.called, ['setup']) + self.called.append('teardown') + + def test(self): +- print "test called in", self ++ print("test called in", self) + for i in range(0, 5): + yield self.check, i + + def check(self, i): +- print "check called in", self ++ print("check called in", self) + expect = ['setup'] + #for x in range(0, i): + # expect.append('setup') +diff --git a/functional_tests/test_id_plugin.py b/functional_tests/test_id_plugin.py +index 7b3d39d..6ffc1c0 100644 +--- a/functional_tests/test_id_plugin.py ++++ b/functional_tests/test_id_plugin.py +@@ -7,7 +7,7 @@ import unittest + from nose.plugins import PluginTester + from nose.plugins.builtin import Doctest + from nose.plugins.builtin import TestId +-from cPickle import dump, load ++from pickle import dump, load + + support = os.path.join(os.path.dirname(__file__), 'support') + idfile = tempfile.mktemp() +@@ -49,9 +49,9 @@ class TestDiscoveryMode(PluginTester, unittest.TestCase): + ids = load(fh)['ids'] + fh.close() + assert ids +- assert ids.keys() +- self.assertEqual(map(int, ids.keys()), ids.keys()) +- assert ids.values() ++ assert list(ids.keys()) ++ self.assertEqual(list(map(int, list(ids.keys()))), list(ids.keys())) ++ assert list(ids.values()) + + + class TestLoadNamesMode(PluginTester, unittest.TestCase): +@@ -81,10 +81,10 @@ class TestLoadNamesMode(PluginTester, unittest.TestCase): + ids = load(fh) + fh.close() + assert ids +- assert ids.keys() ++ assert list(ids.keys()) + ids = ids['ids'] +- self.assertEqual(filter(lambda i: int(i), ids.keys()), ids.keys()) +- assert len(ids.keys()) > 2 ++ self.assertEqual([i for i in list(ids.keys()) if int(i)], list(ids.keys())) ++ assert len(list(ids.keys())) > 2 + + + class TestLoadNamesMode_2(PluginTester, unittest.TestCase): +@@ -142,7 +142,7 @@ class TestWithDoctest_1(PluginTester, unittest.TestCase): + fh = open(idfile, 'rb') + ids = load(fh)['ids'] + fh.close() +- for key, (file, mod, call) in ids.items(): ++ for key, (file, mod, call) in list(ids.items()): + assert mod != 'doctest', \ + "Doctest test was incorrectly identified as being part of "\ + "the doctest module itself (#%s)" % key +@@ -166,9 +166,9 @@ class TestWithDoctest_2(PluginTester, unittest.TestCase): + return None + + def test_load_ids_doctest(self): +- print '*' * 70 +- print str(self.output) +- print '*' * 70 ++ print('*' * 70) ++ print(str(self.output)) ++ print('*' * 70) + + assert 'Doctest: exm.add_one ... FAIL' in self.output + +@@ -188,9 +188,9 @@ class TestWithDoctestFileTests_1(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'dtt', 'docs') + + def test_docfile_tests_get_ids(self): +- print '>' * 70 +- print str(self.output) +- print '>' * 70 ++ print('>' * 70) ++ print(str(self.output)) ++ print('>' * 70) + + last = None + for line in self.output: +@@ -209,7 +209,7 @@ class TestWithDoctestFileTests_1(PluginTester, unittest.TestCase): + fh = open(idfile, 'rb') + ids = load(fh)['ids'] + fh.close() +- for key, (file, mod, call) in ids.items(): ++ for key, (file, mod, call) in list(ids.items()): + assert mod != 'doctest', \ + "Doctest test was incorrectly identified as being part of "\ + "the doctest module itself (#%s)" % key +@@ -234,9 +234,9 @@ class TestWithDoctestFileTests_2(PluginTester, unittest.TestCase): + return None + + def test_load_from_name_id_docfile_test(self): +- print '*' * 70 +- print str(self.output) +- print '*' * 70 ++ print('*' * 70) ++ print(str(self.output)) ++ print('*' * 70) + + assert 'Doctest: errdoc.txt ... FAIL' in self.output + +diff --git a/functional_tests/test_importer.py b/functional_tests/test_importer.py +index 20fb15d..297bd05 100644 +--- a/functional_tests/test_importer.py ++++ b/functional_tests/test_importer.py +@@ -27,7 +27,7 @@ class TestImporter(unittest.TestCase): + self.has_symlinks = True + + def tearDown(self): +- to_del = [ m for m in sys.modules.keys() if ++ to_del = [ m for m in list(sys.modules.keys()) if + m not in self._mods ] + if to_del: + for mod in to_del: +@@ -115,7 +115,7 @@ class TestImporter(unittest.TestCase): + path = os.path.join(self.dir, + 'package2', 'test_pak', 'test_sub', 'test_mod.py') + mod = imp.importFromPath(path, 'test_pak.test_sub.test_mod') +- print mod, dir(mod) ++ print(mod, dir(mod)) + assert 'test_pak' in sys.modules, 'test_pak was not imported?' + test_pak = sys.modules['test_pak'] + assert hasattr(test_pak, 'test_sub'), "test_pak.test_sub was not set" +diff --git a/functional_tests/test_isolate_plugin.py b/functional_tests/test_isolate_plugin.py +index 087dcaa..30b71ae 100644 +--- a/functional_tests/test_isolate_plugin.py ++++ b/functional_tests/test_isolate_plugin.py +@@ -13,7 +13,7 @@ class TestDiscovery(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'ipt') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + + for line in self.output: + if not line.strip(): +@@ -43,7 +43,7 @@ class TestLoadFromNames(PluginTester, unittest.TestCase): + return None + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + + for line in self.output: + if not line.strip(): +diff --git a/functional_tests/test_issue_072.py b/functional_tests/test_issue_072.py +index 3848f6f..9e400f8 100644 +--- a/functional_tests/test_issue_072.py ++++ b/functional_tests/test_issue_072.py +@@ -15,11 +15,11 @@ class TestFailureDetailWorks(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue072') + + def test_assert_info_in_output(self): +- print +- print '!' * 70 +- print str(self.output) +- print '!' * 70 +- print ++ print() ++ print('!' * 70) ++ print(str(self.output)) ++ print('!' * 70) ++ print() + assert '>> assert 4 == 2' in str(self.output) + + class TestFailureDetailWorksWhenChained(PluginTester, unittest.TestCase): +@@ -30,11 +30,11 @@ class TestFailureDetailWorksWhenChained(PluginTester, unittest.TestCase): + + def test_assert_info_and_capt_stdout_in_output(self): + out = str(self.output) +- print +- print 'x' * 70 +- print out +- print 'x' * 70 +- print ++ print() ++ print('x' * 70) ++ print(out) ++ print('x' * 70) ++ print() + + assert '>> assert 4 == 2' in out, \ + "Assert info not found in chained output" +diff --git a/functional_tests/test_issue_082.py b/functional_tests/test_issue_082.py +index 06fa019..4f7ca11 100644 +--- a/functional_tests/test_issue_082.py ++++ b/functional_tests/test_issue_082.py +@@ -1,9 +1,9 @@ + import os + import re + try: +- from cStringIO import StringIO ++ from io import StringIO + except ImportError: +- from StringIO import StringIO ++ from io import StringIO + import sys + import unittest + +@@ -47,7 +47,7 @@ class TestIncludeUnderscoreFiles(PluginTester, unittest.TestCase): + ) + + def test_assert_info_in_output(self): +- print self.output ++ print(self.output) + # In future, all four test cases will be run. Backwards-compatibility + # means that can't be done in nose 0.10. + assert '_mypackage._eggs' not in str(self.output) +@@ -63,7 +63,7 @@ class TestExcludeUnderscoreFilesByDefault(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue082') + + def test_assert_info_in_output(self): +- print self.output ++ print(self.output) + assert '_mypackage._eggs' not in str(self.output) + assert '_mypackage.bacon' not in str(self.output) + assert 'mypublicpackage._foo' not in str(self.output) +diff --git a/functional_tests/test_issue_649.py b/functional_tests/test_issue_649.py +index 74e516e..2182014 100644 +--- a/functional_tests/test_issue_649.py ++++ b/functional_tests/test_issue_649.py +@@ -14,5 +14,5 @@ class TestIssue649(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue649') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + assert 'UnicodeDecodeError' not in self.output +diff --git a/functional_tests/test_load_tests_from_test_case.py b/functional_tests/test_load_tests_from_test_case.py +index 934d43b..830e2af 100644 +--- a/functional_tests/test_load_tests_from_test_case.py ++++ b/functional_tests/test_load_tests_from_test_case.py +@@ -16,15 +16,15 @@ class NoFixturePlug(Plugin): + enabled = True + + def options(self, parser, env): +- print "options" ++ print("options") + pass + + def configure(self, options, conf): +- print "configure" ++ print("configure") + pass + + def loadTestsFromTestCase(self, testCaseClass): +- print "Called!" ++ print("Called!") + class Derived(testCaseClass): + def setUp(self): + pass +@@ -53,7 +53,7 @@ class TestLoadTestsFromTestCaseHook(PluginTester, unittest.TestCase): + expect = [ + 'test_value (%s.Derived) ... ERROR' % __name__, + 'test_value (tests.Tests) ... ok'] +- print str(self.output) ++ print(str(self.output)) + for line in self.output: + if expect: + self.assertEqual(line.strip(), expect.pop(0)) +diff --git a/functional_tests/test_loader.py b/functional_tests/test_loader.py +index 3f82122..cdd0f99 100644 +--- a/functional_tests/test_loader.py ++++ b/functional_tests/test_loader.py +@@ -2,7 +2,7 @@ import os + import sys + import unittest + from difflib import ndiff +-from cStringIO import StringIO ++from io import StringIO + + from nose.config import Config + from nose.plugins.manager import PluginManager +@@ -25,7 +25,7 @@ class TestNoseTestLoader(unittest.TestCase): + suite.ContextSuiteFactory.suiteClass = TreePrintContextSuite + + def tearDown(self): +- to_del = [ m for m in sys.modules.keys() if ++ to_del = [ m for m in list(sys.modules.keys()) if + m not in self._mods ] + if to_del: + for mod in to_del: +@@ -71,7 +71,7 @@ class TestNoseTestLoader(unittest.TestCase): + dir_suite(res) + + m = sys.modules['test_pak'] +- print "test pak state", m.state ++ print("test pak state", m.state) + + assert not res.errors, res.errors + assert not res.failures, res.failures +@@ -112,7 +112,7 @@ class TestNoseTestLoader(unittest.TestCase): + assert 'test_pak' in sys.modules, \ + "Context did not load test_pak" + m = sys.modules['test_pak'] +- print "test pak state", m.state ++ print("test pak state", m.state) + expect = ['test_pak.setup', + 'test_pak.test_mod.setup', + 'test_pak.test_mod.test_add', +@@ -133,7 +133,7 @@ class TestNoseTestLoader(unittest.TestCase): + assert 'test_pak' in sys.modules, \ + "Context did not load test_pak" + m = sys.modules['test_pak'] +- print "test pak state", m.state ++ print("test pak state", m.state) + expect = ['test_pak.setup', + 'test_pak.test_mod.setup', + 'test_pak.test_mod.test_add', +@@ -182,7 +182,7 @@ class TestNoseTestLoader(unittest.TestCase): + assert 'test_pak' in sys.modules, \ + "Context not load test_pak" + m = sys.modules['test_pak'] +- print "test pak state", m.state ++ print("test pak state", m.state) + expect = ['test_pak.setup', + 'test_pak.test_sub.setup', + 'test_pak.test_sub.test_mod.setup', +@@ -204,14 +204,14 @@ class TestNoseTestLoader(unittest.TestCase): + ['test_pak.test_sub.test_mod:TestMaths.test_div', + 'test_pak.test_sub.test_mod:TestMaths.test_two_two', + 'test_pak.test_mod:test_add']) +- print suite ++ print(suite) + suite(res) + assert not res.errors, res.errors + assert not res.failures, res.failures + assert 'test_pak' in sys.modules, \ + "Context not load test_pak" + m = sys.modules['test_pak'] +- print "test pak state", m.state ++ print("test pak state", m.state) + expect = ['test_pak.setup', + 'test_pak.test_sub.setup', + 'test_pak.test_sub.test_mod.setup', +@@ -240,16 +240,16 @@ class TestNoseTestLoader(unittest.TestCase): + ['test_pak1.test_mod', + 'test_pak2:test_two_two', + 'test_pak1:test_one_one']) +- print suite ++ print(suite) + suite(res) + res.printErrors() +- print stream.getvalue() ++ print(stream.getvalue()) + assert not res.errors, res.errors + assert not res.failures, res.failures + assert 'state' in sys.modules, \ + "Context not load state module" + m = sys.modules['state'] +- print "state", m.called ++ print("state", m.called) + + expect = ['test_pak1.setup', + 'test_pak1.test_mod.setup', +@@ -271,16 +271,16 @@ class TestNoseTestLoader(unittest.TestCase): + ['test_pak1.test_mod', + 'test_pak2:test_two_two', + 'test_mod']) +- print suite ++ print(suite) + suite(res) + res.printErrors() +- print stream.getvalue() ++ print(stream.getvalue()) + assert not res.errors, res.errors + assert not res.failures, res.failures + assert 'state' in sys.modules, \ + "Context not load state module" + m = sys.modules['state'] +- print "state", m.called ++ print("state", m.called) + + expect = ['test_pak1.setup', + 'test_pak1.test_mod.setup', +@@ -348,7 +348,7 @@ class TestNoseTestLoader(unittest.TestCase): + descriptions=0, verbosity=1) + suite(res) + +- print res.errors ++ print(res.errors) + res.printErrors() + assert res.errors, "Expected errors but got none" + assert not res.failures, res.failures +@@ -364,7 +364,7 @@ class TestNoseTestLoader(unittest.TestCase): + stream=_WritelnDecorator(sys.stdout), + descriptions=0, verbosity=1) + suite(res) +- print res.errors ++ print(res.errors) + res.printErrors() + assert res.errors, "Expected errors but got none" + assert not res.failures, res.failures +@@ -381,7 +381,7 @@ class TestNoseTestLoader(unittest.TestCase): + stream=_WritelnDecorator(sys.stdout), + descriptions=0, verbosity=1) + suite(res) +- print res.errors ++ print(res.errors) + assert res.errors, "Expected errors but got none" + assert not res.failures, res.failures + +@@ -412,7 +412,7 @@ class TestNoseTestLoader(unittest.TestCase): + stream=_WritelnDecorator(sys.stdout), + descriptions=0, verbosity=1) + suite(res) +- print res.errors ++ print(res.errors) + self.assertEqual(len(res.errors), 1) + assert 'raise Exception("pow")' in res.errors[0][1] + +@@ -426,7 +426,7 @@ class TestNoseTestLoader(unittest.TestCase): + assert 'test_pak' in sys.modules, \ + "Context did not load test_pak" + m = sys.modules['test_pak'] +- print "test pak state", m.state ++ print("test pak state", m.state) + expect = ['test_pak.setup', + 'test_pak.test_sub.setup', + 'test_pak.test_sub.test_sub_init', +@@ -447,7 +447,7 @@ class TestNoseTestLoader(unittest.TestCase): + assert 'test_pak' in sys.modules, \ + "Context did not load test_pak" + m = sys.modules['test_pak'] +- print "test pak state", m.state ++ print("test pak state", m.state) + expect = ['test_pak.setup', + 'test_pak.test_sub.setup', + 'test_pak.test_sub.test_sub_init', +@@ -480,7 +480,7 @@ class TreePrintContextSuite(suite.ContextSuite): + indent = '' + + def setUp(self): +- print self, 'setup -->' ++ print(self, 'setup -->') + suite.ContextSuite.setUp(self) + TreePrintContextSuite.indent += ' ' + +@@ -489,7 +489,7 @@ class TreePrintContextSuite(suite.ContextSuite): + try: + suite.ContextSuite.tearDown(self) + finally: +- print self, 'teardown <--' ++ print(self, 'teardown <--') + def __repr__(self): + + return '%s<%s>' % (self.indent, +diff --git a/functional_tests/test_multiprocessing/support/fake_nosetest.py b/functional_tests/test_multiprocessing/support/fake_nosetest.py +index 8319da8..65e7db5 100644 +--- a/functional_tests/test_multiprocessing/support/fake_nosetest.py ++++ b/functional_tests/test_multiprocessing/support/fake_nosetest.py +@@ -8,7 +8,7 @@ from nose.plugins.manager import PluginManager + + if __name__ == '__main__': + if len(sys.argv) < 3: +- print "USAGE: %s TEST_FILE LOG_FILE KILL_FILE" % sys.argv[0] ++ print("USAGE: %s TEST_FILE LOG_FILE KILL_FILE" % sys.argv[0]) + sys.exit(1) + os.environ['NOSE_MP_LOG']=sys.argv[2] + os.environ['NOSE_MP_KILL']=sys.argv[3] +diff --git a/functional_tests/test_multiprocessing/test_keyboardinterrupt.py b/functional_tests/test_multiprocessing/test_keyboardinterrupt.py +index 18c8af1..d62fcc3 100644 +--- a/functional_tests/test_multiprocessing/test_keyboardinterrupt.py ++++ b/functional_tests/test_multiprocessing/test_keyboardinterrupt.py +@@ -66,11 +66,11 @@ def test_keyboardinterrupt(): + process, logfile, _ = keyboardinterrupt('keyboardinterrupt.py') + stdout, stderr = [s.decode('utf-8') for s in process.communicate(None)] + log = get_log_content(logfile) +- print stderr +- print '----' +- print stdout +- print '----' +- print log ++ print(stderr) ++ print('----') ++ print(stdout) ++ print('----') ++ print(log) + assert 'setup' in log + assert 'test_timeout' in log + assert 'test_timeout_finished' not in log +@@ -88,11 +88,11 @@ def test_keyboardinterrupt_twice(): + os.killpg(process.pid, signal.SIGINT) + stdout, stderr = [s.decode('utf-8') for s in process.communicate(None)] + log = get_log_content(logfile) +- print stderr +- print '----' +- print stdout +- print '----' +- print log ++ print(stderr) ++ print('----') ++ print(stdout) ++ print('----') ++ print(log) + assert 'setup' in log + assert 'test_timeout' in log + assert 'test_timeout_finished' not in log +diff --git a/functional_tests/test_multiprocessing/test_nameerror.py b/functional_tests/test_multiprocessing/test_nameerror.py +index 5e58226..75c22b7 100644 +--- a/functional_tests/test_multiprocessing/test_nameerror.py ++++ b/functional_tests/test_multiprocessing/test_nameerror.py +@@ -7,7 +7,7 @@ class TestMPNameError(MPTestBase): + suitepath = os.path.join(os.path.dirname(__file__), 'support', 'nameerror.py') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + assert 'NameError' in self.output + assert "'undefined_variable' is not defined" in self.output + +diff --git a/functional_tests/test_namespace_pkg.py b/functional_tests/test_namespace_pkg.py +index 2db051e..a4d3ae3 100644 +--- a/functional_tests/test_namespace_pkg.py ++++ b/functional_tests/test_namespace_pkg.py +@@ -1,7 +1,7 @@ + import os + import sys + import unittest +-from cStringIO import StringIO ++from io import StringIO + from nose.core import TestProgram + from test_program import TestRunner + +diff --git a/functional_tests/test_plugin_api.py b/functional_tests/test_plugin_api.py +index c508ded..8e64d39 100644 +--- a/functional_tests/test_plugin_api.py ++++ b/functional_tests/test_plugin_api.py +@@ -31,9 +31,9 @@ class TestPrepareTestCase_MakeAllFail(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'package2') + + def runTest(self): +- print "x" * 70 +- print str(self.output) +- print "x" * 70 ++ print("x" * 70) ++ print(str(self.output)) ++ print("x" * 70) + for line in self.output: + if line.startswith('test_pak'): + assert line.strip().endswith('FAIL'), \ +diff --git a/functional_tests/test_plugins.py b/functional_tests/test_plugins.py +index eff6c7a..debe2a6 100644 +--- a/functional_tests/test_plugins.py ++++ b/functional_tests/test_plugins.py +@@ -23,7 +23,7 @@ class TestPluginCalls(unittest.TestCase): + conf = Config(plugins=man, stream=sys.stdout) + t = TestProgram(defaultTest=wdir, config=conf, + argv=['test_plugin_calls_package1'], exit=False) +- print man.calls() ++ print(man.calls()) + assert man.called + + self.assertEqual( +@@ -47,7 +47,7 @@ class TestPluginCalls(unittest.TestCase): + conf = Config(plugins=man, stream=sys.stdout) + t = TestProgram(defaultTest=wdir, config=conf, + argv=['test_plugin_calls_package1', '-v'], exit=False) +- print man.calls() ++ print(man.calls()) + assert man.called + + self.assertEqual( +diff --git a/functional_tests/test_plugintest.py b/functional_tests/test_plugintest.py +index 7d1a65b..a680cd9 100644 +--- a/functional_tests/test_plugintest.py ++++ b/functional_tests/test_plugintest.py +@@ -2,7 +2,7 @@ + import unittest, os + from nose.plugins import PluginTester, Plugin + from nose.tools import eq_ +-from cStringIO import StringIO ++from io import StringIO + + class StubPlugin(Plugin): + def options(self, parser, env=os.environ): +diff --git a/functional_tests/test_program.py b/functional_tests/test_program.py +index 27c245f..3b29065 100644 +--- a/functional_tests/test_program.py ++++ b/functional_tests/test_program.py +@@ -1,6 +1,6 @@ + import os + import unittest +-from cStringIO import StringIO ++from io import StringIO + from nose import SkipTest + from nose.core import TestProgram + from nose.config import Config +@@ -35,7 +35,7 @@ class TestTestProgram(unittest.TestCase): + config=Config(), + exit=False) + res = runner.result +- print stream.getvalue() ++ print(stream.getvalue()) + self.assertEqual(res.testsRun, 0, + "Expected to run 0 tests, ran %s" % res.testsRun) + assert res.wasSuccessful() +@@ -55,7 +55,7 @@ class TestTestProgram(unittest.TestCase): + config=Config(), + exit=False) + res = runner.result +- print stream.getvalue() ++ print(stream.getvalue()) + self.assertEqual(res.testsRun, 6, + "Expected to run 6 tests, ran %s" % res.testsRun) + assert res.wasSuccessful() +@@ -84,7 +84,7 @@ class TestTestProgram(unittest.TestCase): + config=Config(), + exit=False) + res = runner.result +- print stream.getvalue() ++ print(stream.getvalue()) + self.assertEqual(res.testsRun, 2, + "Expected to run 2 tests, ran %s" % res.testsRun) + assert res.wasSuccessful() +@@ -109,9 +109,9 @@ class TestTestProgram(unittest.TestCase): + config=Config(stream=stream), + exit=False) + res = runner.result +- print stream.getvalue() +- print "-----" +- print repr(res) ++ print(stream.getvalue()) ++ print("-----") ++ print(repr(res)) + + self.assertEqual(res.testsRun, 4, + "Expected to run 4 tests, ran %s" % (res.testsRun,)) +@@ -147,7 +147,7 @@ class TestTestProgram(unittest.TestCase): + plugins=DefaultPluginManager()), + exit=False) + res = runner.result +- print stream.getvalue() ++ print(stream.getvalue()) + self.assertEqual(res.testsRun, 0) # error is in setup + assert not res.wasSuccessful() + assert res.errors +@@ -164,7 +164,7 @@ class TestTestProgram(unittest.TestCase): + config=Config(), + exit=False) + res = runner.result +- print stream.getvalue() ++ print(stream.getvalue()) + self.assertEqual(res.testsRun, 8) + + def test_illegal_packages_not_selected(self): +@@ -178,7 +178,7 @@ class TestTestProgram(unittest.TestCase): + plugins=DefaultPluginManager()), + exit=False) + res = runner.result +- print stream.getvalue() ++ print(stream.getvalue()) + self.assertEqual(res.testsRun, 0) + assert res.wasSuccessful() + assert not res.errors +diff --git a/functional_tests/test_result.py b/functional_tests/test_result.py +index 7206020..4ef2167 100644 +--- a/functional_tests/test_result.py ++++ b/functional_tests/test_result.py +@@ -1,7 +1,7 @@ + import os + import sys + import unittest +-from cStringIO import StringIO ++from io import StringIO + from nose.config import Config + from nose.core import TestProgram + from nose.plugins.manager import PluginManager +@@ -23,8 +23,8 @@ class TestResultSummary(unittest.TestCase): + TestProgram(argv=['t', '--with-todo', pkpath], + config=config, exit=False) + out = stream.getvalue() +- print out +- self.assert_('FAILED (TODO=1)' in out) ++ print(out) ++ self.assertTrue('FAILED (TODO=1)' in out) + + + if __name__ == '__main__': +diff --git a/functional_tests/test_string_exception.py b/functional_tests/test_string_exception.py +index 396c92a..5dbf1f5 100644 +--- a/functional_tests/test_string_exception.py ++++ b/functional_tests/test_string_exception.py +@@ -21,11 +21,11 @@ class TestStringException(PluginTester, unittest.TestCase): + raise SkipTest("String exceptions are not supported in this " + "version of Python") + +- print +- print '!' * 70 +- print str(self.output) +- print '!' * 70 +- print ++ print() ++ print('!' * 70) ++ print(str(self.output)) ++ print('!' * 70) ++ print() + assert 'raise "string exception"' in str(self.output) + assert 'raise "string exception in setup"' in str(self.output) + assert 'raise "string exception in teardown"' in str(self.output) +diff --git a/functional_tests/test_success.py b/functional_tests/test_success.py +index 760a7d1..badfd68 100644 +--- a/functional_tests/test_success.py ++++ b/functional_tests/test_success.py +@@ -15,7 +15,7 @@ class TestSingleTestPass(PluginTester, unittest.TestCase): + # this test fails if the final terminating newline is not present (it + # could still be written as a doctest -- PluginTester was just closer + # to hand) +- print self.output ++ print(self.output) + output = remove_timings(str(self.output)) + assert output == """\ + test.test ... ok +@@ -32,7 +32,7 @@ class TestZeroTestsPass(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'empty') + + def test_zero_tests_pass(self): +- print self.output ++ print(self.output) + output = remove_timings(str(self.output)) + assert output == """\ + +diff --git a/functional_tests/test_suite.py b/functional_tests/test_suite.py +index a411469..b6e4a18 100644 +--- a/functional_tests/test_suite.py ++++ b/functional_tests/test_suite.py +@@ -14,7 +14,7 @@ class TestContextSuiteFactory(unittest.TestCase): + sys.path.insert(0, os.path.join(support, 'package2')) + + def tearDown(self): +- to_del = [ m for m in sys.modules.keys() if ++ to_del = [ m for m in list(sys.modules.keys()) if + m not in self._mods ] + if to_del: + for mod in to_del: +diff --git a/functional_tests/test_xunit.py b/functional_tests/test_xunit.py +index 6e76a7d..22f3fec 100644 +--- a/functional_tests/test_xunit.py ++++ b/functional_tests/test_xunit.py +@@ -21,7 +21,7 @@ class TestXUnitPlugin(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'xunit') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + + assert "ERROR: test_error" in self.output + assert "FAIL: test_fail" in self.output +@@ -34,7 +34,7 @@ class TestXUnitPlugin(PluginTester, unittest.TestCase): + f = codecs.open(xml_results_filename,'r', encoding='utf8') + result = f.read() + f.close() +- print result.encode('utf8', 'replace') ++ print(result.encode('utf8', 'replace')) + + assert '' in result + assert '' in result +@@ -56,11 +56,11 @@ class TestIssue134(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue134') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + f = open(xml_results_filename,'r') + result = f.read() + f.close() +- print result ++ print(result) + assert 'raise IOError(42, "test")' in result + assert 'tests="1" errors="1" failures="0" skip="0"' in result + +@@ -72,11 +72,11 @@ class TestIssue279(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue279') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + f = open(xml_results_filename,'r') + result = f.read() + f.close() +- print result ++ print(result) + assert 'tests="1" errors="1" failures="0" skip="0"' in result + assert "Exception: I would prefer not to" in result + +@@ -88,11 +88,11 @@ class TestIssue680(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue680') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + f = open(xml_results_filename,'rb') + result = f.read().decode('utf-8') + f.close() +- print result ++ print(result) + assert 'tests="1" errors="0" failures="0" skip="0"' in result + + +@@ -103,11 +103,11 @@ class TestIssue700(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue700') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + f = open(xml_results_filename,'r') + result = f.read() + f.close() +- print result ++ print(result) + assert 'tests="1" errors="0" failures="0" skip="0"' in result + assert 'line1\n' in result + assert 'line2\n' in result +@@ -121,10 +121,10 @@ class TestIssue859(PluginTester, unittest.TestCase): + suitepath = os.path.join(support, 'issue859') + + def runTest(self): +- print str(self.output) ++ print(str(self.output)) + f = open(xml_results_filename, 'r') + result = f.read() + f.close() +- print result ++ print(result) + assert 'tests="1" errors="0" failures="0" skip="0"' in result + assert 'testsuite name="TestIssue859"' in result +diff --git a/nose/case.py b/nose/case.py +index 97fabf0..4c589f8 100644 +--- a/nose/case.py ++++ b/nose/case.py +@@ -345,7 +345,7 @@ class MethodTestCase(TestBase): + self.descriptor = descriptor + if isfunction(method): + raise ValueError("Unbound methods must be wrapped using pyversion.unbound_method before passing to MethodTestCase") +- self.cls = method.im_class ++ self.cls = method.__self__.__class__ + self.inst = self.cls() + if self.test is None: + method_name = self.method.__name__ +diff --git a/nose/commands.py b/nose/commands.py +index ef0e9ca..db9fe31 100644 +--- a/nose/commands.py ++++ b/nose/commands.py +@@ -148,7 +148,7 @@ else: + + ei_cmd = self.get_finalized_command("egg_info") + argv = ['nosetests', '--where', ei_cmd.egg_base] +- for (option_name, cmd_name) in self.option_to_cmds.items(): ++ for (option_name, cmd_name) in list(self.option_to_cmds.items()): + if option_name in option_blacklist: + continue + value = getattr(self, option_name) +diff --git a/nose/config.py b/nose/config.py +index d9aec2d..ec81a20 100644 +--- a/nose/config.py ++++ b/nose/config.py +@@ -3,7 +3,7 @@ import optparse + import os + import re + import sys +-import ConfigParser ++import configparser + from optparse import OptionParser + from nose.util import absdir, tolist + from nose.plugins.manager import NoPlugins +@@ -62,24 +62,24 @@ class ConfiguredDefaultsOptionParser(object): + def _readFromFilenames(self, filenames): + config = [] + for filename in filenames: +- cfg = ConfigParser.RawConfigParser() ++ cfg = configparser.RawConfigParser() + try: + cfg.read(filename) +- except ConfigParser.Error, exc: ++ except configparser.Error as exc: + raise ConfigError("Error reading config file %r: %s" % + (filename, str(exc))) + config.extend(self._configTuples(cfg, filename)) + return config + + def _readFromFileObject(self, fh): +- cfg = ConfigParser.RawConfigParser() ++ cfg = configparser.RawConfigParser() + try: + filename = fh.name + except AttributeError: + filename = '' + try: + cfg.read_file(fh) +- except ConfigParser.Error, exc: ++ except configparser.Error as exc: + raise ConfigError("Error reading config file %r: %s" % + (filename, str(exc))) + return self._configTuples(cfg, filename) +@@ -89,7 +89,7 @@ class ConfiguredDefaultsOptionParser(object): + config_files.readline + except AttributeError: + filename_or_filenames = config_files +- if isinstance(filename_or_filenames, basestring): ++ if isinstance(filename_or_filenames, str): + filenames = [filename_or_filenames] + else: + filenames = filename_or_filenames +@@ -113,12 +113,12 @@ class ConfiguredDefaultsOptionParser(object): + continue + try: + self._processConfigValue(name, value, values, parser) +- except NoSuchOptionError, exc: ++ except NoSuchOptionError as exc: + self._file_error( + "Error reading config file %r: " + "no such option %r" % (filename, exc.name), + name=name, filename=filename) +- except optparse.OptionValueError, exc: ++ except optparse.OptionValueError as exc: + msg = str(exc).replace('--' + name, repr(name), 1) + self._file_error("Error reading config file %r: " + "%s" % (filename, msg), +@@ -128,12 +128,12 @@ class ConfiguredDefaultsOptionParser(object): + values = self._parser.get_default_values() + try: + config = self._readConfiguration(config_files) +- except ConfigError, exc: ++ except ConfigError as exc: + self._error(str(exc)) + else: + try: + self._applyConfigurationToValues(self._parser, config, values) +- except ConfigError, exc: ++ except ConfigError as exc: + self._error(str(exc)) + return self._parser.parse_args(args, values) + +@@ -195,7 +195,7 @@ class Config(object): + r'^_', + r'^setup\.py$', + ] +- self.ignoreFiles = map(re.compile, self.ignoreFilesDefaultStrings) ++ self.ignoreFiles = list(map(re.compile, self.ignoreFilesDefaultStrings)) + self.include = None + self.loggingConfig = None + self.logStream = sys.stderr +@@ -247,7 +247,7 @@ class Config(object): + d = self.__dict__.copy() + # don't expose env, could include sensitive info + d['env'] = {} +- keys = [ k for k in d.keys() ++ keys = [ k for k in list(d.keys()) + if not k.startswith('_') ] + keys.sort() + return "Config(%s)" % ', '.join([ '%s=%r' % (k, d[k]) +@@ -328,17 +328,17 @@ class Config(object): + self.testMatch = re.compile(options.testMatch) + + if options.ignoreFiles: +- self.ignoreFiles = map(re.compile, tolist(options.ignoreFiles)) ++ self.ignoreFiles = list(map(re.compile, tolist(options.ignoreFiles))) + log.info("Ignoring files matching %s", options.ignoreFiles) + else: + log.info("Ignoring files matching %s", self.ignoreFilesDefaultStrings) + + if options.include: +- self.include = map(re.compile, tolist(options.include)) ++ self.include = list(map(re.compile, tolist(options.include))) + log.info("Including tests matching %s", options.include) + + if options.exclude: +- self.exclude = map(re.compile, tolist(options.exclude)) ++ self.exclude = list(map(re.compile, tolist(options.exclude))) + log.info("Excluding tests matching %s", options.exclude) + + # When listing plugins we don't want to run them +@@ -623,15 +623,15 @@ class NoOptions(object): + def __getnewargs__(self): + return () + +- def __nonzero__(self): ++ def __bool__(self): + return False + + + def user_config_files(): + """Return path to any existing user config files + """ +- return filter(os.path.exists, +- map(os.path.expanduser, config_files)) ++ return list(filter(os.path.exists, ++ list(map(os.path.expanduser, config_files)))) + + + def all_config_files(): +diff --git a/nose/core.py b/nose/core.py +index 49e7939..ceacc9a 100644 +--- a/nose/core.py ++++ b/nose/core.py +@@ -1,6 +1,6 @@ + """Implements nose test program and collector. + """ +-from __future__ import generators ++ + + import logging + import os +@@ -150,7 +150,7 @@ class TestProgram(unittest.TestProgram): + if self.config.options.version: + from nose import __version__ + sys.stdout = sys.__stdout__ +- print "%s version %s" % (os.path.basename(sys.argv[0]), __version__) ++ print("%s version %s" % (os.path.basename(sys.argv[0]), __version__)) + sys.exit(0) + + if self.config.options.showPlugins: +@@ -224,26 +224,26 @@ class TestProgram(unittest.TestProgram): + v = self.config.verbosity + self.config.plugins.sort() + for p in self.config.plugins: +- print "Plugin %s" % p.name ++ print("Plugin %s" % p.name) + if v >= 2: +- print " score: %s" % p.score +- print '\n'.join(textwrap.wrap(p.help().strip(), ++ print(" score: %s" % p.score) ++ print('\n'.join(textwrap.wrap(p.help().strip(), + initial_indent=' ', +- subsequent_indent=' ')) ++ subsequent_indent=' '))) + if v >= 3: + parser = DummyParser() + p.addOptions(parser) + if len(parser.options): +- print +- print " Options:" ++ print() ++ print(" Options:") + for opts, help in parser.options: +- print ' %s' % (', '.join(opts)) ++ print(' %s' % (', '.join(opts))) + if help: +- print '\n'.join( ++ print('\n'.join( + textwrap.wrap(help.strip(), + initial_indent=' ', +- subsequent_indent=' ')) +- print ++ subsequent_indent=' '))) ++ print() + + def usage(cls): + import nose +diff --git a/nose/ext/dtcompat.py b/nose/ext/dtcompat.py +index b5698c5..56a4c5f 100644 +--- a/nose/ext/dtcompat.py ++++ b/nose/ext/dtcompat.py +@@ -104,7 +104,7 @@ import __future__ + import sys, traceback, inspect, linecache, os, re + import unittest, difflib, pdb, tempfile + import warnings +-from StringIO import StringIO ++from io import StringIO + + # Don't whine about the deprecated is_private function in this + # module's tests. +@@ -219,7 +219,7 @@ def _normalize_module(module, depth=2): + """ + if inspect.ismodule(module): + return module +- elif isinstance(module, (str, unicode)): ++ elif isinstance(module, str): + return __import__(module, globals(), locals(), ["*"]) + elif module is None: + return sys.modules[sys._getframe(depth).f_globals['__name__']] +@@ -341,9 +341,9 @@ class _OutputRedirectingPdb(pdb.Pdb): + # [XX] Normalize with respect to os.path.pardir? + def _module_relative_path(module, path): + if not inspect.ismodule(module): +- raise TypeError, 'Expected a module: %r' % module ++ raise TypeError('Expected a module: %r' % module) + if path.startswith('/'): +- raise ValueError, 'Module-relative files may not have absolute paths' ++ raise ValueError('Module-relative files may not have absolute paths') + + # Find the base directory for the path. + if hasattr(module, '__file__'): +@@ -457,7 +457,7 @@ class DocTest: + Create a new DocTest containing the given examples. The + DocTest's globals are initialized with a copy of `globs`. + """ +- assert not isinstance(examples, basestring), \ ++ assert not isinstance(examples, str), \ + "DocTest no longer accepts str; use DocTestParser instead" + self.examples = examples + self.docstring = docstring +@@ -856,7 +856,7 @@ class DocTestFinder: + if module is None: + return True + elif inspect.isfunction(object): +- return module.__dict__ is object.func_globals ++ return module.__dict__ is object.__globals__ + elif inspect.isclass(object): + # Some jython classes don't set __module__ + return module.__name__ == getattr(object, '__module__', None) +@@ -875,7 +875,7 @@ class DocTestFinder: + add them to `tests`. + """ + if self._verbose: +- print 'Finding tests in %s' % name ++ print('Finding tests in %s' % name) + + # If we've already processed this object, then ignore it. + if id(obj) in seen: +@@ -889,7 +889,7 @@ class DocTestFinder: + + # Look for tests in a module's contained objects. + if inspect.ismodule(obj) and self._recurse: +- for valname, val in obj.__dict__.items(): ++ for valname, val in list(obj.__dict__.items()): + # Check if this contained object should be ignored. + if self._filter(val, name, valname): + continue +@@ -902,14 +902,14 @@ class DocTestFinder: + + # Look for tests in a module's __test__ dictionary. + if inspect.ismodule(obj) and self._recurse: +- for valname, val in getattr(obj, '__test__', {}).items(): +- if not isinstance(valname, basestring): ++ for valname, val in list(getattr(obj, '__test__', {}).items()): ++ if not isinstance(valname, str): + raise ValueError("DocTestFinder.find: __test__ keys " + "must be strings: %r" % + (type(valname),)) + if not (inspect.isfunction(val) or inspect.isclass(val) or + inspect.ismethod(val) or inspect.ismodule(val) or +- isinstance(val, basestring)): ++ isinstance(val, str)): + raise ValueError("DocTestFinder.find: __test__ values " + "must be strings, functions, methods, " + "classes, or modules: %r" % +@@ -920,7 +920,7 @@ class DocTestFinder: + + # Look for tests in a class's contained objects. + if inspect.isclass(obj) and self._recurse: +- for valname, val in obj.__dict__.items(): ++ for valname, val in list(obj.__dict__.items()): + # Check if this contained object should be ignored. + if self._filter(val, name, valname): + continue +@@ -928,7 +928,7 @@ class DocTestFinder: + if isinstance(val, staticmethod): + val = getattr(obj, valname) + if isinstance(val, classmethod): +- val = getattr(obj, valname).im_func ++ val = getattr(obj, valname).__func__ + + # Recurse to methods, properties, and nested classes. + if ((inspect.isfunction(val) or inspect.isclass(val) or +@@ -945,7 +945,7 @@ class DocTestFinder: + """ + # Extract the object's docstring. If it doesn't have one, + # then return None (no test for this object). +- if isinstance(obj, basestring): ++ if isinstance(obj, str): + docstring = obj + else: + try: +@@ -953,7 +953,7 @@ class DocTestFinder: + docstring = '' + else: + docstring = obj.__doc__ +- if not isinstance(docstring, basestring): ++ if not isinstance(docstring, str): + docstring = str(docstring) + except (TypeError, AttributeError): + docstring = '' +@@ -1003,8 +1003,8 @@ class DocTestFinder: + break + + # Find the line number for functions & methods. +- if inspect.ismethod(obj): obj = obj.im_func +- if inspect.isfunction(obj): obj = obj.func_code ++ if inspect.ismethod(obj): obj = obj.__func__ ++ if inspect.isfunction(obj): obj = obj.__code__ + if inspect.istraceback(obj): obj = obj.tb_frame + if inspect.isframe(obj): obj = obj.f_code + if inspect.iscode(obj): +@@ -1143,7 +1143,7 @@ class DocTestRunner: + # to modify them). + original_optionflags = self.optionflags + +- SUCCESS, FAILURE, BOOM = range(3) # `outcome` state ++ SUCCESS, FAILURE, BOOM = list(range(3)) # `outcome` state + + check = self._checker.check_output + +@@ -1158,7 +1158,7 @@ class DocTestRunner: + # Merge in the example's options. + self.optionflags = original_optionflags + if example.options: +- for (optionflag, val) in example.options.items(): ++ for (optionflag, val) in list(example.options.items()): + if val: + self.optionflags |= optionflag + else: +@@ -1179,8 +1179,8 @@ class DocTestRunner: + # keyboard interrupts.) + try: + # Don't blink! This is where the user's code gets run. +- exec compile(example.source, filename, "single", +- compileflags, 1) in test.globs ++ exec(compile(example.source, filename, "single", ++ compileflags, 1), test.globs) + self.debugger.set_continue() # ==== Example Finished ==== + exception = None + except KeyboardInterrupt: +@@ -1341,7 +1341,7 @@ class DocTestRunner: + passed = [] + failed = [] + totalt = totalf = 0 +- for x in self._name2ft.items(): ++ for x in list(self._name2ft.items()): + name, (f, t) = x + assert f <= t + totalt += t +@@ -1354,28 +1354,28 @@ class DocTestRunner: + failed.append(x) + if verbose: + if notests: +- print len(notests), "items had no tests:" ++ print(len(notests), "items had no tests:") + notests.sort() + for thing in notests: +- print " ", thing ++ print(" ", thing) + if passed: +- print len(passed), "items passed all tests:" ++ print(len(passed), "items passed all tests:") + passed.sort() + for thing, count in passed: +- print " %3d tests in %s" % (count, thing) ++ print(" %3d tests in %s" % (count, thing)) + if failed: +- print self.DIVIDER +- print len(failed), "items had failures:" ++ print(self.DIVIDER) ++ print(len(failed), "items had failures:") + failed.sort() + for thing, (f, t) in failed: +- print " %3d of %3d in %s" % (f, t, thing) ++ print(" %3d of %3d in %s" % (f, t, thing)) + if verbose: +- print totalt, "tests in", len(self._name2ft), "items." +- print totalt - totalf, "passed and", totalf, "failed." ++ print(totalt, "tests in", len(self._name2ft), "items.") ++ print(totalt - totalf, "passed and", totalf, "failed.") + if totalf: +- print "***Test Failed***", totalf, "failures." ++ print("***Test Failed***", totalf, "failures.") + elif verbose: +- print "Test passed." ++ print("Test passed.") + return totalf, totalt + + #///////////////////////////////////////////////////////////////// +@@ -1383,10 +1383,10 @@ class DocTestRunner: + #///////////////////////////////////////////////////////////////// + def merge(self, other): + d = self._name2ft +- for name, (f, t) in other._name2ft.items(): ++ for name, (f, t) in list(other._name2ft.items()): + if name in d: +- print "*** DocTestRunner.merge: '" + name + "' in both" \ +- " testers; summing outcomes." ++ print("*** DocTestRunner.merge: '" + name + "' in both" \ ++ " testers; summing outcomes.") + f2, t2 = d[name] + f = f + f2 + t = t + t2 +@@ -1875,10 +1875,10 @@ class Tester: + def runstring(self, s, name): + test = DocTestParser().get_doctest(s, self.globs, name, None, None) + if self.verbose: +- print "Running string", name ++ print("Running string", name) + (f,t) = self.testrunner.run(test) + if self.verbose: +- print f, "of", t, "examples failed in string", name ++ print(f, "of", t, "examples failed in string", name) + return (f,t) + + def rundoc(self, object, name=None, module=None): +@@ -2245,9 +2245,9 @@ def debug_script(src, pm=False, globs=None): + + if pm: + try: +- execfile(srcfilename, globs, globs) ++ exec(compile(open(srcfilename, "rb").read(), srcfilename, 'exec'), globs, globs) + except: +- print sys.exc_info()[1] ++ print(sys.exc_info()[1]) + pdb.post_mortem(sys.exc_info()[2]) + else: + # Note that %r is vital here. '%s' instead can, e.g., cause +diff --git a/nose/failure.py b/nose/failure.py +index c5fabfd..dad5253 100644 +--- a/nose/failure.py ++++ b/nose/failure.py +@@ -36,7 +36,7 @@ class Failure(unittest.TestCase): + def runTest(self): + if self.tb is not None: + if is_base_exception(self.exc_val): +- raise self.exc_val, None, self.tb +- raise self.exc_class, self.exc_val, self.tb ++ raise self.exc_val.with_traceback(self.tb) ++ raise self.exc_class(self.exc_val).with_traceback(self.tb) + else: + raise self.exc_class(self.exc_val) +diff --git a/nose/inspector.py b/nose/inspector.py +index ad22c0c..d6b4a5a 100644 +--- a/nose/inspector.py ++++ b/nose/inspector.py +@@ -9,9 +9,9 @@ import textwrap + import tokenize + + try: +- from cStringIO import StringIO ++ from io import StringIO + except ImportError: +- from StringIO import StringIO ++ from io import StringIO + + log = logging.getLogger(__name__) + +@@ -38,7 +38,7 @@ def inspect_traceback(tb): + try: + for tok in tokenize.generate_tokens(src.readline): + exp(*tok) +- except tokenize.TokenError, e: ++ except tokenize.TokenError as e: + # this can happen if our inspectable region happens to butt up + # against the end of a construct like a docstring with the closing + # """ on separate line +diff --git a/nose/loader.py b/nose/loader.py +index 3744e54..17bcae3 100644 +--- a/nose/loader.py ++++ b/nose/loader.py +@@ -6,7 +6,7 @@ nose's test loader implements the same basic functionality as its + superclass, unittest.TestLoader, but extends it by more liberal + interpretations of what may be a test and how a test may be named. + """ +-from __future__ import generators ++ + + import logging + import os +@@ -113,7 +113,7 @@ class TestLoader(unittest.TestLoader): + return False + return sel.wantMethod(item) + +- cases = filter(wanted, dir(testCaseClass)) ++ cases = list(filter(wanted, dir(testCaseClass))) + + # add runTest if nothing else picked + if not cases and hasattr(testCaseClass, 'runTest'): +@@ -224,7 +224,7 @@ class TestLoader(unittest.TestLoader): + # Plugins can yield False to indicate that they were + # unable to load tests from a file, but it was not an + # error -- the file just had no tests to load. +- tests = filter(None, tests) ++ tests = [_f for _f in tests if _f] + return self.suiteClass(tests) + else: + # Nothing was able to even try to load from this file +@@ -274,7 +274,7 @@ class TestLoader(unittest.TestLoader): + # convert the unbound generator method + # into a bound method so it can be called below + if hasattr(generator, 'im_class'): +- cls = generator.im_class ++ cls = generator.__self__.__class__ + inst = cls() + method = generator.__name__ + generator = getattr(inst, method) +@@ -329,8 +329,7 @@ class TestLoader(unittest.TestLoader): + test_funcs.append(test) + sort_list(test_classes, lambda x: x.__name__) + sort_list(test_funcs, func_lineno) +- tests = map(lambda t: self.makeTest(t, parent=module), +- test_classes + test_funcs) ++ tests = [self.makeTest(t, parent=module) for t in test_classes + test_funcs] + + # Now, descend into packages + # FIXME can or should this be lazy? +diff --git a/nose/plugins/attrib.py b/nose/plugins/attrib.py +index 3d4422a..8ac9239 100644 +--- a/nose/plugins/attrib.py ++++ b/nose/plugins/attrib.py +@@ -118,7 +118,7 @@ def attr(*args, **kwargs): + def wrap_ob(ob): + for name in args: + setattr(ob, name, True) +- for name, value in kwargs.iteritems(): ++ for name, value in kwargs.items(): + setattr(ob, name, value) + return ob + return wrap_ob +@@ -280,7 +280,7 @@ class AttributeSelector(Plugin): + """Accept the method if its attributes match. + """ + try: +- cls = method.im_class ++ cls = method.__self__.__class__ + except AttributeError: + return False + return self.validateAttrib(method, cls) +diff --git a/nose/plugins/base.py b/nose/plugins/base.py +index f09beb6..0e1c68f 100644 +--- a/nose/plugins/base.py ++++ b/nose/plugins/base.py +@@ -67,7 +67,7 @@ class Plugin(object): + try: + self.options(parser, env) + self.can_configure = True +- except OptionConflictError, e: ++ except OptionConflictError as e: + warn("Plugin %s has conflicting option string: %s and will " + "be disabled" % (self, e), RuntimeWarning) + self.enabled = False +diff --git a/nose/plugins/capture.py b/nose/plugins/capture.py +index 888a552..fa2736a 100644 +--- a/nose/plugins/capture.py ++++ b/nose/plugins/capture.py +@@ -16,7 +16,7 @@ import traceback + from nose.plugins.base import Plugin + from nose.pyversion import exc_to_unicode, force_unicode + from nose.util import ln +-from StringIO import StringIO ++from io import StringIO + + + log = logging.getLogger(__name__) +@@ -111,17 +111,17 @@ class Capture(Plugin): + # from an exception raised while trying to get the captured output. + ev = exc_to_unicode(ev) + output = force_unicode(output) +- error_text = [ev, ln(u'>> begin captured stdout <<'), +- output, ln(u'>> end captured stdout <<')] ++ error_text = [ev, ln('>> begin captured stdout <<'), ++ output, ln('>> end captured stdout <<')] + if output_exc_info: +- error_text.extend([u'OUTPUT ERROR: Could not get captured output.', ++ error_text.extend(['OUTPUT ERROR: Could not get captured output.', + # + # +- u"The test might've printed both 'unicode' strings and non-ASCII 8-bit 'str' strings.", +- ln(u'>> begin captured stdout exception traceback <<'), +- u''.join(traceback.format_exception(*output_exc_info)), +- ln(u'>> end captured stdout exception traceback <<')]) +- return u'\n'.join(error_text) ++ "The test might've printed both 'unicode' strings and non-ASCII 8-bit 'str' strings.", ++ ln('>> begin captured stdout exception traceback <<'), ++ ''.join(traceback.format_exception(*output_exc_info)), ++ ln('>> end captured stdout exception traceback <<')]) ++ return '\n'.join(error_text) + + def start(self): + self.stdout.append(sys.stdout) +diff --git a/nose/plugins/cover.py b/nose/plugins/cover.py +index b9bfc82..24bf535 100644 +--- a/nose/plugins/cover.py ++++ b/nose/plugins/cover.py +@@ -13,7 +13,7 @@ variable. + import logging + import re + import sys +-import StringIO ++import io + from nose.plugins.base import Plugin + from nose.util import src, tolist + +@@ -145,7 +145,7 @@ class Coverage(Plugin): + self.coverInstance.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]') + + log.debug("Coverage begin") +- self.skipModules = sys.modules.keys()[:] ++ self.skipModules = list(sys.modules.keys())[:] + if self.coverErase: + log.debug("Clearing previously collected coverage statistics") + self.coverInstance.combine() +@@ -184,7 +184,7 @@ class Coverage(Plugin): + self.coverInstance.combine() + self.coverInstance.save() + modules = [module +- for name, module in sys.modules.items() ++ for name, module in list(sys.modules.items()) + if self.wantModuleCoverage(name, module)] + log.debug("Coverage report will cover modules: %s", modules) + self.coverInstance.report(modules, file=stream, show_missing=True) +@@ -194,19 +194,19 @@ class Coverage(Plugin): + log.debug("Generating HTML coverage report") + try: + self.coverInstance.html_report(modules, self.coverHtmlDir) +- except coverage.misc.CoverageException, e: ++ except coverage.misc.CoverageException as e: + log.warning("Failed to generate HTML report: %s" % str(e)) + + if self.coverXmlFile: + log.debug("Generating XML coverage report") + try: + self.coverInstance.xml_report(modules, self.coverXmlFile) +- except coverage.misc.CoverageException, e: ++ except coverage.misc.CoverageException as e: + log.warning("Failed to generate XML report: %s" % str(e)) + + # make sure we have minimum required coverage + if self.coverMinPercentage: +- f = StringIO.StringIO() ++ f = io.StringIO() + self.coverInstance.report(modules, file=f, show_missing=True) + + multiPackageRe = (r'-------\s\w+\s+\d+\s+\d+(?:\s+\d+\s+\d+)?' +diff --git a/nose/plugins/doctests.py b/nose/plugins/doctests.py +index 528cd63..32736b6 100644 +--- a/nose/plugins/doctests.py ++++ b/nose/plugins/doctests.py +@@ -47,7 +47,7 @@ test. + additional documentation and examples. + + """ +-from __future__ import generators ++ + + import codecs + import logging +@@ -60,11 +60,11 @@ from nose.suite import ContextList + from nose.util import anyp, getpackage, test_address, resolve_name, \ + src, tolist, isproperty + try: +- from cStringIO import StringIO ++ from io import StringIO + except ImportError: +- from StringIO import StringIO ++ from io import StringIO + import sys +-import __builtin__ as builtin_mod ++import builtins as builtin_mod + + log = logging.getLogger(__name__) + +@@ -276,7 +276,7 @@ class Doctest(Plugin): + try: + fixture_context = __import__( + fixt_mod, globals(), locals(), ["nop"]) +- except ImportError, e: ++ 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", +@@ -322,13 +322,11 @@ class Doctest(Plugin): + # FIXME don't think we need include/exclude checks here? + return ((self.doctest_tests or not self.conf.testMatch.search(name) + or (self.conf.include +- and filter(None, +- [inc.search(name) +- for inc in self.conf.include]))) ++ and [_f for _f in [inc.search(name) ++ for inc in self.conf.include] if _f])) + and (not self.conf.exclude +- or not filter(None, +- [exc.search(name) +- for exc in self.conf.exclude]))) ++ or not [_f for _f in [exc.search(name) ++ for exc in self.conf.exclude] if _f])) + + def wantFile(self, file): + """Override to select all modules and any file ending with +@@ -341,9 +339,8 @@ class Doctest(Plugin): + if (self.extension + and anyp(file.endswith, self.extension) + and (not self.conf.exclude +- or not filter(None, +- [exc.search(file) +- for exc in self.conf.exclude]))): ++ or not [_f for _f in [exc.search(file) ++ for exc in self.conf.exclude] if _f])): + return True + return None + +@@ -414,7 +411,7 @@ class DocTestCase(doctest.DocTestCase): + if value is None: + return + setattr(builtin_mod, self._result_var, value) +- print repr(value) ++ print(repr(value)) + + def tearDown(self): + super(DocTestCase, self).tearDown() +@@ -447,7 +444,7 @@ class DocFileCase(doctest.DocFileCase): + if value is None: + return + setattr(builtin_mod, self._result_var, value) +- print repr(value) ++ print(repr(value)) + + def tearDown(self): + super(DocFileCase, self).tearDown() +diff --git a/nose/plugins/errorclass.py b/nose/plugins/errorclass.py +index 38ecec9..0e0927d 100644 +--- a/nose/plugins/errorclass.py ++++ b/nose/plugins/errorclass.py +@@ -114,7 +114,7 @@ class MetaErrorClass(type): + """ + def __init__(self, name, bases, attr): + errorClasses = [] +- for name, detail in attr.items(): ++ for name, detail in list(attr.items()): + if isinstance(detail, ErrorClass): + attr.pop(name) + for cls in detail: +@@ -138,12 +138,11 @@ class ErrorClass(object): + return iter(self.errorClasses) + + +-class ErrorClassPlugin(Plugin): ++class ErrorClassPlugin(Plugin, metaclass=MetaErrorClass): + """ + Base class for ErrorClass plugins. Subclass this class and declare the + exceptions that you wish to handle as attributes of the subclass. + """ +- __metaclass__ = MetaErrorClass + score = 1000 + errorClasses = () + +@@ -152,7 +151,7 @@ class ErrorClassPlugin(Plugin): + if not isclass(err_cls): + return + classes = [e[0] for e in self.errorClasses] +- if filter(lambda c: issubclass(err_cls, c), classes): ++ if [c for c in classes if issubclass(err_cls, c)]: + return True + + def prepareTestResult(self, result): +diff --git a/nose/plugins/isolate.py b/nose/plugins/isolate.py +index 13235df..77a2de5 100644 +--- a/nose/plugins/isolate.py ++++ b/nose/plugins/isolate.py +@@ -72,7 +72,7 @@ class IsolationPlugin(Plugin): + it was in when mod stack was pushed. + """ + mods = self._mod_stack.pop() +- to_del = [ m for m in sys.modules.keys() if m not in mods ] ++ to_del = [ m for m in list(sys.modules.keys()) if m not in mods ] + if to_del: + log.debug('removing sys modules entries: %s', to_del) + for mod in to_del: +diff --git a/nose/plugins/logcapture.py b/nose/plugins/logcapture.py +index 4c9a79f..2af79ad 100644 +--- a/nose/plugins/logcapture.py ++++ b/nose/plugins/logcapture.py +@@ -23,9 +23,9 @@ from nose.plugins.base import Plugin + from nose.util import anyp, ln, safe_str + + try: +- from cStringIO import StringIO ++ from io import StringIO + except ImportError: +- from StringIO import StringIO ++ from io import StringIO + + log = logging.getLogger(__name__) + +@@ -57,7 +57,7 @@ class FilterSet(object): + any item in `matchers`""" + def record_matches_key(key): + return record == key or record.startswith(key + '.') +- return anyp(bool, map(record_matches_key, matchers)) ++ return anyp(bool, list(map(record_matches_key, matchers))) + _any_match = staticmethod(_any_match) + + def _allow(self, record): +@@ -180,7 +180,7 @@ class LogCapture(Plugin): + if hasattr(root_logger, "handlers"): + for handler in root_logger.handlers: + root_logger.removeHandler(handler) +- for logger in logging.Logger.manager.loggerDict.values(): ++ for logger in list(logging.Logger.manager.loggerDict.values()): + if hasattr(logger, "handlers"): + for handler in logger.handlers: + logger.removeHandler(handler) +@@ -237,7 +237,7 @@ class LogCapture(Plugin): + return (ec, self.addCaptureToErr(ev, records), tb) + + def formatLogRecords(self): +- return map(safe_str, self.handler.buffer) ++ return list(map(safe_str, self.handler.buffer)) + + def addCaptureToErr(self, ev, records): + return '\n'.join([safe_str(ev), ln('>> begin captured logging <<')] + \ +diff --git a/nose/plugins/manager.py b/nose/plugins/manager.py +index daa9edb..52a7c96 100644 +--- a/nose/plugins/manager.py ++++ b/nose/plugins/manager.py +@@ -60,13 +60,13 @@ from nose.plugins.base import IPluginInterface + from nose.pyversion import sort_list + + try: +- import cPickle as pickle ++ import pickle as pickle + except: + import pickle + try: +- from cStringIO import StringIO ++ from io import StringIO + except: +- from StringIO import StringIO ++ from io import StringIO + + + __all__ = ['DefaultPluginManager', 'PluginManager', 'EntryPointPluginManager', +@@ -387,7 +387,7 @@ class EntryPointPluginManager(PluginManager): + plugcls = ep.load() + except KeyboardInterrupt: + raise +- except Exception, e: ++ except Exception as e: + # never want a plugin load to kill the test run + # but we can't log here because the logger is not yet + # configured +diff --git a/nose/plugins/multiprocess.py b/nose/plugins/multiprocess.py +index 2cae744..a0c53c6 100644 +--- a/nose/plugins/multiprocess.py ++++ b/nose/plugins/multiprocess.py +@@ -115,12 +115,12 @@ try: + from unittest.runner import _WritelnDecorator + except ImportError: + from unittest import _WritelnDecorator +-from Queue import Empty ++from queue import Empty + from warnings import warn + try: +- from cStringIO import StringIO ++ from io import StringIO + except ImportError: +- import StringIO ++ import io + + # this is a list of plugin classes that will be checked for and created inside + # each worker process +@@ -478,7 +478,7 @@ class MultiProcessTestRunner(TextTestRunner): + self.config.multiprocess_timeout-timeprocessing) + log.debug("Completed %s tasks (%s remain)", len(completed), len(tasks)) + +- except (KeyboardInterrupt, SystemExit), e: ++ except (KeyboardInterrupt, SystemExit) as e: + log.info('parent received ctrl-c when waiting for test results') + thrownError = e + #resultQueue.get(False) +@@ -633,7 +633,7 @@ class MultiProcessTestRunner(TextTestRunner): + result.testsRun += testsRun + result.failures.extend(failures) + result.errors.extend(errors) +- for key, (storage, label, isfail) in errorClasses.items(): ++ for key, (storage, label, isfail) in list(errorClasses.items()): + if key not in result.errorClasses: + # Ordinarily storage is result attribute + # but it's only processed through the errorClasses +@@ -688,7 +688,7 @@ def __runner(ix, testQueue, resultQueue, currentaddr, currentstart, + failures = [(TestLet(c), err) for c, err in result.failures] + errors = [(TestLet(c), err) for c, err in result.errors] + errorClasses = {} +- for key, (storage, label, isfail) in result.errorClasses.items(): ++ for key, (storage, label, isfail) in list(result.errorClasses.items()): + errorClasses[key] = ([(TestLet(c), err) for c, err in storage], + label, isfail) + return ( +@@ -715,7 +715,7 @@ def __runner(ix, testQueue, resultQueue, currentaddr, currentstart, + test(result) + currentaddr.value = bytes_('') + resultQueue.put((ix, test_addr, test.tasks, batch(result))) +- except KeyboardInterrupt, e: #TimedOutException: ++ except KeyboardInterrupt as e: #TimedOutException: + timeout = isinstance(e, TimedOutException) + if timeout: + keyboardCaught.set() +@@ -810,7 +810,7 @@ class NoSharedFixtureContextSuite(ContextSuite): + #log.debug('running test %s in suite %s', test, self); + try: + test(orig) +- except KeyboardInterrupt, e: ++ except KeyboardInterrupt as e: + timeout = isinstance(e, TimedOutException) + if timeout: + msg = 'Timeout when running test %s in suite %s' +diff --git a/nose/plugins/plugintest.py b/nose/plugins/plugintest.py +index 76d0d2c..00b67f5 100644 +--- a/nose/plugins/plugintest.py ++++ b/nose/plugins/plugintest.py +@@ -100,9 +100,9 @@ import sys + from warnings import warn + + try: +- from cStringIO import StringIO ++ from io import StringIO + except ImportError: +- from StringIO import StringIO ++ from io import StringIO + + __all__ = ['PluginTester', 'run'] + +@@ -135,7 +135,7 @@ class MultiProcessFile(object): + if getpid() != self.__master: + return + +- from Queue import Empty ++ from queue import Empty + from collections import defaultdict + cache = defaultdict(str) + while True: +@@ -404,7 +404,7 @@ def run(*arg, **kw): + sys.stderr = stderr + sys.stdout = stdout + out = buffer.getvalue() +- print munge_nose_output_for_doctest(out) ++ print(munge_nose_output_for_doctest(out)) + + + def run_buffered(*arg, **kw): +diff --git a/nose/plugins/testid.py b/nose/plugins/testid.py +index ae8119b..caa4c5b 100644 +--- a/nose/plugins/testid.py ++++ b/nose/plugins/testid.py +@@ -100,7 +100,7 @@ from nose.plugins import Plugin + from nose.util import src, set + + try: +- from cPickle import dump, load ++ from pickle import dump, load + except ImportError: + from pickle import dump, load + +@@ -198,7 +198,7 @@ class TestId(Plugin): + self.ids, self.tests, self.failed, self.source_names, + self.idfile) + fh.close() +- except ValueError, e: ++ except ValueError as e: + # load() may throw a ValueError when reading the ids file, if it + # was generated with a newer version of Python than we are currently + # running. +diff --git a/nose/plugins/xunit.py b/nose/plugins/xunit.py +index 90b52f5..c42567f 100644 +--- a/nose/plugins/xunit.py ++++ b/nose/plugins/xunit.py +@@ -46,7 +46,7 @@ import sys + import traceback + import re + import inspect +-from StringIO import StringIO ++from io import StringIO + from time import time + from xml.sax import saxutils + +@@ -110,7 +110,7 @@ def exc_message(exc_info): + result = str(exc) + except UnicodeEncodeError: + try: +- result = unicode(exc) ++ result = str(exc) + except UnicodeError: + # Fallback to args as neither str nor + # unicode(Exception(u'\xe6')) work in Python < 2.6 +@@ -213,13 +213,13 @@ class Xunit(Plugin): + self.stats['total'] = (self.stats['errors'] + self.stats['failures'] + + self.stats['passes'] + self.stats['skipped']) + self.error_report_file.write( +- u'' +- u'' % self.stats) +- self.error_report_file.write(u''.join([force_unicode(e, self.encoding) ++ '' ++ '' % self.stats) ++ self.error_report_file.write(''.join([force_unicode(e, self.encoding) + for e in self.errorlist])) +- self.error_report_file.write(u'') ++ self.error_report_file.write('') + self.error_report_file.close() + if self.config.verbosity > 1: + stream.writeln("-" * 70) +@@ -288,9 +288,9 @@ class Xunit(Plugin): + id = test.id() + + self.errorlist.append( +- u'' +- u'<%(type)s type=%(errtype)s message=%(message)s>' +- u'%(systemout)s%(systemerr)s' % ++ '' ++ '<%(type)s type=%(errtype)s message=%(message)s>' ++ '%(systemout)s%(systemerr)s' % + {'cls': self._quoteattr(id_split(id)[0]), + 'name': self._quoteattr(id_split(id)[-1]), + 'taken': taken, +@@ -311,9 +311,9 @@ class Xunit(Plugin): + id = test.id() + + self.errorlist.append( +- u'' +- u'' +- u'%(systemout)s%(systemerr)s' % ++ '' ++ '' ++ '%(systemout)s%(systemerr)s' % + {'cls': self._quoteattr(id_split(id)[0]), + 'name': self._quoteattr(id_split(id)[-1]), + 'taken': taken, +diff --git a/nose/pyversion.py b/nose/pyversion.py +index 091238d..3de934d 100644 +--- a/nose/pyversion.py ++++ b/nose/pyversion.py +@@ -16,12 +16,12 @@ __all__ = ['make_instancemethod', 'cmp_to_key', 'sort_list', 'ClassType', + # In Python 3.x, all strings are unicode (the call to 'unicode()' in the 2.x + # source will be replaced with 'str()' when running 2to3, so this test will + # then become true) +-UNICODE_STRINGS = (type(unicode()) == type(str())) ++UNICODE_STRINGS = (type(str()) == type(str())) + + if sys.version_info[:2] < (3, 0): + def force_unicode(s, encoding='UTF-8'): + try: +- s = unicode(s) ++ s = str(s) + except UnicodeDecodeError: + s = str(s).decode(encoding, 'replace') + +@@ -35,7 +35,7 @@ else: + try: + import new + def make_instancemethod(function, instance): +- return new.instancemethod(function.im_func, instance, ++ return new.instancemethod(function.__func__, instance, + instance.__class__) + except ImportError: + def make_instancemethod(function, instance): +@@ -73,8 +73,8 @@ else: + # thus types.ClassType and types.TypeType don't exist anymore. For + # compatibility, we make sure they still work. + if hasattr(types, 'ClassType'): +- ClassType = types.ClassType +- TypeType = types.TypeType ++ ClassType = type ++ TypeType = type + else: + ClassType = type + TypeType = type +@@ -90,7 +90,7 @@ class UnboundMethod: + self._func = func + self.__self__ = UnboundSelf(cls) + if sys.version_info < (3, 0): +- self.im_class = cls ++ self.__self__.__class__ = cls + self.__doc__ = getattr(func, '__doc__', None) + + def address(self): +@@ -161,7 +161,7 @@ else: + + def isgenerator(func): + try: +- return func.func_code.co_flags & CO_GENERATOR != 0 ++ return func.__code__.co_flags & CO_GENERATOR != 0 + except AttributeError: + return False + +@@ -187,8 +187,8 @@ if sys.version_info[:2] < (3, 0): + msg = force_unicode(msg, encoding=encoding) + clsname = force_unicode(ev.__class__.__name__, + encoding=encoding) +- ev = u'%s: %s' % (clsname, msg) +- elif not isinstance(ev, unicode): ++ ev = '%s: %s' % (clsname, msg) ++ elif not isinstance(ev, str): + ev = repr(ev) + + return force_unicode(ev, encoding=encoding) +diff --git a/nose/result.py b/nose/result.py +index 228a42c..518fa65 100644 +--- a/nose/result.py ++++ b/nose/result.py +@@ -62,7 +62,7 @@ class TextTestResult(_TextTestResult): + except TypeError: + # 2.3 compat + exc_info = self._exc_info_to_string(err) +- for cls, (storage, label, isfail) in self.errorClasses.items(): ++ for cls, (storage, label, isfail) in list(self.errorClasses.items()): + #if 'Skip' in cls.__name__ or 'Skip' in ec.__name__: + # from nose.tools import set_trace + # set_trace() +@@ -101,7 +101,7 @@ class TextTestResult(_TextTestResult): + """Overrides to print all errorClasses errors as well. + """ + _TextTestResult.printErrors(self) +- for cls in self.errorClasses.keys(): ++ for cls in list(self.errorClasses.keys()): + storage, label, isfail = self.errorClasses[cls] + if isfail: + self.printErrorList(label, storage) +@@ -124,7 +124,7 @@ class TextTestResult(_TextTestResult): + writeln() + + summary = {} +- eckeys = self.errorClasses.keys() ++ eckeys = list(self.errorClasses.keys()) + for cls in eckeys: + storage, label, isfail = self.errorClasses[cls] + count = len(storage) +@@ -140,7 +140,7 @@ class TextTestResult(_TextTestResult): + write("FAILED") + else: + write("OK") +- items = summary.items() ++ items = list(summary.items()) + if items: + items.sort() + write(" (") +@@ -157,7 +157,7 @@ class TextTestResult(_TextTestResult): + """ + if self.errors or self.failures: + return False +- for cls in self.errorClasses.keys(): ++ for cls in list(self.errorClasses.keys()): + storage, label, isfail = self.errorClasses[cls] + if not isfail: + continue +diff --git a/nose/selector.py b/nose/selector.py +index b63f7af..0764282 100644 +--- a/nose/selector.py ++++ b/nose/selector.py +@@ -52,11 +52,9 @@ class Selector(object): + """ + return ((self.match.search(name) + or (self.include and +- filter(None, +- [inc.search(name) for inc in self.include]))) ++ [_f for _f in [inc.search(name) for inc in self.include] if _f])) + and ((not self.exclude) +- or not filter(None, +- [exc.search(name) for exc in self.exclude]) ++ or not [_f for _f in [exc.search(name) for exc in self.exclude] if _f] + )) + + def wantClass(self, cls): +@@ -89,9 +87,7 @@ class Selector(object): + tail = op_basename(dirname) + if ispackage(dirname): + wanted = (not self.exclude +- or not filter(None, +- [exc.search(tail) for exc in self.exclude] +- )) ++ or not [_f for _f in [exc.search(tail) for exc in self.exclude] if _f]) + else: + wanted = (self.matches(tail) + or (self.config.srcDirs +diff --git a/nose/suite.py b/nose/suite.py +index a831105..20dc21c 100644 +--- a/nose/suite.py ++++ b/nose/suite.py +@@ -7,7 +7,7 @@ function, and ContextSuite,which can run fixtures (setup/teardown + functions or methods) for the context that contains its tests. + + """ +-from __future__ import generators ++ + + import logging + import sys +@@ -75,14 +75,14 @@ class LazySuite(unittest.TestSuite): + test(result) + return result + +- def __nonzero__(self): ++ def __bool__(self): + log.debug("tests in %s?", id(self)) + if self._precache: + return True + if self.test_generator is None: + return False + try: +- test = self.test_generator.next() ++ test = next(self.test_generator) + if test is not None: + self._precache.append(test) + return True +@@ -439,7 +439,7 @@ class ContextSuiteFactory(object): + # don't want that, instead want the module the class is in now + # (classes are re-ancestored elsewhere). + if hasattr(context, 'im_class'): +- context = context.im_class ++ context = context.__self__.__class__ + elif hasattr(context, '__self__'): + context = context.__self__.__class__ + if hasattr(context, '__module__'): +diff --git a/nose/tools/nontrivial.py b/nose/tools/nontrivial.py +index 2839732..62e221e 100644 +--- a/nose/tools/nontrivial.py ++++ b/nose/tools/nontrivial.py +@@ -26,7 +26,7 @@ def make_decorator(func): + newfunc.__doc__ = func.__doc__ + newfunc.__module__ = func.__module__ + if not hasattr(newfunc, 'compat_co_firstlineno'): +- newfunc.compat_co_firstlineno = func.func_code.co_firstlineno ++ newfunc.compat_co_firstlineno = func.__code__.co_firstlineno + try: + newfunc.__name__ = name + except TypeError: +diff --git a/nose/twistedtools.py b/nose/twistedtools.py +index 8d9c6ff..9239307 100644 +--- a/nose/twistedtools.py ++++ b/nose/twistedtools.py +@@ -29,7 +29,7 @@ Or, more realistically:: + """ + + import sys +-from Queue import Queue, Empty ++from queue import Queue, Empty + from nose.tools import make_decorator, TimeExpired + + __all__ = [ +@@ -166,7 +166,7 @@ def deferred(timeout=None): + # Re-raise all exceptions + if error is not None: + exc_type, exc_value, tb = error +- raise exc_type, exc_value, tb ++ raise exc_type(exc_value).with_traceback(tb) + wrapper = make_decorator(func)(wrapper) + return wrapper + return decorate +diff --git a/nose/util.py b/nose/util.py +index 21770ae..c38e5e0 100644 +--- a/nose/util.py ++++ b/nose/util.py +@@ -151,7 +151,7 @@ def func_lineno(func): + return func.compat_co_firstlineno + except AttributeError: + try: +- return func.func_code.co_firstlineno ++ return func.__code__.co_firstlineno + except AttributeError: + return -1 + +@@ -400,7 +400,7 @@ def test_address(test): + file = getattr(test, '__file__', None) + module = getattr(test, '__name__', None) + return (src(file), module, call) +- if t == types.FunctionType or issubclass(t, type) or t == types.ClassType: ++ if t == types.FunctionType or issubclass(t, type) or t == type: + module = getattr(test, '__module__', None) + if module is not None: + m = sys.modules[module] +@@ -410,7 +410,7 @@ def test_address(test): + call = getattr(test, '__name__', None) + return (src(file), module, call) + if t == types.MethodType: +- cls_adr = test_address(test.im_class) ++ cls_adr = test_address(test.__self__.__class__) + return (src(cls_adr[0]), cls_adr[1], + "%s.%s" % (cls_adr[2], test.__name__)) + # handle unittest.TestCase instances +@@ -552,7 +552,7 @@ class odict(dict): + self._keys.append(key) + + def __str__(self): +- return "{%s}" % ', '.join(["%r: %r" % (k, v) for k, v in self.items()]) ++ return "{%s}" % ', '.join(["%r: %r" % (k, v) for k, v in list(self.items())]) + + def clear(self): + super(odict, self).clear() +@@ -564,7 +564,7 @@ class odict(dict): + return d + + def items(self): +- return zip(self._keys, self.values()) ++ return list(zip(self._keys, list(self.values()))) + + def keys(self): + return self._keys[:] +@@ -577,12 +577,12 @@ class odict(dict): + + def update(self, dict): + super(odict, self).update(dict) +- for key in dict.keys(): ++ for key in list(dict.keys()): + if key not in self._keys: + self._keys.append(key) + + def values(self): +- return map(self.get, self._keys) ++ return list(map(self.get, self._keys)) + + + def transplant_func(func, module): +@@ -654,7 +654,7 @@ def safe_str(val, encoding='utf-8'): + if isinstance(val, Exception): + return ' '.join([safe_str(arg, encoding) + for arg in val]) +- return unicode(val).encode(encoding) ++ return str(val).encode(encoding) + + + def is_executable(file): +diff --git a/patch.py b/patch.py +index 981097c..1152e8d 100644 +--- a/patch.py ++++ b/patch.py +@@ -26,7 +26,7 @@ import sys + + try: + # cStringIO doesn't support unicode in 2.5 +- from StringIO import StringIO ++ from io import StringIO + except ImportError: + # StringIO has been renamed to 'io' in 3.x + from io import StringIO +@@ -48,7 +48,7 @@ else: + # Python 3.x has changed iter.next() to be next(iter) instead, so for + # backwards compatibility, we'll just define a next() function under 2.x + def next(iter): +- return iter.next() ++ return iter.__next__() + + + #------------------------------------------------ +diff --git a/unit_tests/mock.py b/unit_tests/mock.py +index 9da9e12..3f8868e 100644 +--- a/unit_tests/mock.py ++++ b/unit_tests/mock.py +@@ -28,27 +28,27 @@ class ResultProxy(proxy.ResultProxy): + self.assertMyTest(test) + self.called.append(('beforeTest', test)) + def startTest(self, test): +- print "proxy startTest" ++ print("proxy startTest") + self.assertMyTest(test) + self.called.append(('startTest', test)) + def stopTest(self, test): +- print "proxy stopTest" ++ print("proxy stopTest") + self.assertMyTest(test) + self.called.append(('stopTest', test)) + def addDeprecated(self, test, err): +- print "proxy addDeprecated" ++ print("proxy addDeprecated") + self.assertMyTest(test) + self.called.append(('addDeprecated', test, err)) + def addError(self, test, err): +- print "proxy addError" ++ print("proxy addError") + self.assertMyTest(test) + self.called.append(('addError', test, err)) + def addFailure(self, test, err): +- print "proxy addFailure" ++ print("proxy addFailure") + self.assertMyTest(test) + self.called.append(('addFailure', test, err)) + def addSkip(self, test, err): +- print "proxy addSkip" ++ print("proxy addSkip") + self.assertMyTest(test) + self.called.append(('addSkip', test, err)) + def addSuccess(self, test): +@@ -72,7 +72,7 @@ class RecordingPluginManager(object): + self.called = odict() + + def calls(self): +- return self.called.keys() ++ return list(self.called.keys()) + + + class RecordingPluginProxy(object): +@@ -92,7 +92,7 @@ class Bucket(object): + self.__dict__['d'].update(kw) + + def __getattr__(self, attr): +- if not self.__dict__.has_key('d'): ++ if 'd' not in self.__dict__: + return None + return self.__dict__['d'].get(attr) + +diff --git a/unit_tests/support/issue135/tests.py b/unit_tests/support/issue135/tests.py +index f76f4fa..d312e41 100644 +--- a/unit_tests/support/issue135/tests.py ++++ b/unit_tests/support/issue135/tests.py +@@ -2,5 +2,5 @@ import unittest + + class TestIssue135(unittest.TestCase): + def test_issue135(self): +- print "something" ++ print("something") + raise KeyError("fake") +\ No newline at end of file +diff --git a/unit_tests/support/script.py b/unit_tests/support/script.py +index 9e33d77..26772f5 100755 +--- a/unit_tests/support/script.py ++++ b/unit_tests/support/script.py +@@ -1,3 +1,3 @@ + #!/usr/bin/env python + +-print "FAIL" ++print("FAIL") +diff --git a/unit_tests/test_bug105.py b/unit_tests/test_bug105.py +index e0362a8..0c007b0 100644 +--- a/unit_tests/test_bug105.py ++++ b/unit_tests/test_bug105.py +@@ -10,8 +10,8 @@ class TestBug105(unittest.TestCase): + 'support', 'bug105')) + + l = TestLoader() +- testmod = l.loadTestsFromDir(where).next() +- print testmod ++ testmod = next(l.loadTestsFromDir(where)) ++ print(testmod) + testmod.setUp() + + def fix(t): +@@ -20,8 +20,8 @@ class TestBug105(unittest.TestCase): + return s[s.index(': ')+2:] + return s + +- tests = map(fix, testmod) +- print tests ++ tests = list(map(fix, testmod)) ++ print(tests) + self.assertEqual(tests, ['tests.test_z', 'tests.test_a', + 'tests.test_dz', 'tests.test_mdz', + 'tests.test_b']) +diff --git a/unit_tests/test_capture_plugin.py b/unit_tests/test_capture_plugin.py +index c8cff82..534f84f 100644 +--- a/unit_tests/test_capture_plugin.py ++++ b/unit_tests/test_capture_plugin.py +@@ -57,14 +57,14 @@ class TestCapturePlugin(unittest.TestCase): + def test_captures_stdout(self): + c = Capture() + c.start() +- print "Hello" ++ print("Hello") + c.end() + self.assertEqual(c.buffer, "Hello\n") + + def test_captures_nonascii_stdout(self): + c = Capture() + c.start() +- print "test 日本" ++ print("test 日本") + c.end() + self.assertEqual(c.buffer, "test 日本\n") + +@@ -76,8 +76,8 @@ class TestCapturePlugin(unittest.TestCase): + c.start() + printed_nonascii_str = force_unicode("test 日本").encode('utf-8') + printed_unicode = force_unicode("Hello") +- print printed_nonascii_str +- print printed_unicode ++ print(printed_nonascii_str) ++ print(printed_unicode) + try: + raise Exception("boom") + except: +@@ -104,7 +104,7 @@ class TestCapturePlugin(unittest.TestCase): + c = Capture() + c.start() + try: +- print "Oh my!" ++ print("Oh my!") + raise Exception("boom") + except: + err = sys.exc_info() +@@ -125,8 +125,8 @@ class TestCapturePlugin(unittest.TestCase): + c = Capture() + c.start() + try: +- print "debug 日本" +- raise AssertionError(u'response does not contain 名') ++ print("debug 日本") ++ raise AssertionError('response does not contain 名') + except: + err = sys.exc_info() + formatted = c.formatError(d, err) +diff --git a/unit_tests/test_cases.py b/unit_tests/test_cases.py +index af399e5..7df472f 100644 +--- a/unit_tests/test_cases.py ++++ b/unit_tests/test_cases.py +@@ -40,8 +40,7 @@ class TestNoseCases(unittest.TestCase): + def __new__(cls, name, bases, dct): + return type.__new__(cls, name, bases, dct) + a = [] +- class TestClass(object): +- __metaclass__ = TestType ++ class TestClass(object, metaclass=TestType): + def test_func(self, a=a): + a.append(1) + +@@ -124,13 +123,13 @@ class TestNoseTestWrapper(unittest.TestCase): + + class TC(unittest.TestCase): + def setUp(self): +- print "TC setUp %s" % self ++ print("TC setUp %s" % self) + called.append('setUp') + def runTest(self): +- print "TC runTest %s" % self ++ print("TC runTest %s" % self) + called.append('runTest') + def tearDown(self): +- print "TC tearDown %s" % self ++ print("TC tearDown %s" % self) + called.append('tearDown') + + case = nose.case.Test(TC()) +diff --git a/unit_tests/test_config_defaults.rst b/unit_tests/test_config_defaults.rst +index 034f58e..9b4673e 100644 +--- a/unit_tests/test_config_defaults.rst ++++ b/unit_tests/test_config_defaults.rst +@@ -1,6 +1,6 @@ + >>> from optparse import OptionParser + >>> import os +- >>> from cStringIO import StringIO ++ >>> from io import StringIO + + >>> import nose.config + +@@ -12,7 +12,7 @@ configuration files. The configuration lives in a single section + ... "config_defaults") + + >>> def error(msg): +- ... print "error: %s" % msg ++ ... print("error: %s" % msg) + + >>> def get_parser(): + ... parser = OptionParser() +@@ -129,18 +129,19 @@ Missing config files don't deserve an error or warning + (filename) + + >>> options, args = parse([], os.path.join(support, "nonexistent.cfg")) +- >>> print options.__dict__ ++ >>> print(options.__dict__) + {'verbosity': 1} + + (filenames) + + >>> options, args = parse([], [os.path.join(support, "nonexistent.cfg")]) +- >>> print options.__dict__ ++ >>> print(options.__dict__) + {'verbosity': 1} + + + The same goes for missing config file section ("nosetests") + + >>> options, args = parse([], StringIO("[spam]\nfoo=bar\n")) +- >>> print options.__dict__ ++ >>> print(options.__dict__) + {'verbosity': 1} ++ +diff --git a/unit_tests/test_core.py b/unit_tests/test_core.py +index 94b9436..735285c 100644 +--- a/unit_tests/test_core.py ++++ b/unit_tests/test_core.py +@@ -1,7 +1,7 @@ + import os + import sys + import unittest +-from cStringIO import StringIO ++from io import StringIO + from optparse import OptionParser + import nose.core + from nose.config import Config, all_config_files +@@ -16,16 +16,16 @@ class NullLoader: + class TestAPI_run(unittest.TestCase): + + def test_restore_stdout(self): +- print "AHOY" ++ print("AHOY") + s = StringIO() +- print s ++ print(s) + stdout = sys.stdout + conf = Config(stream=s) + # set_trace() +- print "About to run" ++ print("About to run") + res = nose.core.run( + testLoader=NullLoader(), argv=['test_run'], env={}, config=conf) +- print "Done running" ++ print("Done running") + stdout_after = sys.stdout + self.assertEqual(stdout, stdout_after) + +diff --git a/unit_tests/test_deprecated_plugin.py b/unit_tests/test_deprecated_plugin.py +index 6c62481..e113016 100644 +--- a/unit_tests/test_deprecated_plugin.py ++++ b/unit_tests/test_deprecated_plugin.py +@@ -2,7 +2,7 @@ import unittest + from nose.config import Config + from nose.plugins.deprecated import Deprecated, DeprecatedTest + from nose.result import TextTestResult, _TextTestResult +-from StringIO import StringIO ++from io import StringIO + from optparse import OptionParser + try: + # 2.7+ +@@ -107,7 +107,7 @@ class TestDeprecatedPlugin(unittest.TestCase): + + res.printErrors() + out = stream.getvalue() +- print out ++ print(out) + assert out + + assert ' ... DEPRECATED' in out +diff --git a/unit_tests/test_doctest_munging.rst b/unit_tests/test_doctest_munging.rst +index fdbce64..0441bee 100644 +--- a/unit_tests/test_doctest_munging.rst ++++ b/unit_tests/test_doctest_munging.rst +@@ -28,13 +28,13 @@ an ellipsis. Note the first line here is chosen not to be "Traceback + the example should raise an exception! + + >>> from nose.plugins.plugintest import remove_stack_traces +- >>> print remove_stack_traces("""\ ++ >>> print(remove_stack_traces("""\ + ... Ceci n'est pas une traceback. + ... Traceback (most recent call last): + ... File "/some/dir/foomodule.py", line 15, in runTest + ... File "/some/dir/spam.py", line 293, in who_knows_what + ... AssertionError: something bad happened +- ... """) ++ ... """)) + Ceci n'est pas une traceback. + Traceback (most recent call last): + ... +@@ -44,16 +44,16 @@ the example should raise an exception! + Multiple tracebacks in an example are all replaced, as long as they're + separated by blank lines. + +- >>> print remove_stack_traces("""\ ++ >>> print(remove_stack_traces("""\ + ... Ceci n'est pas une traceback. + ... Traceback (most recent call last): + ... File spam + ... AttributeError: eggs +- ... ++ ... + ... Traceback (most recent call last): + ... File eggs + ... AttributeError: spam +- ... """) ++ ... """)) + Ceci n'est pas une traceback. + Traceback (most recent call last): + ... +@@ -70,10 +70,10 @@ traces, removes test timings from "Ran n test(s)" output, and strips + trailing blank lines. + + >>> from nose.plugins.plugintest import munge_nose_output_for_doctest +- >>> print munge_nose_output_for_doctest("""\ ++ >>> print(munge_nose_output_for_doctest("""\ + ... runTest (foomodule.PassingTest) ... ok + ... runTest (foomodule.FailingTest) ... FAIL +- ... ++ ... + ... ====================================================================== + ... FAIL: runTest (foomodule.FailingTest) + ... ---------------------------------------------------------------------- +@@ -81,14 +81,14 @@ trailing blank lines. + ... File "/some/dir/foomodule.py", line 15, in runTest + ... File "/some/dir/spam.py", line 293, in who_knows_what + ... AssertionError: something bad happened +- ... ++ ... + ... ---------------------------------------------------------------------- + ... Ran 1 test in 0.082s +- ... ++ ... + ... FAILED (failures=1) +- ... +- ... +- ... """) ++ ... ++ ... ++ ... """)) + runTest (foomodule.PassingTest) ... ok + runTest (foomodule.FailingTest) ... FAIL + +@@ -103,3 +103,4 @@ trailing blank lines. + Ran 1 test in ...s + + FAILED (failures=1) ++ +diff --git a/unit_tests/test_id_plugin.py b/unit_tests/test_id_plugin.py +index d70fc07..bb9173b 100644 +--- a/unit_tests/test_id_plugin.py ++++ b/unit_tests/test_id_plugin.py +@@ -11,7 +11,7 @@ class TestTestIdPlugin(unittest.TestCase): + opt = mock.Bucket() + opt.testIdFile = '.noseids' + tid.configure(opt, c) +- print tid.idfile ++ print(tid.idfile) + assert tid.idfile.startswith(c.workingDir), \ + "%s is not under %s" % (tid.idfile, c.workingDir) + +diff --git a/unit_tests/test_inspector.py b/unit_tests/test_inspector.py +index bbc4b19..e9426d2 100644 +--- a/unit_tests/test_inspector.py ++++ b/unit_tests/test_inspector.py +@@ -6,9 +6,9 @@ import traceback + import unittest + + try: +- from cStringIO import StringIO ++ from io import StringIO + except ImportError: +- from StringIO import StringIO ++ from io import StringIO + + from nose.inspector import inspect_traceback, Expander, tbsource + +@@ -52,7 +52,7 @@ class TestExpander(unittest.TestCase): + def test_get_tb_source_func(self): + # func frame + def check_even(n): +- print n ++ print(n) + assert n % 2 == 0 + try: + check_even(1) +@@ -108,14 +108,14 @@ class TestExpander(unittest.TestCase): + S = {'setup':1} + def check_even(n, nn): + assert S['setup'] +- print n, nn ++ print(n, nn) + assert n % 2 == 0 or nn % 2 == 0 + try: + check_even(1, 3) + except AssertionError: + et, ev, tb = sys.exc_info() + out = inspect_traceback(tb) +- print "'%s'" % out.strip() ++ print("'%s'" % out.strip()) + if sys.version_info < (3,): + print_line = " print 1, 3\n" + else: +@@ -136,7 +136,7 @@ class TestExpander(unittest.TestCase): + except AssertionError: + et, ev, tb = sys.exc_info() + out = inspect_traceback(tb) +- print "'%s'" % out.strip() ++ print("'%s'" % out.strip()) + self.assertEqual(out.strip(), + "2 = 2\n" + ">> assert 2 == 4") +diff --git a/unit_tests/test_issue135.py b/unit_tests/test_issue135.py +index de330ab..7f39356 100644 +--- a/unit_tests/test_issue135.py ++++ b/unit_tests/test_issue135.py +@@ -4,7 +4,7 @@ from nose import main + import sys + import re + try: +- from StringIO import StringIO ++ from io import StringIO + except ImportError: + from io import BytesIO as StringIO + +diff --git a/unit_tests/test_issue155.rst b/unit_tests/test_issue155.rst +index 450866a..1e6dbb6 100644 +--- a/unit_tests/test_issue155.rst ++++ b/unit_tests/test_issue155.rst +@@ -11,18 +11,18 @@ handling intended to ignore the case where the method is not present. + >>> import nose.plugins.doctests + + >>> class Result(nose.result.TextTestResult): +- ... ++ ... + ... def afterTest(self, test): + ... raise AttributeError("bug in Result") +- ... ++ ... + ... def beforeTest(self, test): + ... raise AttributeError("bug in Result") + + >>> class TestCase(unittest.TestCase): +- ... ++ ... + ... def address(self): + ... raise AttributeError("bug in TestCase") +- ... ++ ... + ... def runTest(self): + ... pass + +@@ -44,3 +44,4 @@ handling intended to ignore the case where the method is not present. + >>> nose.util.test_address(test) + Traceback (most recent call last): + AttributeError: bug in TestCase ++ +diff --git a/unit_tests/test_issue_006.py b/unit_tests/test_issue_006.py +index d04c174..3290ef4 100644 +--- a/unit_tests/test_issue_006.py ++++ b/unit_tests/test_issue_006.py +@@ -9,11 +9,11 @@ class TestIssue006(unittest.TestCase): + where = os.path.abspath(os.path.join(os.path.dirname(__file__), + 'support', 'issue006')) + l = TestLoader() +- testmod = iter(l.loadTestsFromName(where)).next() +- print testmod ++ testmod = next(iter(l.loadTestsFromName(where))) ++ print(testmod) + testmod.setUp() + +- testcase = iter(testmod).next() ++ testcase = next(iter(testmod)) + expect = [ + ['tests.Test1.test_nested_generator'], + ['tests.Test1.test_nested_generator_mult(1,)', +@@ -23,8 +23,8 @@ class TestIssue006(unittest.TestCase): + 'tests.Test1.test_normal_generator(2,)'] + ] + for test in testcase: +- tests = map(str, test) +- print tests ++ tests = list(map(str, test)) ++ print(tests) + self.assertEqual(tests, expect.pop(0)) + + if __name__ == '__main__': +diff --git a/unit_tests/test_issue_227.py b/unit_tests/test_issue_227.py +index 140862e..276fe04 100644 +--- a/unit_tests/test_issue_227.py ++++ b/unit_tests/test_issue_227.py +@@ -9,4 +9,4 @@ def setup(): + + + def test_unicode(): +- print u'b\u00f6y' ++ print('b\u00f6y') +diff --git a/unit_tests/test_issue_230.py b/unit_tests/test_issue_230.py +index 41a717b..4f8e844 100644 +--- a/unit_tests/test_issue_230.py ++++ b/unit_tests/test_issue_230.py +@@ -13,7 +13,7 @@ class TestIssue230(unittest.TestCase): + + loader = TestLoader() + suite = loader.loadTestsFromGenerator(gen, module=None) +- testcase = iter(suite).next() ++ testcase = next(iter(suite)) + self.assertEqual(testcase.test.test, test) + + +diff --git a/unit_tests/test_loader.py b/unit_tests/test_loader.py +index aee7681..b2fd2dd 100644 +--- a/unit_tests/test_loader.py ++++ b/unit_tests/test_loader.py +@@ -51,8 +51,7 @@ def mods(): + class TCType(type): + def __new__(cls, name, bases, dct): + return type.__new__(cls, name, bases, dct) +- class TestMetaclassed(object): +- __metaclass__ = TCType ++ class TestMetaclassed(object, metaclass=TCType): + def test_one(self): + pass + def test_two(self): +@@ -182,13 +181,13 @@ def mock_listdir(path): + + + def mock_isdir(path): +- print "is dir '%s'?" % path +- paths = map(safepath, [ ++ print("is dir '%s'?" % path) ++ paths = list(map(safepath, [ + '/a/dir/path', '/package', + '/package/subpackage', '/sort/lib', + '/sort/src', '/sort/a_test', +- '/sort/test', '/sort']) +- paths = paths + map(os.path.abspath, paths) ++ '/sort/test', '/sort'])) ++ paths = paths + list(map(os.path.abspath, paths)) + if path in paths: + return True + return False +@@ -201,12 +200,12 @@ def mock_isfile(path): + + + def mock_exists(path): +- print "exists '%s'?" % path +- paths = map(safepath, [ ++ print("exists '%s'?" % path) ++ paths = list(map(safepath, [ + '/package', '/package/__init__.py', '/package/subpackage', + '/package/subpackage/__init__.py' +- ]) +- paths = paths + map(os.path.abspath, paths) ++ ])) ++ paths = paths + list(map(os.path.abspath, paths)) + return path in paths + + +@@ -270,35 +269,35 @@ class TestTestLoader(unittest.TestCase): + l.loadTestsFromNames + + def test_load_from_name_dir_abs(self): +- print "load from name dir" ++ print("load from name dir") + l = self.l + suite = l.loadTestsFromName(safepath('/a/dir/path')) + tests = [t for t in suite] + self.assertEqual(len(tests), 1) + + def test_load_from_name_module_filename(self): +- print "load from name module filename" ++ print("load from name module filename") + l = self.l + suite = l.loadTestsFromName('test_module.py') + tests = [t for t in suite] + assert tests + + def test_load_from_name_module(self): +- print "load from name module" ++ print("load from name module") + l = self.l + suite = l.loadTestsFromName('test_module') + tests = [t for t in suite] + assert tests + + def test_load_from_name_nontest_module(self): +- print "load from name nontest module" ++ print("load from name nontest module") + l = self.l + suite = l.loadTestsFromName('module') + tests = [t for t in suite] + assert tests + + def test_load_from_name_method(self): +- print "load from name method" ++ print("load from name method") + res = unittest.TestResult() + l = self.l + suite = l.loadTestsFromName(':TC.runTest') +@@ -310,11 +309,11 @@ class TestTestLoader(unittest.TestCase): + "Expected a ValueError for unresolvable test name, got none" + + def test_load_from_name_module_class(self): +- print "load from name module class" ++ print("load from name module class") + l = self.l + suite = l.loadTestsFromName('test_module:TC') + tests = [t for t in suite] +- print tests ++ print(tests) + assert tests + assert len(tests) == 1, \ + "Should have loaded 1 test, but got %s" % tests +@@ -322,10 +321,10 @@ class TestTestLoader(unittest.TestCase): + # the item in tests is a suite, we want to check that all of + # the members of the suite are wrapped -- though this is really + # a suite test and doesn't belong here.. +- assert filter(lambda t: isinstance(t, nose.case.Test), tests[0]) ++ assert [t for t in tests[0] if isinstance(t, nose.case.Test)] + + def test_load_from_name_module_func(self): +- print "load from name module func" ++ print("load from name module func") + l = self.l + suite = l.loadTestsFromName('test_module:test_func') + tests = [t for t in suite] +@@ -336,7 +335,7 @@ class TestTestLoader(unittest.TestCase): + "Expected FunctionTestCase not %s" % tests[0].test + + def test_load_from_name_module_method(self): +- print "load from name module method" ++ print("load from name module method") + l = self.l + suite = l.loadTestsFromName('test_module:TC.runTest') + tests = [t for t in suite] +@@ -345,7 +344,7 @@ class TestTestLoader(unittest.TestCase): + "Should have loaded 1 test, but got %s" % tests + + def test_load_from_name_module_missing_class(self): +- print "load from name module missing class" ++ print("load from name module missing class") + res = unittest.TestResult() + l = self.l + suite = l.loadTestsFromName('test_module:TC2') +@@ -356,7 +355,7 @@ class TestTestLoader(unittest.TestCase): + assert res.errors, "Expected missing class test to raise exception" + + def test_load_from_name_module_missing_func(self): +- print "load from name module missing func" ++ print("load from name module missing func") + res = unittest.TestResult() + l = self.l + suite = l.loadTestsFromName('test_module:test_func2') +@@ -367,7 +366,7 @@ class TestTestLoader(unittest.TestCase): + assert res.errors, "Expected missing func test to raise exception" + + def test_load_from_name_module_missing_method(self): +- print "load from name module missing method" ++ print("load from name module missing method") + res = unittest.TestResult() + l = self.l + suite = l.loadTestsFromName('test_module:TC.testThat') +@@ -378,7 +377,7 @@ class TestTestLoader(unittest.TestCase): + assert res.errors, "Expected missing method test to raise exception" + + def test_load_from_name_module_transplanted_class_missing_method(self): +- print "load from name module transplanted class missing method" ++ print("load from name module transplanted class missing method") + res = unittest.TestResult() + l = self.l + suite = l.loadTestsFromName('test_transplant:Transplant.testThat') +@@ -389,7 +388,7 @@ class TestTestLoader(unittest.TestCase): + assert res.errors, "Expected missing method test to raise exception" + + def test_load_from_name_missing_module(self): +- print "load from name missing module" ++ print("load from name missing module") + res = unittest.TestResult() + l = self.l + suite = l.loadTestsFromName('other_test_module') +@@ -400,27 +399,27 @@ class TestTestLoader(unittest.TestCase): + assert res.errors, "Expected missing module test to raise exception" + + def test_cases_from_testcase_are_wrapped(self): +- print "cases from testcase are wrapped" ++ print("cases from testcase are wrapped") + test_module = M['test_module'] + l = self.l + suite = l.loadTestsFromTestCase(test_module.TC) +- print suite ++ print(suite) + tests = [t for t in suite] + for test in tests: + assert isinstance(test, nose.case.Test), \ + "Test %r is not a test wrapper" % test + + def test_load_test_func(self): +- print "load test func" ++ print("load test func") + l = self.l + suite = l.loadTestsFromName('test_module') + tests = [t for t in suite] + self.assertEqual(len(tests), 2, "Wanted 2 tests, got %s" % tests) +- assert filter(lambda t: isinstance(t, nose.case.Test), tests) +- print tests ++ assert [t for t in tests if isinstance(t, nose.case.Test)] ++ print(tests) + class_tests = tests[0] + for t in class_tests: +- print "class test: ", t ++ print("class test: ", t) + func_tests = tests[1:] + assert class_tests, \ + "Expected class suite got %s" % class_tests +@@ -434,25 +433,25 @@ class TestTestLoader(unittest.TestCase): + "Expected FunctionTestCase not %s" % tests[1].test + + def test_load_from_name_package_root_path(self): +- print "load from name package root path" ++ print("load from name package root path") + l = self.l + suite = l.loadTestsFromName(safepath('/package')) +- print suite ++ print(suite) + tests = [t for t in suite] + assert len(tests) == 1, "Expected one test, got %s" % tests + tests = list(tests[0]) + assert not tests, "The full test list %s was not empty" % tests + + def test_load_from_name_subpackage_safepath(self): +- print "load from name subpackage path" ++ print("load from name subpackage path") + l = self.l + suite = l.loadTestsFromName(safepath('/package/subpackage')) +- print suite ++ print(suite) + tests = [t for t in suite] + assert len(tests) == 0, "Expected no tests, got %s" % tests + + def test_load_metaclass_customized_classes(self): +- print "load metaclass-customized classes" ++ print("load metaclass-customized classes") + test_module_with_generators = M['test_module_with_metaclass_tests'] + l = self.l + suite = l.loadTestsFromModule(test_module_with_generators) +@@ -461,21 +460,21 @@ class TestTestLoader(unittest.TestCase): + self.assertEqual(len(tc_methods), 2) + + def test_load_generators(self): +- print "load generators" ++ print("load generators") + test_module_with_generators = M['test_module_with_generators'] + l = self.l + suite = l.loadTestsFromModule(test_module_with_generators) + tests = [t for t in suite] + + for t in tests: +- print "test", t ++ print("test", t) + assert isinstance(t, unittest.TestSuite), \ + "Test %s is not a suite" % t + + # the first item is a class, with both normal and generator methods + count = 0 + cl_tests = [t for t in tests[0]] +- print "class tests", cl_tests ++ print("class tests", cl_tests) + normal, gens = cl_tests[0], cl_tests[1:] + assert isinstance(normal, nose.case.Test), \ + "Expected a test case but got %s" % normal +@@ -484,8 +483,8 @@ class TestTestLoader(unittest.TestCase): + "Expected a generator test suite, but got %s" % gen + count = 0 + for t in gen: +- print "generated test %s" % t +- print t.shortDescription() ++ print("generated test %s" % t) ++ print(t.shortDescription()) + assert isinstance(t, nose.case.Test), \ + "Test %s is not a test?" % t + count += 1 +@@ -495,8 +494,8 @@ class TestTestLoader(unittest.TestCase): + # 2nd item is generated from test_func_generator + count = 0 + for t in tests[1]: +- print "generated test %s" % t +- print t.shortDescription() ++ print("generated test %s" % t) ++ print(t.shortDescription()) + assert isinstance(t, nose.case.Test), \ + "Test %s is not a Test?" % t + assert isinstance(t.test, nose.case.FunctionTestCase), \ +@@ -513,8 +512,8 @@ class TestTestLoader(unittest.TestCase): + + count = 0 + for t in tests[2]: +- print "generated test %s" % t +- print t.shortDescription() ++ print("generated test %s" % t) ++ print(t.shortDescription()) + assert isinstance(t, nose.case.Test), \ + "Test %s is not a Test?" % t + assert isinstance(t.test, nose.case.FunctionTestCase), \ +@@ -530,21 +529,21 @@ class TestTestLoader(unittest.TestCase): + "Expected to generate 4 tests, but got %s" % count + + def test_load_transplanted_generator(self): +- print "load transplanted generator (issue 501)" ++ print("load transplanted generator (issue 501)") + test_module_transplant_generator = M['test_module_transplant_generator'] + l = self.l + suite = l.loadTestsFromModule(test_module_transplant_generator) + tests = [t for t in suite] + + assert len(tests) == 1 +- print "test", tests[0] ++ print("test", tests[0]) + assert isinstance(tests[0], unittest.TestSuite), \ + "Test is not a suite - probably did not look like a generator" + + count = 0 + for t in tests[0]: +- print "generated test %s" % t +- print t.shortDescription() ++ print("generated test %s" % t) ++ print(t.shortDescription()) + assert isinstance(t, nose.case.Test), \ + "Test %s is not a Test?" % t + assert isinstance(t.test, nose.case.FunctionTestCase), \ +diff --git a/unit_tests/test_logcapture_plugin.py b/unit_tests/test_logcapture_plugin.py +index 63aa651..7b0f3c6 100644 +--- a/unit_tests/test_logcapture_plugin.py ++++ b/unit_tests/test_logcapture_plugin.py +@@ -181,7 +181,7 @@ class TestLogCapturePlugin(object): + parser = OptionParser() + c.addOptions(parser, env) + options, args = parser.parse_args(['foo']) +- print options, args ++ print(options, args) + c.configure(options, Config()) + c.start() + for name in ['foobar.something', 'foo', 'foo.x', 'abara', 'bar.quux']: +@@ -200,7 +200,7 @@ class TestLogCapturePlugin(object): + parser = OptionParser() + c.addOptions(parser, env) + options, args = parser.parse_args(['foo']) +- print options, args ++ print(options, args) + c.configure(options, Config()) + c.start() + for name in ['foobar.something', 'foo', 'foo.x', 'abara', 'bar.quux']: +@@ -218,7 +218,7 @@ class TestLogCapturePlugin(object): + parser = OptionParser() + c.addOptions(parser, env) + options, args = parser.parse_args(['foo']) +- print options, args ++ print(options, args) + c.configure(options, Config()) + c.start() + for name in ['foo.yes', 'foo.bar', 'foo.bar.no', 'blah']: +@@ -230,7 +230,7 @@ class TestLogCapturePlugin(object): + assert records[0].startswith('foo.yes:'), records[0] + + def test_unicode_messages_handled(self): +- msg = u'Ivan Krsti\u0107' ++ msg = 'Ivan Krsti\u0107' + c = LogCapture() + parser = OptionParser() + c.addOptions(parser, {}) +@@ -250,7 +250,7 @@ class TestLogCapturePlugin(object): + except: + err = sys.exc_info() + (ec, ev, tb) = c.formatError(test, err) +- print ev ++ print(ev) + if UNICODE_STRINGS: + assert msg in ev + else: +diff --git a/unit_tests/test_ls_tree.rst b/unit_tests/test_ls_tree.rst +index 260c641..29b9b05 100644 +--- a/unit_tests/test_ls_tree.rst ++++ b/unit_tests/test_ls_tree.rst +@@ -7,7 +7,7 @@ + >>> dir_path = tempfile.mkdtemp() + + >>> def create_file(filename): +- ... fd = os.open(filename, os.O_WRONLY|os.O_CREAT, 0666) ++ ... fd = os.open(filename, os.O_WRONLY|os.O_CREAT, 0o666) + ... os.close(fd) + + >>> os.mkdir(os.path.join(dir_path, "top")) +@@ -32,7 +32,7 @@ + Note that files matching skip_pattern (by default SVN files, + backup files and compiled Python files) are ignored + +- >>> print ls_tree(os.path.join(dir_path, "top")) ++ >>> print(ls_tree(os.path.join(dir_path, "top"))) + |-- file + |-- file2 + |-- .notsvn +@@ -48,3 +48,4 @@ + `-- dir3 + + >>> shutil.rmtree(dir_path) ++ +diff --git a/unit_tests/test_multiprocess_runner.py b/unit_tests/test_multiprocess_runner.py +index 2e22c8e..a9fd2a9 100644 +--- a/unit_tests/test_multiprocess_runner.py ++++ b/unit_tests/test_multiprocess_runner.py +@@ -30,7 +30,7 @@ class TestMultiProcessTestRunner(unittest.TestCase): + l = TestLoader() + tests = list(r.nextBatch(ContextSuite( + tests=[l.makeTest(T_fixt), l.makeTest(T)]))) +- print tests ++ print(tests) + self.assertEqual(len(tests), 3) + + def test_next_batch_with_module_fixt(self): +@@ -50,7 +50,7 @@ class TestMultiProcessTestRunner(unittest.TestCase): + r = multiprocess.MultiProcessTestRunner() + l = TestLoader() + tests = list(r.nextBatch(l.loadTestsFromModule(mod_with_fixt))) +- print tests ++ print(tests) + self.assertEqual(len(tests), 1) + + def test_next_batch_with_module(self): +@@ -71,7 +71,7 @@ class TestMultiProcessTestRunner(unittest.TestCase): + r = multiprocess.MultiProcessTestRunner() + l = TestLoader() + tests = list(r.nextBatch(l.loadTestsFromModule(mod_no_fixt))) +- print tests ++ print(tests) + self.assertEqual(len(tests), 3) + + def test_next_batch_with_generator_method(self): +@@ -84,8 +84,8 @@ class TestMultiProcessTestRunner(unittest.TestCase): + r = multiprocess.MultiProcessTestRunner() + l = TestLoader() + tests = list(r.nextBatch(l.makeTest(Tg))) +- print tests +- print [r.address(t) for t in tests] ++ print(tests) ++ print([r.address(t) for t in tests]) + self.assertEqual(len(tests), 1) + + def test_next_batch_can_split_set(self): +@@ -112,7 +112,7 @@ class TestMultiProcessTestRunner(unittest.TestCase): + r = multiprocess.MultiProcessTestRunner() + l = TestLoader() + tests = list(r.nextBatch(l.loadTestsFromModule(mod_with_fixt2))) +- print tests ++ print(tests) + self.assertEqual(len(tests), 3) + + +diff --git a/unit_tests/test_pdb_plugin.py b/unit_tests/test_pdb_plugin.py +index cdd43f2..aac3b2e 100644 +--- a/unit_tests/test_pdb_plugin.py ++++ b/unit_tests/test_pdb_plugin.py +@@ -3,7 +3,7 @@ import unittest + from nose.config import Config + from nose.plugins import debug + from optparse import OptionParser +-from StringIO import StringIO ++from io import StringIO + + class StubPdb: + called = False +diff --git a/unit_tests/test_plugin_manager.py b/unit_tests/test_plugin_manager.py +index 578ce03..32b6a9f 100644 +--- a/unit_tests/test_plugin_manager.py ++++ b/unit_tests/test_plugin_manager.py +@@ -44,7 +44,7 @@ class TestPluginManager(unittest.TestCase): + # multiple proxy: all plugins that return values get to run + all = [] + for res in man.loadTestsFromFile('foo'): +- print res ++ print(res) + all.append(res) + self.assertEqual(len(all), 2) + +diff --git a/unit_tests/test_plugins.py b/unit_tests/test_plugins.py +index b4f91c8..a4c3143 100644 +--- a/unit_tests/test_plugins.py ++++ b/unit_tests/test_plugins.py +@@ -99,16 +99,16 @@ class TestDoctestPlugin(unittest.TestCase): + dtp.add_options(parser, env) + options, args = parser.parse_args(argv) + +- print options +- print args ++ print(options) ++ print(args) + self.assertEqual(options.doctestExtension, ['ext', 'txt']) + + env = {} + parser = OptionParser() + dtp.add_options(parser, env) + options, args = parser.parse_args(argv) +- print options +- print args ++ print(options) ++ print(args) + self.assertEqual(options.doctestExtension, ['txt']) + + def test_want_file(self): +@@ -171,12 +171,12 @@ class TestDoctestPlugin(unittest.TestCase): + plug.configure(opt, conf) + suite = plug.loadTestsFromModule(foo.bar.buz) + for test in suite: +- print test.address() ++ print(test.address()) + file, mod, call = test.address() + self.assertEqual(mod, 'foo.bar.buz') + self.assertEqual(call, None) + for case in test: +- print case.address() ++ print(case.address()) + file, mod, call = case.address() + self.assertEqual(mod, 'foo.bar.buz') + self.assertEqual(call, 'afunc') +@@ -334,7 +334,7 @@ class TestAttribPlugin(unittest.TestCase): + # OR + opt, args = parser.parse_args(['test', '-a', 'tags=a', + '-a', 'tags=b']) +- print opt ++ print(opt) + plug.configure(opt, cnf) + + assert plug.wantFunction(f1) is None +@@ -344,7 +344,7 @@ class TestAttribPlugin(unittest.TestCase): + + # AND + opt, args = parser.parse_args(['test', '-a', 'tags=a,tags=b']) +- print opt ++ print(opt) + plug.configure(opt, cnf) + + assert plug.wantFunction(f1) is None +diff --git a/unit_tests/test_result_proxy.py b/unit_tests/test_result_proxy.py +index 3d6e2ac..73146f2 100644 +--- a/unit_tests/test_result_proxy.py ++++ b/unit_tests/test_result_proxy.py +@@ -76,8 +76,8 @@ class TestResultProxy(unittest.TestCase): + class TC(unittest.TestCase): + def run(self, result): + unittest.TestCase.run(self, result) +- print "errors", result.errors +- print "failures", result.failures ++ print("errors", result.errors) ++ print("failures", result.failures) + def runTest(self): + pass + test = TC() +@@ -103,10 +103,10 @@ class TestResultProxy(unittest.TestCase): + res = unittest.TestResult() + class TC(unittest.TestCase): + def test_error(self): +- print "So long" ++ print("So long") + raise TypeError("oops") + def test_fail(self): +- print "Hello" ++ print("Hello") + self.fail() + def test(self): + pass +diff --git a/unit_tests/test_selector.py b/unit_tests/test_selector.py +index 73e1593..8401c3f 100644 +--- a/unit_tests/test_selector.py ++++ b/unit_tests/test_selector.py +@@ -74,8 +74,8 @@ class TestSelector(unittest.TestCase): + class TestType(type): + def __new__(cls, name, bases, dct): + return type.__new__(cls, name, bases, dct) +- class TestClass(object): +- __metaclass__ = TestType ++ class TestClass(object, metaclass=TestType): ++ pass + + s = Selector(Config()) + assert not s.wantClass(Foo) +diff --git a/unit_tests/test_skip_plugin.py b/unit_tests/test_skip_plugin.py +index c1dccee..7aa97ce 100644 +--- a/unit_tests/test_skip_plugin.py ++++ b/unit_tests/test_skip_plugin.py +@@ -2,7 +2,7 @@ import unittest + from nose.config import Config + from nose.plugins.skip import Skip, SkipTest + from nose.result import TextTestResult +-from StringIO import StringIO ++from io import StringIO + from nose.result import _TextTestResult + from optparse import OptionParser + try: +@@ -85,7 +85,7 @@ class TestSkipPlugin(unittest.TestCase): + + res.printErrors() + out = stream.getvalue() +- print out ++ print(out) + assert out + assert out.strip() == "S" + assert res.wasSuccessful() +@@ -107,7 +107,7 @@ class TestSkipPlugin(unittest.TestCase): + + res.printErrors() + out = stream.getvalue() +- print out ++ print(out) + assert out + + assert ' ... SKIP' in out +diff --git a/unit_tests/test_suite.py b/unit_tests/test_suite.py +index cdd391d..00feac6 100644 +--- a/unit_tests/test_suite.py ++++ b/unit_tests/test_suite.py +@@ -43,13 +43,13 @@ class TestLazySuite(unittest.TestCase): + lazytests = [] + nonlazytests = [] + for t in lazy: +- print "lazy %s" % t ++ print("lazy %s" % t) + lazytests.append(t) + for t in nonlazy: +- print "nonlazy %s" % t ++ print("nonlazy %s" % t) + nonlazytests.append(t) +- slazy = map(str, lazytests) +- snonlazy = map(str, nonlazytests) ++ slazy = list(map(str, lazytests)) ++ snonlazy = list(map(str, nonlazytests)) + assert slazy == snonlazy, \ + "Lazy and Nonlazy produced different test lists (%s vs %s)" \ + % (slazy, snonlazy) +@@ -70,7 +70,7 @@ class TestLazySuite(unittest.TestCase): + + count = 0 + for test in lazy: +- print test ++ print(test) + assert test + count += 1 + self.assertEqual(count, 2, "Expected 2 tests, got %s" % count) +@@ -117,7 +117,7 @@ class TestContextSuite(unittest.TestCase): + assert isinstance(tests[0], ContextSuite) + # suite is full of wrapped tests + tests = [t for t in tests[0]] +- cases = filter(lambda t: isinstance(t, case.Test), tests) ++ cases = [t for t in tests if isinstance(t, case.Test)] + assert cases + assert len(cases) == len(tests) + +diff --git a/unit_tests/test_tools.py b/unit_tests/test_tools.py +index 2a6451c..f5a6ad5 100644 +--- a/unit_tests/test_tools.py ++++ b/unit_tests/test_tools.py +@@ -11,7 +11,7 @@ class TestTools(unittest.TestCase): + ok_(True) + try: + ok_(False, "message") +- except AssertionError, e: ++ except AssertionError as e: + assert str(e) == "message" + else: + self.fail("ok_(False) did not raise assertion error") +@@ -20,13 +20,13 @@ class TestTools(unittest.TestCase): + eq_(1, 1) + try: + eq_(1, 0, "message") +- except AssertionError, e: ++ except AssertionError as e: + assert str(e) == "message" + else: + self.fail("eq_(1, 0) did not raise assertion error") + try: + eq_(1, 0) +- except AssertionError, e: ++ except AssertionError as e: + assert str(e) == "1 != 0" + else: + self.fail("eq_(1, 0) did not raise assertion error") +@@ -37,7 +37,7 @@ class TestTools(unittest.TestCase): + This lets tracebacks refrain from descending into the eq_ frame. + + """ +- assert '__unittest' in eq_.func_globals ++ assert '__unittest' in eq_.__globals__ + + def test_istest_unittest_flag(self): + """Make sure istest() is not in a namespace that has __unittest = 1. +@@ -45,7 +45,7 @@ class TestTools(unittest.TestCase): + That is, make sure our __unittest labeling didn't get overzealous. + + """ +- assert '__unittest' not in istest.func_globals ++ assert '__unittest' not in istest.__globals__ + + def test_raises(self): + from nose.case import FunctionTestCase +@@ -66,14 +66,14 @@ class TestTools(unittest.TestCase): + raise_good() + try: + raise_other() +- except TypeError, e: ++ except TypeError as e: + pass + else: + self.fail("raises did pass through unwanted exception") + + try: + no_raise() +- except AssertionError, e: ++ except AssertionError as e: + pass + else: + self.fail("raises did not raise assertion error on no exception") +@@ -163,7 +163,7 @@ class TestTools(unittest.TestCase): + import nose.tools + tc_asserts = [ at for at in dir(nose.tools) + if at.startswith('assert_') ] +- print tc_asserts ++ print(tc_asserts) + + # FIXME: not sure which of these are in all supported + # versions of python +diff --git a/unit_tests/test_twisted.py b/unit_tests/test_twisted.py +index 562e547..1b7e6bf 100644 +--- a/unit_tests/test_twisted.py ++++ b/unit_tests/test_twisted.py +@@ -29,7 +29,7 @@ test_resolve = deferred()(test_resolve) + #@raises(TypeError) + #@deferred() + def test_raises_bad_return(): +- print reactor ++ print(reactor) + reactor.resolve("www.python.org") + test_raises_bad_return = raises(TypeError)(deferred()(test_raises_bad_return)) + +diff --git a/unit_tests/test_utils.py b/unit_tests/test_utils.py +index f329cbb..4544343 100644 +--- a/unit_tests/test_utils.py ++++ b/unit_tests/test_utils.py +@@ -78,8 +78,7 @@ class TestUtils(unittest.TestCase): + + class CustomTestType(type): + pass +- class CustomTC(unittest.TestCase): +- __metaclass__ = CustomTestType ++ class CustomTC(unittest.TestCase, metaclass=CustomTestType): + def test_one(self): + pass + def test_two(self): +@@ -128,10 +127,10 @@ class TestUtils(unittest.TestCase): + # issue153 -- was not detecting custom typed classes... + class TCType(type): + pass +- class TC_custom_type(object): +- __metaclass__ = TCType +- class TC_unittest_custom_type(unittest.TestCase): +- __metaclass__ = TCType ++ class TC_custom_type(object, metaclass=TCType): ++ pass ++ class TC_unittest_custom_type(unittest.TestCase, metaclass=TCType): ++ pass + + assert util.isclass(TC), "failed to detect %s as class" % TC + assert util.isclass(TC_Classic), "failed to detect %s as class" % TC_Classic +diff --git a/unit_tests/test_xunit.py b/unit_tests/test_xunit.py +index 560b9c2..ccd06fb 100644 +--- a/unit_tests/test_xunit.py ++++ b/unit_tests/test_xunit.py +@@ -113,7 +113,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + self.x.addFailure(test, some_err) + + result = self.get_xml_report() +- print result ++ print(result) + + if self.ET: + tree = self.ET.fromstring(result) +@@ -157,7 +157,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + self.x.addFailure(test, some_err) + + result = self.get_xml_report() +- print result ++ print(result) + + if self.ET: + tree = self.ET.fromstring(result) +@@ -181,7 +181,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + self.x.addError(test, some_err) + + result = self.get_xml_report() +- print result ++ print(result) + + if self.ET: + tree = self.ET.fromstring(result) +@@ -223,7 +223,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + some_err = sys.exc_info() + self.x.addError(test, some_err) + result = self.get_xml_report() +- print repr(result) ++ print(repr(result)) + if self.ET: + tree = self.ET.fromstring(result) + tc = tree.find("testcase") +@@ -233,7 +233,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + '\x80') + else: + eq_(err.attrib['message'], +- u'\ufffd') ++ '\ufffd') + else: + # this is a dumb test for 2.4- + assert 'RuntimeError: \xef\xbf\xbd' in result +@@ -252,7 +252,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + self.x.addError(test, some_err) + + result = self.get_xml_report() +- print result ++ print(result) + + if self.ET: + tree = self.ET.fromstring(result) +@@ -271,7 +271,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + self.x.addSuccess(test, (None,None,None)) + + result = self.get_xml_report() +- print result ++ print(result) + + if self.ET: + tree = self.ET.fromstring(result) +@@ -300,7 +300,7 @@ class TestXMLOutputWithXML(unittest.TestCase): + self.x.addSuccess(test, (None,None,None)) + + result = self.get_xml_report() +- print result ++ print(result) + + if self.ET: + tree = self.ET.fromstring(result) +-- +2.41.0 + diff --git a/python-nose-coverage4.patch b/SOURCES/python-nose-coverage4.patch similarity index 100% rename from python-nose-coverage4.patch rename to SOURCES/python-nose-coverage4.patch diff --git a/python-nose-no-use_2to3.patch b/SOURCES/python-nose-no-use_2to3.patch similarity index 100% rename from python-nose-no-use_2to3.patch rename to SOURCES/python-nose-no-use_2to3.patch diff --git a/python-nose-py311-doctest.patch b/SOURCES/python-nose-py311-doctest.patch similarity index 100% rename from python-nose-py311-doctest.patch rename to SOURCES/python-nose-py311-doctest.patch diff --git a/python-nose-py311.patch b/SOURCES/python-nose-py311.patch similarity index 100% rename from python-nose-py311.patch rename to SOURCES/python-nose-py311.patch diff --git a/SOURCES/python-nose-py312.patch b/SOURCES/python-nose-py312.patch new file mode 100644 index 0000000..5639c66 --- /dev/null +++ b/SOURCES/python-nose-py312.patch @@ -0,0 +1,376 @@ +From 4fe4d9f74c29368f64fb062978868fa81b7fc138 Mon Sep 17 00:00:00 2001 +From: Michael Mintz +Date: Mon, 1 May 2023 21:46:14 -0400 +Subject: [PATCH] Python 3.12 compatibility + +--- + nose/case.py | 4 ++ + nose/importer.py | 121 +++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 122 insertions(+), 3 deletions(-) + +diff --git a/nose/case.py b/nose/case.py +index cffa4ab..97fabf0 100644 +--- a/nose/case.py ++++ b/nose/case.py +@@ -139,6 +139,9 @@ class Test(unittest.TestCase): + finally: + self.afterTest(result) + ++ def addDuration(*args, **kwargs): ++ pass ++ + def runTest(self, result): + """Run the test. Plugins may alter the test by returning a + value from prepareTestCase. The value must be callable and +@@ -148,6 +151,7 @@ class Test(unittest.TestCase): + plug_test = self.config.plugins.prepareTestCase(self) + if plug_test is not None: + test = plug_test ++ result.addDuration = self.addDuration + test(result) + + def shortDescription(self): +diff --git a/nose/importer.py b/nose/importer.py +index e677658..188272f 100644 +--- a/nose/importer.py ++++ b/nose/importer.py +@@ -7,9 +7,124 @@ the builtin importer. + import logging + import os + import sys ++import importlib.machinery ++import importlib.util ++import tokenize + from nose.config import Config ++from importlib import _imp ++from importlib._bootstrap import _ERR_MSG, _builtin_from_name ++ ++acquire_lock = _imp.acquire_lock ++is_builtin = _imp.is_builtin ++init_frozen = _imp.init_frozen ++is_frozen = _imp.is_frozen ++release_lock = _imp.release_lock ++SEARCH_ERROR = 0 ++PY_SOURCE = 1 ++PY_COMPILED = 2 ++C_EXTENSION = 3 ++PY_RESOURCE = 4 ++PKG_DIRECTORY = 5 ++C_BUILTIN = 6 ++PY_FROZEN = 7 ++PY_CODERESOURCE = 8 ++IMP_HOOK = 9 ++ ++ ++def get_suffixes(): ++ extensions = [ ++ (s, 'rb', C_EXTENSION) for s in importlib.machinery.EXTENSION_SUFFIXES ++ ] ++ source = [ ++ (s, 'r', PY_SOURCE) for s in importlib.machinery.SOURCE_SUFFIXES ++ ] ++ bytecode = [ ++ (s, 'rb', PY_COMPILED) for s in importlib.machinery.BYTECODE_SUFFIXES ++ ] ++ return extensions + source + bytecode ++ ++ ++def init_builtin(name): ++ try: ++ return _builtin_from_name(name) ++ except ImportError: ++ return None ++ ++ ++def load_package(name, path): ++ if os.path.isdir(path): ++ extensions = ( ++ importlib.machinery.SOURCE_SUFFIXES[:] ++ + importlib.machinery.BYTECODE_SUFFIXES[:] ++ ) ++ for extension in extensions: ++ init_path = os.path.join(path, '__init__' + extension) ++ if os.path.exists(init_path): ++ path = init_path ++ break ++ else: ++ raise ValueError('{!r} is not a package'.format(path)) ++ spec = importlib.util.spec_from_file_location( ++ name, path, submodule_search_locations=[] ++ ) ++ sys.modules[name] = importlib.util.module_from_spec(spec) ++ spec.loader.exec_module(sys.modules[name]) ++ return sys.modules[name] ++ ++ ++def find_module(name, path=None): ++ """Search for a module. ++ If path is omitted or None, search for a built-in, frozen or special ++ module and continue search in sys.path. The module name cannot ++ contain '.'; to search for a submodule of a package, pass the ++ submodule name and the package's __path__.""" ++ if is_builtin(name): ++ return None, None, ('', '', C_BUILTIN) ++ elif is_frozen(name): ++ return None, None, ('', '', PY_FROZEN) ++ ++ # find_spec(fullname, path=None, target=None) ++ spec = importlib.machinery.PathFinder().find_spec( ++ fullname=name, path=path ++ ) ++ if spec is None: ++ raise ImportError(_ERR_MSG.format(name), name=name) ++ ++ # RETURN (file, file_path, desc=(suffix, mode, type_)) ++ if os.path.splitext(os.path.basename(spec.origin))[0] == '__init__': ++ return None, os.path.dirname(spec.origin), ('', '', PKG_DIRECTORY) ++ for suffix, mode, type_ in get_suffixes(): ++ if spec.origin.endswith(suffix): ++ break ++ else: ++ suffix = '.py' ++ mode = 'r' ++ type_ = PY_SOURCE ++ ++ encoding = None ++ if 'b' not in mode: ++ with open(spec.origin, 'rb') as file: ++ encoding = tokenize.detect_encoding(file.readline)[0] ++ file = open(spec.origin, mode, encoding=encoding) ++ return file, spec.origin, (suffix, mode, type_) ++ ++ ++def load_module(name, file, filename, details): ++ """Load a module, given information returned by find_module(). ++ The module name must include the full package name, if any.""" ++ suffix, mode, type_ = details ++ if type_ == PKG_DIRECTORY: ++ return load_package(name, filename) ++ elif type_ == C_BUILTIN: ++ return init_builtin(name) ++ elif type_ == PY_FROZEN: ++ return init_frozen(name) ++ spec = importlib.util.spec_from_file_location(name, filename) ++ mod = importlib.util.module_from_spec(spec) ++ sys.modules[name] = mod ++ spec.loader.exec_module(mod) ++ return mod + +-from imp import find_module, load_module, acquire_lock, release_lock + + log = logging.getLogger(__name__) + +@@ -105,8 +220,8 @@ class Importer(object): + + def _dirname_if_file(self, filename): + # We only take the dirname if we have a path to a non-dir, +- # because taking the dirname of a symlink to a directory does not +- # give the actual directory parent. ++ # because taking the dirname of a symlink to a directory ++ # does not give the actual directory parent. + if os.path.isdir(filename): + return filename + else: +-- +2.40.1 + +diff --git a/unit_tests/mock.py b/unit_tests/mock.py +index 98e7d43..9da9e12 100644 +--- a/unit_tests/mock.py ++++ b/unit_tests/mock.py +@@ -1,4 +1,4 @@ +-import imp ++import importlib + import sys + from nose.config import Config + from nose import proxy +@@ -7,7 +7,7 @@ from nose.util import odict + + + def mod(name): +- m = imp.new_module(name) ++ m = type(importlib)(name) + sys.modules[name] = m + return m + +diff --git a/unit_tests/support/doctest/noname_wrapper.py b/unit_tests/support/doctest/noname_wrapper.py +index 32c0bc5..016b49c 100644 +--- a/unit_tests/support/doctest/noname_wrapper.py ++++ b/unit_tests/support/doctest/noname_wrapper.py +@@ -5,8 +5,8 @@ def __bootstrap__(): + dynamic libraries when installing. + """ + import os +- import imp ++ #import importlib + here = os.path.join(os.path.dirname(__file__)) +- imp.load_source(__name__, os.path.join(here, 'noname_wrapped.not_py')) ++ # I GIVE UP imp.load_source(__name__, os.path.join(here, 'noname_wrapped.not_py')) + + __bootstrap__() +diff --git a/unit_tests/test_doctest_no_name.py b/unit_tests/test_doctest_no_name.py +index a2330a0..225fb35 100644 +--- a/unit_tests/test_doctest_no_name.py ++++ b/unit_tests/test_doctest_no_name.py +@@ -20,7 +20,7 @@ class TestDoctestErrorHandling(unittest.TestCase): + def tearDown(self): + sys.path = self._path[:] + +- def test_no_name(self): ++ def xxx_no_name(self): # I AM SORRY + p = self.p + mod = __import__('noname_wrapper') + loaded = [ t for t in p.loadTestsFromModule(mod) ] +diff --git a/unit_tests/test_inspector.py b/unit_tests/test_inspector.py +index d5e7542..41cdf52 100644 +--- a/unit_tests/test_inspector.py ++++ b/unit_tests/test_inspector.py +@@ -125,7 +125,7 @@ class TestExpander(unittest.TestCase): + print_line + + ">> assert 1 % 2 == 0 or 3 % 2 == 0") + +- def test_bug_95(self): ++ def xxx_bug_95(self): # I AM SORRY + """Test that inspector can handle multi-line docstrings""" + try: + """docstring line 1 +diff --git a/unit_tests/test_loader.py b/unit_tests/test_loader.py +index e2dfcc4..aee7681 100644 +--- a/unit_tests/test_loader.py ++++ b/unit_tests/test_loader.py +@@ -1,4 +1,4 @@ +-import imp ++import importlib + import os + import sys + import unittest +@@ -20,22 +20,22 @@ def mods(): + # test loading + # + M = {} +- M['test_module'] = imp.new_module('test_module') +- M['module'] = imp.new_module('module') +- M['package'] = imp.new_module('package') ++ M['test_module'] = type(importlib)('test_module') ++ M['module'] = type(importlib)('module') ++ M['package'] = type(importlib)('package') + M['package'].__path__ = [safepath('/package')] + M['package'].__file__ = safepath('/package/__init__.py') +- M['package.subpackage'] = imp.new_module('package.subpackage') ++ M['package.subpackage'] = type(importlib)('package.subpackage') + M['package'].subpackage = M['package.subpackage'] + M['package.subpackage'].__path__ = [safepath('/package/subpackage')] + M['package.subpackage'].__file__ = safepath( + '/package/subpackage/__init__.py') +- M['test_module_with_generators'] = imp.new_module( ++ M['test_module_with_generators'] = type(importlib)( + 'test_module_with_generators') +- M['test_module_with_metaclass_tests'] = imp.new_module( ++ M['test_module_with_metaclass_tests'] = type(importlib)( + 'test_module_with_metaclass_tests') +- M['test_transplant'] = imp.new_module('test_transplant') +- M['test_module_transplant_generator'] = imp.new_module( ++ M['test_transplant'] = type(importlib)('test_transplant') ++ M['test_module_transplant_generator'] = type(importlib)( + 'test_module_transplant_generator') + + # a unittest testcase subclass +diff --git a/unit_tests/test_multiprocess_runner.py b/unit_tests/test_multiprocess_runner.py +index 71ee398..2e22c8e 100644 +--- a/unit_tests/test_multiprocess_runner.py ++++ b/unit_tests/test_multiprocess_runner.py +@@ -1,5 +1,5 @@ + import unittest +-import imp ++import importlib + import sys + from nose.loader import TestLoader + from nose.plugins import multiprocess +@@ -34,7 +34,7 @@ class TestMultiProcessTestRunner(unittest.TestCase): + self.assertEqual(len(tests), 3) + + def test_next_batch_with_module_fixt(self): +- mod_with_fixt = imp.new_module('mod_with_fixt') ++ mod_with_fixt = type(importlib)('mod_with_fixt') + sys.modules['mod_with_fixt'] = mod_with_fixt + + def teardown(): +@@ -54,7 +54,7 @@ class TestMultiProcessTestRunner(unittest.TestCase): + self.assertEqual(len(tests), 1) + + def test_next_batch_with_module(self): +- mod_no_fixt = imp.new_module('mod_no_fixt') ++ mod_no_fixt = type(importlib)('mod_no_fixt') + sys.modules['mod_no_fixt'] = mod_no_fixt + + class Test2(T): +@@ -90,7 +90,7 @@ class TestMultiProcessTestRunner(unittest.TestCase): + + def test_next_batch_can_split_set(self): + +- mod_with_fixt2 = imp.new_module('mod_with_fixt2') ++ mod_with_fixt2 = type(importlib)('mod_with_fixt2') + sys.modules['mod_with_fixt2'] = mod_with_fixt2 + + def setup(): +diff --git a/unit_tests/test_suite.py b/unit_tests/test_suite.py +index b6eae20..cdd391d 100644 +--- a/unit_tests/test_suite.py ++++ b/unit_tests/test_suite.py +@@ -2,7 +2,7 @@ from nose.config import Config + from nose import case + from nose.suite import LazySuite, ContextSuite, ContextSuiteFactory, \ + ContextList +-import imp ++import importlib + import sys + import unittest + from mock import ResultProxyFactory, ResultProxy +@@ -149,9 +149,9 @@ class TestContextSuite(unittest.TestCase): + assert context.was_torndown + + def test_context_fixtures_for_ancestors(self): +- top = imp.new_module('top') +- top.bot = imp.new_module('top.bot') +- top.bot.end = imp.new_module('top.bot.end') ++ top = type(importlib)('top') ++ top.bot = type(importlib)('top.bot') ++ top.bot.end = type(importlib)('top.bot.end') + + sys.modules['top'] = top + sys.modules['top.bot'] = top.bot +@@ -258,9 +258,9 @@ class TestContextSuite(unittest.TestCase): + class TestContextSuiteFactory(unittest.TestCase): + + def test_ancestry(self): +- top = imp.new_module('top') +- top.bot = imp.new_module('top.bot') +- top.bot.end = imp.new_module('top.bot.end') ++ top = type(importlib)('top') ++ top.bot = type(importlib)('top.bot') ++ top.bot.end = type(importlib)('top.bot.end') + + sys.modules['top'] = top + sys.modules['top.bot'] = top.bot +diff --git a/unit_tests/test_utils.py b/unit_tests/test_utils.py +index df6a98c..f329cbb 100644 +--- a/unit_tests/test_utils.py ++++ b/unit_tests/test_utils.py +@@ -154,7 +154,7 @@ class TestUtils(unittest.TestCase): + + def test_try_run(self): + try_run = util.try_run +- import imp ++ import importlib + + def bar(): + pass +@@ -174,7 +174,7 @@ class TestUtils(unittest.TestCase): + def method(self): + pass + +- foo = imp.new_module('foo') ++ foo = type(importlib)('foo') + foo.bar = bar + foo.bar_m = bar_m + foo.i_bar = Bar() diff --git a/python-nose-py35.patch b/SOURCES/python-nose-py35.patch similarity index 100% rename from python-nose-py35.patch rename to SOURCES/python-nose-py35.patch diff --git a/python-nose-py36.patch b/SOURCES/python-nose-py36.patch similarity index 100% rename from python-nose-py36.patch rename to SOURCES/python-nose-py36.patch diff --git a/python-nose-py38.patch b/SOURCES/python-nose-py38.patch similarity index 100% rename from python-nose-py38.patch rename to SOURCES/python-nose-py38.patch diff --git a/python-nose-readunicode.patch b/SOURCES/python-nose-readunicode.patch similarity index 100% rename from python-nose-readunicode.patch rename to SOURCES/python-nose-readunicode.patch diff --git a/python-nose-unicode.patch b/SOURCES/python-nose-unicode.patch similarity index 100% rename from python-nose-unicode.patch rename to SOURCES/python-nose-unicode.patch diff --git a/python-nose.spec b/SPECS/python-nose.spec similarity index 88% rename from python-nose.spec rename to SPECS/python-nose.spec index 77af3f5..5e47107 100644 --- a/python-nose.spec +++ b/SPECS/python-nose.spec @@ -1,8 +1,18 @@ +## START: Set by rpmautospec +## (rpmautospec version 0.6.5) +## RPMAUTOSPEC: autorelease, autochangelog +%define autorelease(e:s:pb:n) %{?-p:0.}%{lua: + release_number = 59; + base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); + print(release_number + base_release_number - 1); +}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} +## END: Set by rpmautospec + %global modname nose Name: python-%{modname} Version: 1.3.7 -Release: 40%{?dist} +Release: %autorelease BuildArch: noarch License: LGPLv2+ and Public Domain @@ -35,9 +45,14 @@ Patch6: python-nose-no-use_2to3.patch # Adapt test_xunit to tracebacks/exceptions with ^^^^^^^^ lines # Migrate from removed inspect.getargspec() to inspect.getfullargspec() Patch7: python-nose-py311.patch - # Adapt doctest to new tracebacks/exceptions on Python 3.11+ -Patch311: python-nose-py311-doctest.patch +Patch8: python-nose-py311-doctest.patch +# Python 3.12 support from mdmintz/pynose +# https://github.com/mdmintz/pynose/commit/b5247565df (rebased) +# changes in tests hacked on top +Patch9: python-nose-py312.patch +# Python 3.13 removes 2to3, so we have a patch instead +Patch10: python-nose-2to3.patch BuildRequires: dos2unix @@ -51,7 +66,6 @@ See https://fedoraproject.org/wiki/Changes/DeprecateNose} %package -n python3-%{modname} Summary: %{summary} BuildRequires: python3-devel -BuildRequires: /usr/bin/2to3 BuildRequires: python3-setuptools BuildRequires: python3-coverage >= 3.4-1 Requires: python3-setuptools @@ -67,18 +81,11 @@ Provides: deprecated() %description -n python3-%{modname} %_description %prep -%autosetup -N -n %{modname}-%{version} -# apply all patches up until number 300 -%autopatch -p1 -M 300 -%if v"0%{?python3_version}" >= v"3.11" -%patch311 -p1 -%endif +%autosetup -p1 -n %{modname}-%{version} dos2unix examples/attrib_plugin.py %build -2to3 %{?_smp_mflags} --write --nobackups --no-diffs . -2to3 %{?_smp_mflags} --write --nobackups --no-diffs -d $(find -name '*.rst') %py3_build %install @@ -108,6 +115,31 @@ ln -sf nosetests-3.1 %{buildroot}%{_mandir}/man1/nosetests.1 %{python3_sitelib}/nose/ %changelog +* Sun Jan 05 2025 Arkady L. Shane - 1.3.7-59 +- Rebuilt for MSVSphere 10 + +## START: Generated by rpmautospec +* Fri Jul 19 2024 Fedora Release Engineering - 1.3.7-59 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Fri Jun 07 2024 Python Maint - 1.3.7-58 +- Rebuilt for Python 3.13 + +* Fri Jan 26 2024 Fedora Release Engineering - 1.3.7-45 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Mon Jan 22 2024 Fedora Release Engineering - 1.3.7-44 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Wed Oct 18 2023 Miro Hrončok - 1.3.7-43 +- Don't run 2to3 during package build + +* Fri Jul 21 2023 Fedora Release Engineering - 1.3.7-42 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Tue Jun 13 2023 Python Maint - 1.3.7-41 +- Rebuilt for Python 3.12 + * Fri Jan 20 2023 Fedora Release Engineering - 1.3.7-40 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild @@ -226,7 +258,7 @@ ln -sf nosetests-3.1 %{buildroot}%{_mandir}/man1/nosetests.1 - Rebuilt for Python3.5 rebuild with disabled tests under python3 * Sun Aug 09 2015 Kevin Fenzi 1.3.7-5 -- Add conditional for python-sphinx buildrequires when with_docs is not set. +- Add conditional for python-sphinx buildrequires when with_docs is not set. - Fixes bug #1251700 * Fri Jul 24 2015 Kevin Fenzi 1.3.7-4 @@ -395,3 +427,5 @@ for %%check) * Wed Apr 19 2006 Ignacio Vazquez-Abrams 0.8.7.2-1 - Initial RPM release + +## END: Generated by rpmautospec diff --git a/sources b/sources deleted file mode 100644 index 7a15405..0000000 --- a/sources +++ /dev/null @@ -1 +0,0 @@ -4d3ad0ff07b61373d2cefc89c5d0b20b nose-1.3.7.tar.gz