Merge pull request #11914 - Activate flake8-bugbear and flake8-pyi

This commit is contained in:
Pierre Sassoulas 2024-02-05 09:37:37 +01:00 committed by GitHub
commit 0d1f4c63fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 64 additions and 52 deletions

View File

@ -128,15 +128,24 @@ ignore = "W009"
src = ["src"]
line-length = 88
select = [
"B", # bugbear
"D", # pydocstyle
"E", # pycodestyle
"F", # pyflakes
"I", # isort
"PYI", # flake8-pyi
"UP", # pyupgrade
"RUF", # ruff
"W", # pycodestyle
]
ignore = [
# bugbear ignore
"B004", # Using `hasattr(x, "__call__")` to test if x is callable is unreliable.
"B007", # Loop control variable `i` not used within loop body
"B009", # Do not call `getattr` with a constant attribute value
"B010", # [*] Do not call `setattr` with a constant attribute value.
"B011", # Do not `assert False` (`python -O` removes these calls)
"B028", # No explicit `stacklevel` keyword argument found
# pycodestyle ignore
# pytest can do weird low-level things, and we usually know
# what we're doing when we use type(..) is ...
@ -180,4 +189,6 @@ known-local-folder = ["pytest", "_pytest"]
lines-after-imports = 2
[tool.ruff.lint.per-file-ignores]
"src/_pytest/_py/**/*.py" = ["B", "PYI"]
"src/_pytest/_version.py" = ["I001"]
"testing/python/approx.py" = ["B015"]

View File

@ -79,7 +79,7 @@ def prepare_release_pr(
)
except InvalidFeatureRelease as e:
print(f"{Fore.RED}{e}")
raise SystemExit(1)
raise SystemExit(1) from None
print(f"Version: {Fore.CYAN}{version}")

View File

@ -208,7 +208,7 @@ def main() -> None:
f.write(f"This list contains {len(plugins)} plugins.\n\n")
f.write(".. only:: not latex\n\n")
wcwidth # reference library that must exist for tabulate to work
_ = wcwidth # reference library that must exist for tabulate to work
plugin_table = tabulate.tabulate(plugins, headers="keys", tablefmt="rst")
f.write(indent(plugin_table, " "))
f.write("\n\n")

View File

@ -232,17 +232,17 @@ class TerminalWriter:
# which may lead to the previous color being propagated to the
# start of the expression, so reset first.
return "\x1b[0m" + highlighted
except pygments.util.ClassNotFound:
except pygments.util.ClassNotFound as e:
raise UsageError(
"PYTEST_THEME environment variable had an invalid value: '{}'. "
"Only valid pygment styles are allowed.".format(
os.getenv("PYTEST_THEME")
)
)
except pygments.util.OptionError:
) from e
except pygments.util.OptionError as e:
raise UsageError(
"PYTEST_THEME_MODE environment variable had an invalid value: '{}'. "
"The only allowed values are 'dark' and 'light'.".format(
os.getenv("PYTEST_THEME_MODE")
)
)
) from e

View File

@ -598,7 +598,8 @@ if sys.version_info >= (3, 11) or TYPE_CHECKING:
else:
class CaptureResult(
collections.namedtuple("CaptureResult", ["out", "err"]), Generic[AnyStr]
collections.namedtuple("CaptureResult", ["out", "err"]), # noqa: PYI024
Generic[AnyStr],
):
"""The result of :method:`caplog.readouterr() <pytest.CaptureFixture.readouterr>`."""

View File

@ -15,11 +15,6 @@ from typing import Any
from typing import Callable
from typing import Final
from typing import NoReturn
from typing import TypeVar
_T = TypeVar("_T")
_S = TypeVar("_S")
# fmt: off

View File

@ -1848,13 +1848,13 @@ def parse_warning_filter(
try:
action: "warnings._ActionKind" = warnings._getaction(action_) # type: ignore[attr-defined]
except warnings._OptionError as e:
raise UsageError(error_template.format(error=str(e)))
raise UsageError(error_template.format(error=str(e))) from None
try:
category: Type[Warning] = _resolve_warning_category(category_)
except Exception:
exc_info = ExceptionInfo.from_current()
exception_text = exc_info.getrepr(style="native")
raise UsageError(error_template.format(error=exception_text))
raise UsageError(error_template.format(error=exception_text)) from None
if message and escape:
message = re.escape(message)
if module and escape:
@ -1867,7 +1867,7 @@ def parse_warning_filter(
except ValueError as e:
raise UsageError(
error_template.format(error=f"invalid lineno {lineno_!r}: {e}")
)
) from None
else:
lineno = 0
return action, message, category, module, lineno

View File

@ -209,8 +209,8 @@ class TestCaseFunction(Function):
)
# Invoke the attributes to trigger storing the traceback
# trial causes some issue there.
excinfo.value
excinfo.traceback
_ = excinfo.value
_ = excinfo.traceback
except TypeError:
try:
try:
@ -361,14 +361,21 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None:
# Twisted trial support.
classImplements_has_run = False
@hookimpl(wrapper=True)
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules:
ut: Any = sys.modules["twisted.python.failure"]
global classImplements_has_run
Failure__init__ = ut.Failure.__init__
check_testcase_implements_trial_reporter()
if not classImplements_has_run:
from twisted.trial.itrial import IReporter
from zope.interface import classImplements
classImplements(TestCaseFunction, IReporter)
classImplements_has_run = True
def excstore(
self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None
@ -396,16 +403,6 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
return res
def check_testcase_implements_trial_reporter(done: List[int] = []) -> None:
if done:
return
from twisted.trial.itrial import IReporter
from zope.interface import classImplements
classImplements(TestCaseFunction, IReporter)
done.append(1)
def _is_skipped(obj) -> bool:
"""Return True if the given object has been marked with @unittest.skip."""
return bool(getattr(obj, "__unittest_skip__", False))

View File

@ -1241,9 +1241,9 @@ class TestWINLocalPath:
def test_owner_group_not_implemented(self, path1):
with pytest.raises(NotImplementedError):
path1.stat().owner
_ = path1.stat().owner
with pytest.raises(NotImplementedError):
path1.stat().group
_ = path1.stat().group
def test_chmod_simple_int(self, path1):
mode = path1.stat().mode

View File

@ -387,7 +387,7 @@ def test_excinfo_no_python_sourcecode(tmp_path: Path) -> None:
excinfo = pytest.raises(ValueError, template.render, h=h)
for item in excinfo.traceback:
print(item) # XXX: for some reason jinja.Template.render is printed in full
item.source # shouldn't fail
_ = item.source # shouldn't fail
if isinstance(item.path, Path) and item.path.name == "test.txt":
assert str(item.source) == "{{ h()}}:"
@ -418,7 +418,7 @@ def test_codepath_Queue_example() -> None:
def test_match_succeeds():
with pytest.raises(ZeroDivisionError) as excinfo:
0 // 0
_ = 0 // 0
excinfo.match(r".*zero.*")
@ -584,7 +584,7 @@ class TestFormattedExcinfo:
try:
def f():
1 / 0
_ = 1 / 0
f()
@ -601,7 +601,7 @@ class TestFormattedExcinfo:
print(line)
assert lines == [
" def f():",
"> 1 / 0",
"> _ = 1 / 0",
"E ZeroDivisionError: division by zero",
]
@ -638,7 +638,7 @@ raise ValueError()
pr = FormattedExcinfo()
try:
1 / 0
_ = 1 / 0
except ZeroDivisionError:
excinfo = ExceptionInfo.from_current()
@ -1582,7 +1582,7 @@ def test_no_recursion_index_on_recursion_error():
return getattr(self, "_" + attr)
with pytest.raises(RuntimeError) as excinfo:
RecursionDepthError().trigger
_ = RecursionDepthError().trigger
assert "maximum recursion" in str(excinfo.getrepr())

View File

@ -280,7 +280,7 @@ class TestRaises:
def test_raises_context_manager_with_kwargs(self):
with pytest.raises(TypeError) as excinfo:
with pytest.raises(Exception, foo="bar"): # type: ignore[call-overload]
with pytest.raises(OSError, foo="bar"): # type: ignore[call-overload]
pass
assert "Unexpected keyword arguments" in str(excinfo.value)

View File

@ -1,10 +1,10 @@
# mypy: allow-untyped-defs
import collections
import sys
import textwrap
from typing import Any
from typing import List
from typing import MutableSequence
from typing import NamedTuple
from typing import Optional
import attr
@ -1179,7 +1179,9 @@ class TestAssert_reprcompare_attrsclass:
class TestAssert_reprcompare_namedtuple:
def test_namedtuple(self) -> None:
NT = collections.namedtuple("NT", ["a", "b"])
class NT(NamedTuple):
a: Any
b: Any
left = NT(1, "b")
right = NT(1, "c")
@ -1200,8 +1202,13 @@ class TestAssert_reprcompare_namedtuple:
]
def test_comparing_two_different_namedtuple(self) -> None:
NT1 = collections.namedtuple("NT1", ["a", "b"])
NT2 = collections.namedtuple("NT2", ["a", "b"])
class NT1(NamedTuple):
a: Any
b: Any
class NT2(NamedTuple):
a: Any
b: Any
left = NT1(1, "b")
right = NT2(2, "b")

View File

@ -169,17 +169,17 @@ class ErrorsHelper:
def test_helper_failures() -> None:
helper = ErrorsHelper()
with pytest.raises(Exception):
helper.raise_exception
with pytest.raises(Exception): # noqa: B017
_ = helper.raise_exception
with pytest.raises(OutcomeException):
helper.raise_fail_outcome
_ = helper.raise_fail_outcome
def test_safe_getattr() -> None:
helper = ErrorsHelper()
assert safe_getattr(helper, "raise_exception", "default") == "default"
assert safe_getattr(helper, "raise_fail_outcome", "default") == "default"
with pytest.raises(BaseException):
with pytest.raises(BaseException): # noqa: B017
assert safe_getattr(helper, "raise_baseexception", "default")

View File

@ -108,7 +108,7 @@ class TestFixtureRequestSessionScoped:
AttributeError,
match="path not available in session-scoped context",
):
session_request.fspath
_ = session_request.fspath
@pytest.mark.parametrize("config_type", ["ini", "pyproject"])

View File

@ -42,7 +42,7 @@ class TestMark:
def test_pytest_mark_name_starts_with_underscore(self) -> None:
mark = MarkGenerator(_ispytest=True)
with pytest.raises(AttributeError):
mark._some_name
_ = mark._some_name
def test_marked_class_run_twice(pytester: Pytester) -> None:

View File

@ -228,7 +228,7 @@ class TestDeprecatedCall:
for warning in other_warnings:
def f():
warnings.warn(warning("hi"))
warnings.warn(warning("hi")) # noqa: B023
with pytest.warns(warning):
with pytest.raises(pytest.fail.Exception):

View File

@ -1,6 +1,5 @@
# mypy: allow-untyped-defs
"""Terminal reporting of the full testing process."""
import collections
from io import StringIO
import os
from pathlib import Path
@ -10,6 +9,7 @@ from types import SimpleNamespace
from typing import cast
from typing import Dict
from typing import List
from typing import NamedTuple
from typing import Tuple
import pluggy
@ -34,7 +34,9 @@ from _pytest.terminal import TerminalReporter
import pytest
DistInfo = collections.namedtuple("DistInfo", ["project_name", "version"])
class DistInfo(NamedTuple):
project_name: str
version: int
TRANS_FNMATCH = str.maketrans({"[": "[[]", "]": "[]]"})

View File

@ -18,8 +18,7 @@ WARNINGS_SUMMARY_HEADER = "warnings summary"
def pyfile_with_warnings(pytester: Pytester, request: FixtureRequest) -> str:
"""Create a test file which calls a function in a module which generates warnings."""
pytester.syspathinsert()
test_name = request.function.__name__
module_name = test_name.lstrip("test_") + "_module"
module_name = request.function.__name__[len("test_") :] + "_module"
test_file = pytester.makepyfile(
f"""
import {module_name}