Skip to content

Commit

Permalink
Handle import errors with non-ascii messages when importing plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoddemus committed Oct 12, 2016
1 parent 3301a1c commit 5af866e
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 6 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
* 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.

*


.. _@cwitty: https://github.com/cwitty

.. _#1976: https://github.com/pytest-dev/pytest/issues/1976
.. _#1998: https://github.com/pytest-dev/pytest/issues/1998



Expand Down
16 changes: 15 additions & 1 deletion _pytest/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
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)
4 changes: 3 additions & 1 deletion _pytest/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
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")
Expand Down Expand Up @@ -405,7 +406,8 @@ def import_plugin(self, modname):
try:
__import__(importspec)
except ImportError as e:
new_exc = ImportError('Error importing plugin "%s": %s' % (modname, e))
msg = safe_str(e.args[0])
new_exc = ImportError('Error importing plugin "%s": %s' % (modname, msg))
# copy over name and path attributes
for attr in ('name', 'path'):
if hasattr(e, attr):
Expand Down
12 changes: 9 additions & 3 deletions testing/test_pluginmanager.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# encoding: UTF-8
import pytest
import py
import os
Expand Down Expand Up @@ -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))


Expand Down

0 comments on commit 5af866e

Please sign in to comment.