Repository: nose-devs/nose2

Issue:
changelog.rst does not describe differences in 0.5.0
PyPI has 0.5.0 but the changelog.rst only describes changes up to 0.4.7.  What's new in 0.5.0?


Comments:

Patch:
diff --git a/.travis.yml b/.travis.yml
index 29ef0a7..9137f5f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,9 +10,12 @@ python:
 - '3.4'
 - '3.5'
 - '3.6'
-# include 3.7-dev, but put it in allow_failures (so we can easily view status,
-# but not block on it)
-- '3.7-dev'
+matrix:
+  fast_finish: true
+  include:
+  - python: '3.7'
+    dist: xenial    # required for Python 3.7 (travis-ci/travis-ci#9069)
+    sudo: required  # required for Python 3.7 (travis-ci/travis-ci#9069)
 install:
 - travis_retry pip install tox-travis
 - travis_retry pip install coveralls
@@ -30,10 +33,6 @@ deploy:
     tags: true
     distributions: sdist bdist_wheel
     repo: nose-devs/nose2
-matrix:
-  fast_finish: true
-  allow_failures:
-  - python: "3.7-dev"
 notifications:
   webhooks:
     urls:
diff --git a/README.rst b/README.rst
index d5c20d3..0ff4532 100644
--- a/README.rst
+++ b/README.rst
@@ -1,24 +1,16 @@
-.. image:: https://travis-ci.org/nose-devs/nose2.png?branch=master
+.. image:: https://travis-ci.org/nose-devs/nose2.svg?branch=master
     :target: https://travis-ci.org/nose-devs/nose2
     :alt: Build Status
-    
-.. image:: https://coveralls.io/repos/nose-devs/nose2/badge.png?branch=master
-    :target: https://coveralls.io/r/nose-devs/nose2?branch=master
+
+.. image:: https://coveralls.io/repos/github/nose-devs/nose2/badge.svg?branch=master
+    :target: https://coveralls.io/github/nose-devs/nose2?branch=master
     :alt: Coverage Status
-    
-.. image:: https://landscape.io/github/nose-devs/nose2/master/landscape.png
-   :target: https://landscape.io/github/nose-devs/nose2/master
-   :alt: Code Health
-    
+
 .. image:: https://img.shields.io/pypi/v/nose2.svg
     :target: https://pypi.org/project/nose2/
     :alt: Latest PyPI version
 
-.. image:: https://www.versioneye.com/user/projects/52037a30632bac57a00257ea/badge.png
-    :target: https://www.versioneye.com/user/projects/52037a30632bac57a00257ea/
-    :alt: Dependencies Status    
-
-.. image:: https://badges.gitter.im/gitterHQ/gitter.png
+.. image:: https://badges.gitter.im/gitterHQ/gitter.svg
     :target: https://gitter.im/nose2
     :alt: Gitter Channel
 
diff --git a/docs/changelog.rst b/docs/changelog.rst
index a855226..0ca0c62 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -103,6 +103,37 @@ Added support for python 3.6.
     * Make the ``collect`` plugin work with layers
     * Fix coverage plugin to take import-time coverage into account
 
+0.5.0
+-----
+
+* Added
+    * Add with_setup and with_teardown decorators to set the setup & teardown
+      on a function
+    * dundertests plugin to skip tests with `__test__ == False`
+    * Add `cartesian_params` decorator
+    * Add coverage plugin
+    * Add EggDiscoveryLoader for discovering tests within Eggs
+    * Support `params` with `such`
+    * `such` errors early if Layers plugin is not loaded
+    * Include logging output in junit XML
+
+* Fixed
+    * Such DSL ignores two `such.A` with the same description
+    * Record skipped tests as 'skipped' instead of 'skips'
+    * Result output failed on unicode characters
+    * Fix multiprocessing plugin on Windows
+    * Allow use of `nose2.main()` from within a test module
+    * Ensure plugins write to the event stream
+    * multiprocessing could lock master proc and fail to exit
+    * junit report path was sensitive to changes in cwd
+    * Test runs would crash if a TestCase `__init__` threw an exception
+    * Plugin failures no longer crash the whole test run
+    * Handle errors in test setup and teardown
+    * Fix reporting of xfail tests
+    * Log capture was waiting too long to render mutable objects to strings
+    * Layers plugin was not running testSetUp/testTearDown from higher `such` layers
+
+
 0.4.7
 -----
 
diff --git a/nose2/plugins/junitxml.py b/nose2/plugins/junitxml.py
index ced1ce7..9f8f50a 100644
--- a/nose2/plugins/junitxml.py
+++ b/nose2/plugins/junitxml.py
@@ -160,6 +160,9 @@ class JUnitXmlReporter(events.Plugin):
         elif event.outcome == result.SKIP:
             self.skipped += 1
             skipped = ET.SubElement(testcase, 'skipped')
+            if msg:
+                skipped.set('message', 'test skipped')
+                skipped.text = msg
         elif event.outcome == result.FAIL and event.expected:
             self.skipped += 1
             skipped = ET.SubElement(testcase, 'skipped')
@@ -245,15 +248,6 @@ class JUnitXmlReporter(events.Plugin):
 # xml utility functions
 #
 
-# six doesn't include a unichr function
-
-
-def _unichr(string):
-    if six.PY3:
-        return chr(string)
-    else:
-        return unichr(string)
-
 # etree outputs XML 1.0 so the 1.1 Restricted characters are invalid.
 # and there are no characters that can be given as entities aside
 # form & < > ' " which ever have to be escaped (etree handles these fine)
@@ -278,12 +272,12 @@ if sys.maxunicode > 0xFFFF:
 
 ILLEGAL_REGEX_STR = \
     six.u('[') + \
-    six.u('').join(["%s-%s" % (_unichr(l), _unichr(h))
+    six.u('').join(["%s-%s" % (six.unichr(l), six.unichr(h))
                     for (l, h) in ILLEGAL_RANGES]) + \
     six.u(']')
 RESTRICTED_REGEX_STR = \
     six.u('[') + \
-    six.u('').join(["%s-%s" % (_unichr(l), _unichr(h))
+    six.u('').join(["%s-%s" % (six.unichr(l), six.unichr(h))
                     for (l, h) in RESTRICTED_RANGES]) + \
     six.u(']')
 
diff --git a/setup.py b/setup.py
index b6084bb..495076b 100644
--- a/setup.py
+++ b/setup.py
@@ -25,6 +25,7 @@ CLASSIFIERS = [
     'Programming Language :: Python :: 3.4',
     'Programming Language :: Python :: 3.5',
     'Programming Language :: Python :: 3.6',
+    'Programming Language :: Python :: 3.7',
     'Programming Language :: Python :: Implementation :: CPython',
     'Programming Language :: Python :: Implementation :: PyPy',
     'Operating System :: OS Independent',


Test patch:
diff --git a/nose2/tests/unit/test_junitxml.py b/nose2/tests/unit/test_junitxml.py
index 9bfae3b..0748672 100644
--- a/nose2/tests/unit/test_junitxml.py
+++ b/nose2/tests/unit/test_junitxml.py
@@ -88,6 +88,9 @@ class TestJunitXmlPlugin(TestCase):
             def test_skip(self):
                 self.skipTest('skip')
 
+            def test_skip_no_reason(self):
+                self.skipTest('')
+
             def test_bad_xml(self):
                 raise RuntimeError(TestJunitXmlPlugin.BAD_FOR_XML_U)
 
@@ -172,6 +175,17 @@ class TestJunitXmlPlugin(TestCase):
         case = self.plugin.tree.find('testcase')
         skip = case.find('skipped')
         assert skip is not None
+        self.assertEqual(skip.get('message'), 'test skipped')
+        self.assertEqual(skip.text, 'skip')
+
+    def test_skip_includes_skipped_no_reason(self):
+        test = self.case('test_skip_no_reason')
+        test(self.result)
+        case = self.plugin.tree.find('testcase')
+        skip = case.find('skipped')
+        assert skip is not None
+        self.assertIsNone(skip.get('message'))
+        self.assertIsNone(skip.text)
 
     def test_generator_test_name_correct(self):
         gen = generators.Generators(session=self.session)
@@ -234,7 +248,7 @@ class TestJunitXmlPlugin(TestCase):
         for case in event.extraTests:
             case(self.result)
         xml = self.plugin.tree.findall('testcase')
-        self.assertEqual(len(xml), 12)
+        self.assertEqual(len(xml), 13)
         params = [x for x in xml if x.get('name').startswith('test_params')]
         self.assertEqual(len(params), 3)
         self.assertEqual(params[0].get('name'), 'test_params:1')
@@ -259,7 +273,7 @@ class TestJunitXmlPlugin(TestCase):
         for case in event.extraTests:
             case(self.result)
         xml = self.plugin.tree.findall('testcase')
-        self.assertEqual(len(xml), 12)
+        self.assertEqual(len(xml), 13)
         params = [x for x in xml if x.get('name').startswith('test_params')]
         self.assertEqual(len(params), 3)
         self.assertEqual(params[0].get('name'), 'test_params:1 (1)')