diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 96a257781..237ea478f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,8 @@ * Import errors when collecting test modules now display the full traceback (`#1976`_). Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. -* +* When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). + Thanks `@nicoddemus`_ for the PR. * @@ -14,6 +15,7 @@ .. _@cwitty: https://github.com/cwitty .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 +.. _#1998: https://github.com/pytest-dev/pytest/issues/1998 @@ -28,7 +30,7 @@ (``pip install -e``) (`#1934`_). Thanks `@nicoddemus`_ for the PR. -* Fix pkg_resources import error in Jython projects (`#1853`). +* Fix pkg_resources import error in Jython projects (`#1853`_). Thanks `@raquel-ucl`_ for the PR. * Got rid of ``AttributeError: 'Module' object has no attribute '_obj'`` exception @@ -48,6 +50,7 @@ .. _@axil: https://github.com/axil .. _@tgoodlet: https://github.com/tgoodlet +.. _#1853: https://github.com/pytest-dev/pytest/issues/1853 .. _#1905: https://github.com/pytest-dev/pytest/issues/1905 .. _#1934: https://github.com/pytest-dev/pytest/issues/1934 .. _#1944: https://github.com/pytest-dev/pytest/issues/1944 diff --git a/_pytest/compat.py b/_pytest/compat.py index 1d8c2f331..51fc3bc5c 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -213,4 +213,18 @@ def _is_unittest_unexpected_success_a_failure(): Changed in version 3.4: Returns False if there were any unexpectedSuccesses from tests marked with the expectedFailure() decorator. """ - return sys.version_info >= (3, 4) \ No newline at end of file + return sys.version_info >= (3, 4) + + +if _PY3: + def safe_str(v): + """returns v as string""" + return str(v) +else: + def safe_str(v): + """returns v as string, converting to ascii if necessary""" + try: + return str(v) + except UnicodeError: + errors = 'replace' + return v.encode('ascii', errors) diff --git a/_pytest/config.py b/_pytest/config.py index 661a8513d..a169a68a2 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -12,6 +12,7 @@ import _pytest._code import _pytest.hookspec # the extension point definitions import _pytest.assertion from _pytest._pluggy import PluginManager, HookimplMarker, HookspecMarker +from _pytest.compat import safe_str hookimpl = HookimplMarker("pytest") hookspec = HookspecMarker("pytest") @@ -405,7 +406,7 @@ class PytestPluginManager(PluginManager): try: __import__(importspec) except ImportError as e: - new_exc = ImportError('Error importing plugin "%s": %s' % (modname, e)) + new_exc = ImportError('Error importing plugin "%s": %s' % (modname, safe_str(e.args[0]))) # copy over name and path attributes for attr in ('name', 'path'): if hasattr(e, attr): diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 36847638d..e61c84247 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -1,3 +1,4 @@ +# encoding: UTF-8 import pytest import py import os @@ -179,15 +180,20 @@ def test_default_markers(testdir): ]) -def test_importplugin_issue375(testdir, pytestpm): +def test_importplugin_error_message(testdir, pytestpm): """Don't hide import errors when importing plugins and provide an easy to debug message. + + See #375 and #1998. """ testdir.syspathinsert(testdir.tmpdir) - testdir.makepyfile(qwe="import aaaa") + testdir.makepyfile(qwe=""" + # encoding: UTF-8 + raise ImportError(u'Not possible to import: ☺') + """) with pytest.raises(ImportError) as excinfo: pytestpm.import_plugin("qwe") - expected = '.*Error importing plugin "qwe": No module named \'?aaaa\'?' + expected = '.*Error importing plugin "qwe": Not possible to import: .' assert py.std.re.match(expected, str(excinfo.value))