From bd065a12bb186d0488dd67fbf212391c1275ac45 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 23 May 2017 07:40:39 +0200 Subject: [PATCH 1/9] Fix up 3.1 changelog --- CHANGELOG.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 049d5ead0..9009d575a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -53,8 +53,6 @@ Changes * ``--pdbcls`` no longer implies ``--pdb``. This makes it possible to use ``addopts=--pdbcls=module.SomeClass`` on ``pytest.ini``. Thanks `@davidszotten`_ for the PR (`#1952`_). -* Change exception raised by ``capture.DontReadFromInput.fileno()`` from ``ValueError`` - to ``io.UnsupportedOperation``. Thanks `@vlad-dragos`_ for the PR. * fix `#2013`_: turn RecordedWarning into ``namedtuple``, to give it a comprehensible repr while preventing unwarranted modification. @@ -86,7 +84,7 @@ Changes Thanks `@RonnyPfannschmidt`_ for the PR. * fix `#2391`_: consider pytest_plugins on all plugin modules - Thansks `@RonnyPfannschmidt`_ for the PR. + Thanks `@RonnyPfannschmidt`_ for the PR. Bug Fixes @@ -98,7 +96,7 @@ Bug Fixes * Change capture.py's ``DontReadFromInput`` class to throw ``io.UnsupportedOperation`` errors rather than ValueErrors in the ``fileno`` method (`#2276`_). - Thanks `@metasyn`_ for the PR. + Thanks `@metasyn`_ and `@vlad-dragos`_ for the PR. * Fix exception formatting while importing modules when the exception message contains non-ascii characters (`#2336`_). From 7d6bde2496c47c72c4c692ad3f8049b0f896769e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 23 May 2017 07:57:34 +0200 Subject: [PATCH 2/9] Add docs for id= with pytest.param --- doc/en/example/parametrize.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index 7a9992ca7..bb286b472 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -116,6 +116,15 @@ the argument name:: diff = a - b assert diff == expected + @pytest.mark.parametrize("a,b,expected", [ + pytest.param(datetime(2001, 12, 12), datetime(2001, 12, 11), + timedelta(1), id='forward'), + pytest.param(datetime(2001, 12, 11), datetime(2001, 12, 12), + timedelta(-1), id='backward'), + ]) + def test_timedistance_v3(a, b, expected): + diff = a - b + assert diff == expected In ``test_timedistance_v0``, we let pytest generate the test IDs. @@ -132,7 +141,7 @@ objects, they are still using the default pytest representation:: ======= test session starts ======== platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y rootdir: $REGENDOC_TMPDIR, inifile: - collected 6 items + collected 8 items @@ -140,9 +149,14 @@ objects, they are still using the default pytest representation:: + + ======= no tests ran in 0.12 seconds ======== +In ``test_timedistance_v3``, we used ``pytest.param`` to specify the test IDs +together with the actual data, instead of listing them separately. + A quick port of "testscenarios" ------------------------------------ From d9b93674c3563d62a3b8529d324c8590aaa28665 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 23 May 2017 08:01:39 +0200 Subject: [PATCH 3/9] Make --cache-show output deterministic This makes sure things don't jump around in the regenerated docs. --- _pytest/cacheprovider.py | 4 ++-- doc/en/cache.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_pytest/cacheprovider.py b/_pytest/cacheprovider.py index ab08362ee..7fc08fff3 100755 --- a/_pytest/cacheprovider.py +++ b/_pytest/cacheprovider.py @@ -219,7 +219,7 @@ def cacheshow(config, session): basedir = config.cache._cachedir vdir = basedir.join("v") tw.sep("-", "cache values") - for valpath in vdir.visit(lambda x: x.isfile()): + for valpath in sorted(vdir.visit(lambda x: x.isfile())): key = valpath.relto(vdir).replace(valpath.sep, "/") val = config.cache.get(key, dummy) if val is dummy: @@ -235,7 +235,7 @@ def cacheshow(config, session): ddir = basedir.join("d") if ddir.isdir() and ddir.listdir(): tw.sep("-", "cache directories") - for p in basedir.join("d").visit(): + for p in sorted(basedir.join("d").visit()): #if p.check(dir=1): # print("%s/" % p.relto(basedir)) if p.isfile(): diff --git a/doc/en/cache.rst b/doc/en/cache.rst index 9672562af..688b6dd04 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -231,10 +231,10 @@ You can always peek at the content of the cache using the rootdir: $REGENDOC_TMPDIR, inifile: cachedir: $REGENDOC_TMPDIR/.cache ------------------------------- cache values ------------------------------- - example/value contains: - 42 cache/lastfailed contains: {'test_caching.py::test_function': True} + example/value contains: + 42 ======= no tests ran in 0.12 seconds ======== From c39689da41eee6656d2956d20c09b6725151583d Mon Sep 17 00:00:00 2001 From: wanghui Date: Thu, 25 May 2017 17:59:42 +0800 Subject: [PATCH 4/9] Correct warnings with unicode message. --- _pytest/warnings.py | 4 +++- testing/test_warnings.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/_pytest/warnings.py b/_pytest/warnings.py index bfa2b0087..7596b0098 100644 --- a/_pytest/warnings.py +++ b/_pytest/warnings.py @@ -5,6 +5,8 @@ from contextlib import contextmanager import pytest +from _pytest import compat + def _setoption(wmod, arg): """ @@ -62,7 +64,7 @@ def catch_warnings_for_item(item): for warning in log: msg = warnings.formatwarning( - warning.message, warning.category, + compat.safe_str(warning.message), warning.category, warning.filename, warning.lineno, warning.line) item.warn("unused", msg) diff --git a/testing/test_warnings.py b/testing/test_warnings.py index e0baed8d1..85fda430e 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -1,3 +1,6 @@ +# -*- coding: utf8 -*- +from __future__ import unicode_literals + import pytest @@ -106,3 +109,29 @@ def test_ignore(testdir, pyfile_with_warnings, method): ]) assert WARNINGS_SUMMARY_HEADER not in result.stdout.str() + + +def test_unicode(testdir, pyfile_with_warnings): + testdir.makepyfile(''' + # -*- coding: utf8 -*- + import warnings + import pytest + + + @pytest.fixture + def fix(): + warnings.warn(u"测试") + yield + + def test_func(fix): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== %s ==*' % WARNINGS_SUMMARY_HEADER, + + '*test_unicode.py:8: UserWarning: \u6d4b\u8bd5', + '*warnings.warn(u"\u6d4b\u8bd5")', + '* 1 passed, 1 warnings*', + ]) + From 313a884459385adf41d966523659f710febcd7de Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 25 May 2017 21:19:08 -0300 Subject: [PATCH 5/9] Warn that warning-capture can break existing suites in the docs and CHANGELOG Related to discussion in #2430 --- CHANGELOG.rst | 18 ++++++++++++++++-- doc/en/warnings.rst | 14 ++++++++++++++ tox.ini | 2 ++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9009d575a..942dc481e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,11 +5,25 @@ New Features ------------ -* The ``pytest-warnings`` plugin has been integrated into the core, so now ``pytest`` automatically +* The ``pytest-warnings`` plugin has been integrated into the core and now ``pytest`` automatically captures and displays warnings at the end of the test session. + + .. warning:: + + This feature may disrupt test suites which apply and treat warnings themselves, and can be + disabled in your ``pytest.ini``: + + .. code-block:: ini + + [pytest] + addopts = -p no:warnings + + See the `warnings documentation page `_ for more + information. + Thanks `@nicoddemus`_ for the PR. -* Added ``junit_suite_name`` ini option to specify root `` name for JUnit XML reports (`#533`_). +* Added ``junit_suite_name`` ini option to specify root ```` name for JUnit XML reports (`#533`_). * Added an ini option ``doctest_encoding`` to specify which encoding to use for doctest files. Thanks `@wheerd`_ for the PR (`#2101`_). diff --git a/doc/en/warnings.rst b/doc/en/warnings.rst index 1766f997c..20ea00a65 100644 --- a/doc/en/warnings.rst +++ b/doc/en/warnings.rst @@ -5,6 +5,20 @@ Warnings Capture .. versionadded:: 3.1 +.. warning:: + pytest captures all warnings between tests, which prevents custom warning + filters in existing test suites from working. If this causes problems to your test suite, + this plugin can be disabled in your ``pytest.ini`` file with: + + .. code-block:: ini + + [pytest] + addopts = -p no:warnings + + There's an ongoing discussion about this on `#2430 + `_. + + Starting from version ``3.1``, pytest now automatically catches all warnings during test execution and displays them at the end of the session:: diff --git a/tox.ini b/tox.ini index a2d4af9ed..f30557a4b 100644 --- a/tox.ini +++ b/tox.ini @@ -46,6 +46,8 @@ commands= [testenv:linting] +skipsdist=True +usedevelop=True basepython = python2.7 # needed to keep check-manifest working setenv = From d7a5c5716f2386c083a2658708c4a3d9eda522c4 Mon Sep 17 00:00:00 2001 From: wanghui Date: Fri, 26 May 2017 13:12:02 +0800 Subject: [PATCH 6/9] Add UnicodeWarning for unicode warnings in Python2 --- _pytest/compat.py | 2 ++ _pytest/warnings.py | 15 ++++++++++++++- testing/test_warnings.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/_pytest/compat.py b/_pytest/compat.py index 25610b645..8c200af5f 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -126,6 +126,7 @@ if _PY3: import codecs imap = map STRING_TYPES = bytes, str + UNICODE_TYPES = str, def _escape_strings(val): """If val is pure ascii, returns it as a str(). Otherwise, escapes @@ -157,6 +158,7 @@ if _PY3: return val.encode('unicode_escape').decode('ascii') else: STRING_TYPES = bytes, str, unicode + UNICODE_TYPES = unicode, from itertools import imap # NOQA diff --git a/_pytest/warnings.py b/_pytest/warnings.py index 7596b0098..cbed43b8f 100644 --- a/_pytest/warnings.py +++ b/_pytest/warnings.py @@ -63,11 +63,24 @@ def catch_warnings_for_item(item): yield for warning in log: + warn_msg = warning.message + unicode_warning = False + + if compat._PY2 and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args): + warn_msg.args = [compat.safe_str(m) for m in warn_msg.args] + unicode_warning = True + msg = warnings.formatwarning( - compat.safe_str(warning.message), warning.category, + warn_msg, warning.category, warning.filename, warning.lineno, warning.line) item.warn("unused", msg) + if unicode_warning: + warnings.warn( + "This warning %s is broken as it's message is not a str instance" + "(after all this is a stdlib problem workaround)" % msg, + UnicodeWarning) + @pytest.hookimpl(hookwrapper=True) def pytest_runtest_protocol(item): diff --git a/testing/test_warnings.py b/testing/test_warnings.py index 85fda430e..df9c4cdc4 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -1,6 +1,8 @@ # -*- coding: utf8 -*- from __future__ import unicode_literals +import sys + import pytest @@ -111,6 +113,8 @@ def test_ignore(testdir, pyfile_with_warnings, method): +@pytest.mark.skipif(sys.version_info < (3, 0), + reason='warnings message is unicode is ok in python3') def test_unicode(testdir, pyfile_with_warnings): testdir.makepyfile(''' # -*- coding: utf8 -*- @@ -135,3 +139,30 @@ def test_unicode(testdir, pyfile_with_warnings): '* 1 passed, 1 warnings*', ]) + +@pytest.mark.skipif(sys.version_info >= (3, 0), + reason='warnings message is broken as it is not str instance') +def test_py2_unicode(testdir, pyfile_with_warnings): + testdir.makepyfile(''' + # -*- coding: utf8 -*- + import warnings + import pytest + + + @pytest.fixture + def fix(): + warnings.warn(u"测试") + yield + + def test_func(fix): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*== %s ==*' % WARNINGS_SUMMARY_HEADER, + + '*test_py2_unicode.py:8: UserWarning: \u6d4b\u8bd5', + '*warnings.warn(u"\u6d4b\u8bd5")', + '*warnings.py:82: UnicodeWarning: This warning*\u6d4b\u8bd5', + '* 1 passed, 2 warnings*', + ]) From 53add4435f64363cb2d79299013ea850024dcd86 Mon Sep 17 00:00:00 2001 From: wanghui Date: Fri, 26 May 2017 13:14:42 +0800 Subject: [PATCH 7/9] Add ChangeLog --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9009d575a..9133d5f5b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,9 @@ +3.1.1 (unreleased) +================== + +* Fix encoding errors for unicode warnings in Python 2. + + 3.1.0 (2017-05-22) ================== From 836dc451f46f63ea7ae0f1ec0132b507838466f2 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 25 May 2017 17:08:32 -0300 Subject: [PATCH 8/9] Fix unicode issue while running doctests in Python 2 Fix #2434 --- CHANGELOG.rst | 4 +++- _pytest/doctest.py | 29 +++++++++++++++++++++++++++++ testing/test_doctest.py | 22 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9133d5f5b..03e2fe294 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,9 @@ 3.1.1 (unreleased) ================== -* Fix encoding errors for unicode warnings in Python 2. +* Fix encoding errors for unicode warnings in Python 2. (towncrier: 2436.bugfix) + +* Fix issue with non-ascii contents in doctest text files. (towncrier: 2434.bugfix) 3.1.0 (2017-05-22) diff --git a/_pytest/doctest.py b/_pytest/doctest.py index f9299be72..46b49d212 100644 --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -181,6 +181,7 @@ class DoctestTextfile(pytest.Module): optionflags = get_optionflags(self) runner = doctest.DebugRunner(verbose=0, optionflags=optionflags, checker=_get_checker()) + _fix_spoof_python2(runner, encoding) parser = doctest.DocTestParser() test = parser.get_doctest(text, globs, name, filename, 0) @@ -216,6 +217,10 @@ class DoctestModule(pytest.Module): optionflags = get_optionflags(self) runner = doctest.DebugRunner(verbose=0, optionflags=optionflags, checker=_get_checker()) + + encoding = self.config.getini("doctest_encoding") + _fix_spoof_python2(runner, encoding) + for test in finder.find(module, module.__name__): if test.examples: # skip empty doctests yield DoctestItem(test.name, self, runner, test) @@ -324,6 +329,30 @@ def _get_report_choice(key): DOCTEST_REPORT_CHOICE_NONE: 0, }[key] + +def _fix_spoof_python2(runner, encoding): + """ + Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output. + + This fixes the problem related in issue #2434. + """ + from _pytest.compat import _PY2 + if not _PY2: + return + + from doctest import _SpoofOut + + class UnicodeSpoof(_SpoofOut): + + def getvalue(self): + result = _SpoofOut.getvalue(self) + if encoding: + result = result.decode(encoding) + return result + + runner._fakeout = UnicodeSpoof() + + @pytest.fixture(scope='session') def doctest_namespace(): """ diff --git a/testing/test_doctest.py b/testing/test_doctest.py index 82597b477..e22976c75 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -505,6 +505,28 @@ class TestDoctests(object): "--junit-xml=junit.xml") reprec.assertoutcome(failed=1) + def test_unicode_doctest(self, testdir): + """ + Test case for issue 2434: DecodeError on Python 2 when doctest contains non-ascii + characters. + """ + p = testdir.maketxtfile(test_unicode_doctest=""" + .. doctest:: + + >>> print( + ... "Hi\\n\\nByé") + Hi + ... + Byé + >>> 1/0 # Byé + 1 + """) + result = testdir.runpytest(p) + result.stdout.fnmatch_lines([ + '*UNEXPECTED EXCEPTION: ZeroDivisionError*', + '*1 failed*', + ]) + class TestLiterals(object): From 7950c26a8efa6f819d6ed954c4be1897a57d9f34 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 26 May 2017 08:09:29 -0300 Subject: [PATCH 9/9] Add Hui Wang to AUTHORS list --- AUTHORS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 90e639234..25829a464 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,8 +13,8 @@ Andreas Zeidler Andrzej Ostrowski Andy Freeland Anthon van der Neut -Antony Lee Anthony Sottile +Antony Lee Armin Rigo Aron Curzon Aviv Palivoda @@ -70,6 +70,7 @@ Grig Gheorghiu Grigorii Eremeev (budulianin) Guido Wesdorp Harald Armin Massa +Hui Wang (coldnight) Ian Bicking Jaap Broekhuizen Jan Balster @@ -158,8 +159,8 @@ Trevor Bekolay Tyler Goodlet Vasily Kuznetsov Victor Uriarte -Vlad Dragos Vidar T. Fauske Vitaly Lashmanov +Vlad Dragos Wouter van Ackooy Xuecong Liao