-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Hi,
I recently update to pytest 3.5.0 and use it to test applications that use spyne.
Unfortunately, my tests that have code like
import pytest
from spyne.errors import RequestNotAllowed, InvalidCredentialsError
import mymodule
def test_a():
with pytest.raises(RequestNotAllowed):
mymodule.func_that_raises_request_not_allowed()
def test_b():
with pytest.raises(InvalidCredentialsError):
mymodule.func_that_raises_invalid_credentials_error()
now break in the lines starting on with pytest.raises
and give a traceback similar to this one:
___ test_detect_replay_nonce[example_forecast.xml.gz] ___
def test_a():
> with pytest.raises(RequestNotAllowed):
tests/test_client.py:130:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/foobar/lib/python3.6/site-packages/_pytest/python_api.py:587: in raises
for exc in filterfalse(isclass, always_iterable(expected_exception)):
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <class 'spyne.error.RequestNotAllowed'>, item = 0
def __getitem__(self, item):
> return self.customize(**item)
E TypeError: customize() argument after ** must be a mapping, not int
/foobar/lib/python3.6/site-packages/spyne/model/_base.py:179: TypeError
The issue didn't come up in previous versions of pytest so I dug a bit and found that
- pytest.raises changed in version 3.5.0 to use
always_iterable
, - the exception classes used by spyne both have a
__len__
and a__getitem__
function, - python thinks that the exception class is iterable,
and that this is the cause of these unexpected problems.
I don't know whether exception classes that look iterable are generally disallowed or if this is something that should be supported/fixed in pytest.
I didn't find this behavior change to be mentioned in the changelog but I may have not looked thoroughly enough.
Perhaps you can advise?
Thanks!
Tim
Here is some IPython output from my digging:
Python 3.6.5
Type 'copyright', 'credits' or 'license' for more information
IPython 6.3.0 -- An enhanced Interactive Python. Type '?' for help.
Warning: disable autoreload in ipython_config.py to improve performance.
In [1]: from spyne.error import InvalidCredentialsError
In [2]: hasattr(InvalidCredentialsError, '__getitem__')
Out[2]: True
In [3]: hasattr(InvalidCredentialsError, '__len__')
Out[3]: True
In [4]: from more_itertools.more import always_iterable
In [5]: next(always_iterable(InvalidCredentialsError))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-24d61822a93e> in <module>()
----> 1 next(always_iterable(InvalidCredentialsError))
/foobar/lib/python3.6/site-packages/spyne/model/_base.py in __getitem__(self, item)
177 class ModelBaseMeta(type(object)):
178 def __getitem__(self, item):
--> 179 return self.customize(**item)
180
181 def customize(self, **kwargs):
TypeError: customize() argument after ** must be a mapping, not int
always_iterable
attempts to create an iterable by executing
try:
return iter(obj)
except TypeError:
return iter((obj,))
In [6]: next(iter(InvalidCredentialsError))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-5759e2f7cde0> in <module>()
----> 1 next(iter(InvalidCredentialsError))
/foobar/lib/python3.6/site-packages/spyne/model/_base.py in __getitem__(self, item)
177 class ModelBaseMeta(type(object)):
178 def __getitem__(self, item):
--> 179 return self.customize(**item)
180
181 def customize(self, **kwargs):
TypeError: customize() argument after ** must be a mapping, not int
I'm using
- python 3.6.5
- pytest 3.5.0
- spyne 2.12.14
It works in pytest 3.4.2 where always_iterable
isn't used in functionraises
of _pytest/python_api.py
.