Skip to content

Commit 5af866e

Browse files
committed
Handle import errors with non-ascii messages when importing plugins
Fix pytest-dev#1998
1 parent 3301a1c commit 5af866e

File tree

4 files changed

+30
-6
lines changed

4 files changed

+30
-6
lines changed

CHANGELOG.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
* Import errors when collecting test modules now display the full traceback (`#1976`_).
77
Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR.
88

9-
*
9+
* When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_).
10+
Thanks `@nicoddemus`_ for the PR.
1011

1112
*
1213

1314

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

1617
.. _#1976: https://github.com/pytest-dev/pytest/issues/1976
18+
.. _#1998: https://github.com/pytest-dev/pytest/issues/1998
1719

1820

1921

_pytest/compat.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,18 @@ def _is_unittest_unexpected_success_a_failure():
213213
Changed in version 3.4: Returns False if there were any
214214
unexpectedSuccesses from tests marked with the expectedFailure() decorator.
215215
"""
216-
return sys.version_info >= (3, 4)
216+
return sys.version_info >= (3, 4)
217+
218+
219+
if _PY3:
220+
def safe_str(v):
221+
"""returns v as string"""
222+
return str(v)
223+
else:
224+
def safe_str(v):
225+
"""returns v as string, converting to ascii if necessary"""
226+
try:
227+
return str(v)
228+
except UnicodeError:
229+
errors = 'replace'
230+
return v.encode('ascii', errors)

_pytest/config.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import _pytest.hookspec # the extension point definitions
1313
import _pytest.assertion
1414
from _pytest._pluggy import PluginManager, HookimplMarker, HookspecMarker
15+
from _pytest.compat import safe_str
1516

1617
hookimpl = HookimplMarker("pytest")
1718
hookspec = HookspecMarker("pytest")
@@ -405,7 +406,8 @@ def import_plugin(self, modname):
405406
try:
406407
__import__(importspec)
407408
except ImportError as e:
408-
new_exc = ImportError('Error importing plugin "%s": %s' % (modname, e))
409+
msg = safe_str(e.args[0])
410+
new_exc = ImportError('Error importing plugin "%s": %s' % (modname, msg))
409411
# copy over name and path attributes
410412
for attr in ('name', 'path'):
411413
if hasattr(e, attr):

testing/test_pluginmanager.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# encoding: UTF-8
12
import pytest
23
import py
34
import os
@@ -179,15 +180,20 @@ def test_default_markers(testdir):
179180
])
180181

181182

182-
def test_importplugin_issue375(testdir, pytestpm):
183+
def test_importplugin_error_message(testdir, pytestpm):
183184
"""Don't hide import errors when importing plugins and provide
184185
an easy to debug message.
186+
187+
See #375 and #1998.
185188
"""
186189
testdir.syspathinsert(testdir.tmpdir)
187-
testdir.makepyfile(qwe="import aaaa")
190+
testdir.makepyfile(qwe="""
191+
# encoding: UTF-8
192+
raise ImportError(u'Not possible to import: ☺')
193+
""")
188194
with pytest.raises(ImportError) as excinfo:
189195
pytestpm.import_plugin("qwe")
190-
expected = '.*Error importing plugin "qwe": No module named \'?aaaa\'?'
196+
expected = '.*Error importing plugin "qwe": Not possible to import: .'
191197
assert py.std.re.match(expected, str(excinfo.value))
192198

193199

0 commit comments

Comments
 (0)