[Pytest-commit] Issue #589: pytest incorrectly considers NotImplementedError when detecting recursion (hpk42/pytest)

Charles Cloud issues-reply at bitbucket.org
Fri Sep 12 19:10:13 CEST 2014


New issue 589: pytest incorrectly considers NotImplementedError when detecting recursion
https://bitbucket.org/hpk42/pytest/issue/589/pytest-incorrectly-considers

Charles Cloud:

Here's an example where this happens:

```python
import operator


class EqList(list):
    def __init__(self, *args):
        super(EqList, self).__init__(*args)

    def __nonzero__(self):
        raise ValueError('this is what numpy does')

    def __bool__(self):
        if len(self) > 1:
            return self.__nonzero__()
        return bool(len(self))

    def __eq__(self, other):
        if not isinstance(other, EqList):
            return EqList([False] * len(self))
        return EqList(map(operator.eq, list(self), list(other)))


_typecache = {}


def dispatch(*types):
    def wrapper(f):
        _typecache[types] = f

        def wrapped(*args, **kwargs):
            func = _typecache[tuple(map(type, args))]
            return func(*args, **kwargs)
        return wrapped
    return wrapper


@dispatch(object)
def flatten(o):
    return [o]


@dispatch(tuple)
def flatten(t):
    return flatten(list(t))


@dispatch(EqList)
def flatten(s):
    raise NotImplementedError('EqList bork')


@dispatch(list)
def flatten(lst):
    for el in lst:
        for e in flatten(el):
            yield e


def test_flatten():
    r = EqList([1, 2, 3])
    x = list(flatten([(r,)]))
    assert x is not None


if __name__ == '__main__':
    test_flatten()
```

The issue is the interaction between

1. `py.test` checking for `NotImplementedError` when detecting recursion followed by
2. comparison of variables in scope between a function appearing to be recursive and
3. any variables in said scopes that do not return a scalar `bool` from their `__eq__` method.

The above code should raise `NotImplementedError`, not a huge `INTERNALERROR` traceback because it couldn't compare variables when trying to detect recursion. Running with

```sh
$ python above_file.py
```
does the right thing, while

```sh
$ py.test above_file.py
```
yields a huge `INTERNALERROR` traceback ending in:

```
INTERNALERROR>   File "/Users/pcloud/test_pytest.py", line 15, in __bool__
INTERNALERROR>     return self.__nonzero__()
INTERNALERROR>   File "/Users/pcloud/test_pytest.py", line 11, in __nonzero__
INTERNALERROR>     raise ValueError('this is what numpy does')
INTERNALERROR> ValueError: this is what numpy does
```

I propose that instead of checking for general `RuntimeError`s (which includes subclasses), that `py.test` check for the *exact* type of `RuntimeError`. `NotImplementedError` doesn't seem like an exception that would indicate recursion.




More information about the pytest-commit mailing list