Stop using more-itertools

We barely use it; the couple places that do are not really worth the
extra dependency, I think the code is clearer without it.

Also simplifies one (regular) itertools usage.

Also improves a check and an error message in `pytest.raises`.
This commit is contained in:
Ran Benita 2020-07-30 17:05:32 +03:00
parent 645cbc91fc
commit 96a48f0c66
6 changed files with 40 additions and 22 deletions

View File

@ -0,0 +1 @@
The dependency on the ``more-itertools`` package has been removed.

View File

@ -42,7 +42,6 @@ packages =
install_requires = install_requires =
attrs>=17.4.0 attrs>=17.4.0
iniconfig iniconfig
more-itertools>=4.0.0
packaging packaging
pluggy>=0.12,<1.0 pluggy>=0.12,<1.0
py>=1.8.2 py>=1.8.2

View File

@ -1,6 +1,5 @@
import functools import functools
import inspect import inspect
import itertools
import sys import sys
import warnings import warnings
from collections import defaultdict from collections import defaultdict
@ -1489,10 +1488,10 @@ class FixtureManager:
else: else:
argnames = () argnames = ()
usefixtures = itertools.chain.from_iterable( usefixtures = tuple(
mark.args for mark in node.iter_markers(name="usefixtures") arg for mark in node.iter_markers(name="usefixtures") for arg in mark.args
) )
initialnames = tuple(usefixtures) + argnames initialnames = usefixtures + argnames
fm = node.session._fixturemanager fm = node.session._fixturemanager
initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure( initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure(
initialnames, node, ignore_args=self._get_direct_parametrize_args(node) initialnames, node, ignore_args=self._get_direct_parametrize_args(node)

View File

@ -1,11 +1,9 @@
import inspect
import math import math
import pprint import pprint
from collections.abc import Iterable from collections.abc import Iterable
from collections.abc import Mapping from collections.abc import Mapping
from collections.abc import Sized from collections.abc import Sized
from decimal import Decimal from decimal import Decimal
from itertools import filterfalse
from numbers import Number from numbers import Number
from types import TracebackType from types import TracebackType
from typing import Any from typing import Any
@ -18,8 +16,6 @@ from typing import Tuple
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
from more_itertools.more import always_iterable
import _pytest._code import _pytest._code
from _pytest.compat import overload from _pytest.compat import overload
from _pytest.compat import STRING_TYPES from _pytest.compat import STRING_TYPES
@ -30,9 +26,6 @@ if TYPE_CHECKING:
from typing import Type from typing import Type
BASE_TYPE = (type, STRING_TYPES)
def _non_numeric_type_error(value, at: Optional[str]) -> TypeError: def _non_numeric_type_error(value, at: Optional[str]) -> TypeError:
at_str = " at {}".format(at) if at else "" at_str = " at {}".format(at) if at else ""
return TypeError( return TypeError(
@ -680,11 +673,16 @@ def raises( # noqa: F811
documentation for :ref:`the try statement <python:try>`. documentation for :ref:`the try statement <python:try>`.
""" """
__tracebackhide__ = True __tracebackhide__ = True
for exc in filterfalse(
inspect.isclass, always_iterable(expected_exception, BASE_TYPE) if isinstance(expected_exception, type):
): excepted_exceptions = (expected_exception,) # type: Tuple[Type[_E], ...]
msg = "exceptions must be derived from BaseException, not %s" else:
raise TypeError(msg % type(exc)) excepted_exceptions = expected_exception
for exc in excepted_exceptions:
if not isinstance(exc, type) or not issubclass(exc, BaseException):
msg = "expected exception must be a BaseException type, not {}"
not_a = exc.__name__ if isinstance(exc, type) else type(exc).__name__
raise TypeError(msg.format(not_a))
message = "DID NOT RAISE {}".format(expected_exception) message = "DID NOT RAISE {}".format(expected_exception)

View File

@ -25,7 +25,6 @@ from typing import Union
import attr import attr
import pluggy import pluggy
import py import py
from more_itertools import collapse
import pytest import pytest
from _pytest import nodes from _pytest import nodes
@ -715,11 +714,14 @@ class TerminalReporter:
self._write_report_lines_from_hooks(lines) self._write_report_lines_from_hooks(lines)
def _write_report_lines_from_hooks( def _write_report_lines_from_hooks(
self, lines: List[Union[str, List[str]]] self, lines: Sequence[Union[str, Sequence[str]]]
) -> None: ) -> None:
lines.reverse() for line_or_lines in reversed(lines):
for line in collapse(lines): if isinstance(line_or_lines, str):
self.write_line(line) self.write_line(line_or_lines)
else:
for line in line_or_lines:
self.write_line(line)
def pytest_report_header(self, config: Config) -> List[str]: def pytest_report_header(self, config: Config) -> List[str]:
line = "rootdir: %s" % config.rootdir line = "rootdir: %s" % config.rootdir

View File

@ -283,3 +283,22 @@ class TestRaises:
with pytest.raises(Exception, foo="bar"): # type: ignore[call-overload] with pytest.raises(Exception, foo="bar"): # type: ignore[call-overload]
pass pass
assert "Unexpected keyword arguments" in str(excinfo.value) assert "Unexpected keyword arguments" in str(excinfo.value)
def test_expected_exception_is_not_a_baseexception(self) -> None:
with pytest.raises(TypeError) as excinfo:
with pytest.raises("hello"): # type: ignore[call-overload]
pass # pragma: no cover
assert "must be a BaseException type, not str" in str(excinfo.value)
class NotAnException:
pass
with pytest.raises(TypeError) as excinfo:
with pytest.raises(NotAnException): # type: ignore[type-var]
pass # pragma: no cover
assert "must be a BaseException type, not NotAnException" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
with pytest.raises(("hello", NotAnException)): # type: ignore[arg-type]
pass # pragma: no cover
assert "must be a BaseException type, not str" in str(excinfo.value)