diff --git a/.gitblameignore b/.git-blame-ignore-revs similarity index 88% rename from .gitblameignore rename to .git-blame-ignore-revs index 0cb298b02..249ce7022 100644 --- a/.gitblameignore +++ b/.git-blame-ignore-revs @@ -26,3 +26,6 @@ afc607cfd81458d4e4f3b1f3cf8cc931b933907e # move argument parser to own file c9df77cbd6a365dcb73c39618e4842711817e871 + +# Replace reorder-python-imports by isort due to black incompatibility (#11896) +8b54596639f41dfac070030ef20394b9001fe63c diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 26ca339b9..244fe48e0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/psf/black - rev: 23.12.1 + rev: 24.1.1 hooks: - id: black args: [--safe, --quiet] @@ -36,11 +36,12 @@ repos: additional_dependencies: - flake8-typing-imports==1.12.0 - flake8-docstrings==1.5.0 -- repo: https://github.com/asottile/reorder-python-imports - rev: v3.12.0 +- repo: https://github.com/pycqa/isort + rev: 5.13.2 hooks: - - id: reorder-python-imports - args: ['--application-directories=.:src', --py38-plus] + - id: isort + name: isort + args: [--force-single-line, --profile=black] - repo: https://github.com/asottile/pyupgrade rev: v3.15.0 hooks: diff --git a/bench/bench.py b/bench/bench.py index c40fc8636..c314b4f56 100644 --- a/bench/bench.py +++ b/bench/bench.py @@ -2,9 +2,10 @@ import sys if __name__ == "__main__": import cProfile - import pytest # NOQA import pstats + import pytest # NOQA + script = sys.argv[1:] if len(sys.argv) > 1 else ["empty.py"] cProfile.run("pytest.cmdline.main(%r)" % script, "prof") p = pstats.Stats("prof") diff --git a/doc/en/conf.py b/doc/en/conf.py index 2bc18be58..bb5737d7a 100644 --- a/doc/en/conf.py +++ b/doc/en/conf.py @@ -440,9 +440,10 @@ intersphinx_mapping = { def configure_logging(app: "sphinx.application.Sphinx") -> None: """Configure Sphinx's WarningHandler to handle (expected) missing include.""" - import sphinx.util.logging import logging + import sphinx.util.logging + class WarnLogFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: """Ignore warnings about missing include with "only" directive. diff --git a/doc/en/example/multipython.py b/doc/en/example/multipython.py index 8d76ed483..1354cb37c 100644 --- a/doc/en/example/multipython.py +++ b/doc/en/example/multipython.py @@ -1,12 +1,12 @@ """Module containing a parametrized tests testing cross-python serialization via the pickle module.""" + import shutil import subprocess import textwrap import pytest - pythonlist = ["python3.9", "python3.10", "python3.11"] diff --git a/scripts/update-plugin-list.py b/scripts/update-plugin-list.py index 0f811b778..287073f57 100644 --- a/scripts/update-plugin-list.py +++ b/scripts/update-plugin-list.py @@ -19,7 +19,6 @@ from requests_cache import OriginalResponse from requests_cache import SQLiteCache from tqdm import tqdm - FILE_HEAD = r""" .. Note this file is autogenerated by scripts/update-plugin-list.py - usually weekly via github action diff --git a/src/_pytest/__init__.py b/src/_pytest/__init__.py index 8a406c5c7..9062768ea 100644 --- a/src/_pytest/__init__.py +++ b/src/_pytest/__init__.py @@ -1,7 +1,8 @@ __all__ = ["__version__", "version_tuple"] try: - from ._version import version as __version__, version_tuple + from ._version import version as __version__ + from ._version import version_tuple except ImportError: # pragma: no cover # broken installation, we don't even try # unknown only works because we do poor mans version compare diff --git a/src/_pytest/_argcomplete.py b/src/_pytest/_argcomplete.py index 6a8083770..c2ec1797f 100644 --- a/src/_pytest/_argcomplete.py +++ b/src/_pytest/_argcomplete.py @@ -61,6 +61,7 @@ If things do not work right away: which should throw a KeyError: 'COMPLINE' (which is properly set by the global argcomplete script). """ + import argparse import os import sys diff --git a/src/_pytest/_code/__init__.py b/src/_pytest/_code/__init__.py index 511d0dde6..f82c3d2b0 100644 --- a/src/_pytest/_code/__init__.py +++ b/src/_pytest/_code/__init__.py @@ -1,4 +1,5 @@ """Python inspection/code generation API.""" + from .code import Code from .code import ExceptionInfo from .code import filter_traceback diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index 39bbc3c14..8b38a8e78 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -278,9 +278,9 @@ class TracebackEntry: Mostly for internal use. """ - tbh: Union[ - bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool] - ] = False + tbh: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]] = ( + False + ) for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals): # in normal cases, f_locals and f_globals are dictionaries # however via `exec(...)` / `eval(...)` they can be other types @@ -377,12 +377,10 @@ class Traceback(List[TracebackEntry]): return self @overload - def __getitem__(self, key: "SupportsIndex") -> TracebackEntry: - ... + def __getitem__(self, key: "SupportsIndex") -> TracebackEntry: ... @overload - def __getitem__(self, key: slice) -> "Traceback": - ... + def __getitem__(self, key: slice) -> "Traceback": ... def __getitem__( self, key: Union["SupportsIndex", slice] @@ -1056,13 +1054,13 @@ class FormattedExcinfo: # full support for exception groups added to ExceptionInfo. # See https://github.com/pytest-dev/pytest/issues/9159 if isinstance(e, BaseExceptionGroup): - reprtraceback: Union[ - ReprTracebackNative, ReprTraceback - ] = ReprTracebackNative( - traceback.format_exception( - type(excinfo_.value), - excinfo_.value, - excinfo_.traceback[0]._rawentry, + reprtraceback: Union[ReprTracebackNative, ReprTraceback] = ( + ReprTracebackNative( + traceback.format_exception( + type(excinfo_.value), + excinfo_.value, + excinfo_.traceback[0]._rawentry, + ) ) ) else: diff --git a/src/_pytest/_code/source.py b/src/_pytest/_code/source.py index efee1fad3..a85b14371 100644 --- a/src/_pytest/_code/source.py +++ b/src/_pytest/_code/source.py @@ -47,12 +47,10 @@ class Source: __hash__ = None # type: ignore @overload - def __getitem__(self, key: int) -> str: - ... + def __getitem__(self, key: int) -> str: ... @overload - def __getitem__(self, key: slice) -> "Source": - ... + def __getitem__(self, key: slice) -> "Source": ... def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]: if isinstance(key, int): diff --git a/src/_pytest/_io/__init__.py b/src/_pytest/_io/__init__.py index db001e918..a804cb549 100644 --- a/src/_pytest/_io/__init__.py +++ b/src/_pytest/_io/__init__.py @@ -1,7 +1,6 @@ from .terminalwriter import get_terminal_width from .terminalwriter import TerminalWriter - __all__ = [ "TerminalWriter", "get_terminal_width", diff --git a/src/_pytest/_io/terminalwriter.py b/src/_pytest/_io/terminalwriter.py index 56107d566..89221796a 100644 --- a/src/_pytest/_io/terminalwriter.py +++ b/src/_pytest/_io/terminalwriter.py @@ -1,4 +1,5 @@ """Helper functions for writing to terminals and files.""" + import os import shutil import sys @@ -10,7 +11,6 @@ from typing import TextIO from .wcwidth import wcswidth - # This code was initially copied from py 1.8.1, file _io/terminalwriter.py. @@ -210,8 +210,8 @@ class TerminalWriter: from pygments.lexers.python import PythonLexer as Lexer elif lexer == "diff": from pygments.lexers.diff import DiffLexer as Lexer - from pygments import highlight import pygments.util + from pygments import highlight except ImportError: return source else: diff --git a/src/_pytest/_py/error.py b/src/_pytest/_py/error.py index 0b8f2d535..4b08d3b7a 100644 --- a/src/_pytest/_py/error.py +++ b/src/_pytest/_py/error.py @@ -1,4 +1,5 @@ """create errno-specific classes for IO or os calls.""" + from __future__ import annotations import errno diff --git a/src/_pytest/_py/path.py b/src/_pytest/_py/path.py index 04b1695f1..44262a524 100644 --- a/src/_pytest/_py/path.py +++ b/src/_pytest/_py/path.py @@ -204,12 +204,10 @@ class Stat: if TYPE_CHECKING: @property - def size(self) -> int: - ... + def size(self) -> int: ... @property - def mtime(self) -> float: - ... + def mtime(self) -> float: ... def __getattr__(self, name: str) -> Any: return getattr(self._osstatresult, "st_" + name) @@ -962,12 +960,10 @@ class LocalPath: return p @overload - def stat(self, raising: Literal[True] = ...) -> Stat: - ... + def stat(self, raising: Literal[True] = ...) -> Stat: ... @overload - def stat(self, raising: Literal[False]) -> Stat | None: - ... + def stat(self, raising: Literal[False]) -> Stat | None: ... def stat(self, raising: bool = True) -> Stat | None: """Return an os.stat() tuple.""" @@ -1168,7 +1164,8 @@ class LocalPath: where the 'self' path points to executable. The process is directly invoked and not through a system shell. """ - from subprocess import Popen, PIPE + from subprocess import PIPE + from subprocess import Popen popen_opts.pop("stdout", None) popen_opts.pop("stderr", None) diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 149101e71..c24263e06 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -1,4 +1,5 @@ """Rewrite assertion AST to produce nice error messages.""" + import ast import errno import functools @@ -33,15 +34,16 @@ from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest._io.saferepr import saferepr from _pytest._version import version from _pytest.assertion import util -from _pytest.assertion.util import ( # noqa: F401 - format_explanation as _format_explanation, -) from _pytest.config import Config from _pytest.main import Session from _pytest.pathlib import absolutepath from _pytest.pathlib import fnmatch_ex from _pytest.stash import StashKey +# fmt: off +from _pytest.assertion.util import format_explanation as _format_explanation # noqa:F401, isort:skip +# fmt:on + if TYPE_CHECKING: from _pytest.assertion import AssertionState @@ -669,9 +671,9 @@ class AssertionRewriter(ast.NodeVisitor): self.enable_assertion_pass_hook = False self.source = source self.scope: tuple[ast.AST, ...] = () - self.variables_overwrite: defaultdict[ - tuple[ast.AST, ...], Dict[str, str] - ] = defaultdict(dict) + self.variables_overwrite: defaultdict[tuple[ast.AST, ...], Dict[str, str]] = ( + defaultdict(dict) + ) def run(self, mod: ast.Module) -> None: """Find all assert statements in *mod* and rewrite them.""" @@ -858,9 +860,10 @@ class AssertionRewriter(ast.NodeVisitor): the expression is false. """ if isinstance(assert_.test, ast.Tuple) and len(assert_.test.elts) >= 1: - from _pytest.warning_types import PytestAssertRewriteWarning import warnings + from _pytest.warning_types import PytestAssertRewriteWarning + # TODO: This assert should not be needed. assert self.module_path is not None warnings.warn_explicit( diff --git a/src/_pytest/assertion/truncate.py b/src/_pytest/assertion/truncate.py index 16de27f25..1e5865672 100644 --- a/src/_pytest/assertion/truncate.py +++ b/src/_pytest/assertion/truncate.py @@ -3,6 +3,7 @@ Current default behaviour is to truncate assertion explanations at terminal lines, unless running with an assertions verbosity level of at least 2 or running on CI. """ + from typing import List from typing import Optional @@ -10,7 +11,6 @@ from _pytest.assertion import util from _pytest.config import Config from _pytest.nodes import Item - DEFAULT_MAX_LINES = 8 DEFAULT_MAX_CHARS = 8 * 80 USAGE_MSG = "use '-vv' to show" diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py index ee68cc38c..87ef38b5e 100755 --- a/src/_pytest/cacheprovider.py +++ b/src/_pytest/cacheprovider.py @@ -112,6 +112,7 @@ class Cache: """ check_ispytest(_ispytest) import warnings + from _pytest.warning_types import PytestCacheWarning warnings.warn( diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index ad8558b1f..821b422f3 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -17,7 +17,6 @@ from typing import Final from typing import NoReturn from typing import TypeVar - _T = TypeVar("_T") _S = TypeVar("_S") diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index c0e1e195f..7bab69b7a 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -66,9 +66,10 @@ from _pytest.warning_types import PytestConfigWarning from _pytest.warning_types import warn_explicit_for if TYPE_CHECKING: + from .argparsing import Argument + from .argparsing import Parser from _pytest._code.code import _TracebackStyle from _pytest.terminal import TerminalReporter - from .argparsing import Argument, Parser _PluggyPlugin = object @@ -973,7 +974,8 @@ class Config: *, invocation_params: Optional[InvocationParams] = None, ) -> None: - from .argparsing import Parser, FILE_OR_DIR + from .argparsing import FILE_OR_DIR + from .argparsing import Parser if invocation_params is None: invocation_params = self.InvocationParams( @@ -1390,8 +1392,9 @@ class Config: return # Imported lazily to improve start-up time. + from packaging.requirements import InvalidRequirement + from packaging.requirements import Requirement from packaging.version import Version - from packaging.requirements import InvalidRequirement, Requirement plugin_info = self.pluginmanager.list_plugin_distinfo() plugin_dist_info = {dist.project_name: dist.version for _, dist in plugin_info} diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 1bc2cf57e..0f611aa5c 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -8,6 +8,7 @@ All constants defined in this module should be either instances of :class:`PytestWarning`, or :class:`UnformattedWarning` in case of warnings which need to format their messages. """ + from warnings import warn from _pytest.warning_types import PytestDeprecationWarning diff --git a/src/_pytest/faulthandler.py b/src/_pytest/faulthandler.py index 1bccd18c6..824aec58e 100644 --- a/src/_pytest/faulthandler.py +++ b/src/_pytest/faulthandler.py @@ -8,7 +8,6 @@ from _pytest.config.argparsing import Parser from _pytest.nodes import Item from _pytest.stash import StashKey - fault_handler_original_stderr_fd_key = StashKey[int]() fault_handler_stderr_fd_key = StashKey[int]() diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index d7d8a720b..7000cdab8 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -67,7 +67,6 @@ from _pytest.scope import _ScopeName from _pytest.scope import HIGH_SCOPES from _pytest.scope import Scope - if TYPE_CHECKING: from typing import Deque @@ -1231,8 +1230,7 @@ def fixture( Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] ] = ..., name: Optional[str] = ..., -) -> FixtureFunction: - ... +) -> FixtureFunction: ... @overload @@ -1246,8 +1244,7 @@ def fixture( # noqa: F811 Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] ] = ..., name: Optional[str] = None, -) -> FixtureFunctionMarker: - ... +) -> FixtureFunctionMarker: ... def fixture( # noqa: F811 diff --git a/src/_pytest/freeze_support.py b/src/_pytest/freeze_support.py index 9f8ea231f..d028058e3 100644 --- a/src/_pytest/freeze_support.py +++ b/src/_pytest/freeze_support.py @@ -1,5 +1,6 @@ """Provides a function to report all internal modules for using freezing tools.""" + import types from typing import Iterator from typing import List diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index 3c27dcf91..0aace8c34 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -19,12 +19,12 @@ if TYPE_CHECKING: import warnings from typing import Literal - from _pytest._code.code import ExceptionRepr from _pytest._code.code import ExceptionInfo + from _pytest._code.code import ExceptionRepr + from _pytest.config import _PluggyPlugin from _pytest.config import Config from _pytest.config import ExitCode from _pytest.config import PytestPluginManager - from _pytest.config import _PluggyPlugin from _pytest.config.argparsing import Parser from _pytest.fixtures import FixtureDef from _pytest.fixtures import SubRequest diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index f01afd915..a198e1d23 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -34,7 +34,6 @@ from _pytest.reports import TestReport from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter - xml_key = StashKey["LogXML"]() diff --git a/src/_pytest/legacypath.py b/src/_pytest/legacypath.py index cb9a36243..5dafea402 100644 --- a/src/_pytest/legacypath.py +++ b/src/_pytest/legacypath.py @@ -15,6 +15,7 @@ from typing import Union from iniconfig import SectionWrapper import py + from _pytest.cacheprovider import Cache from _pytest.config import Config from _pytest.config import hookimpl diff --git a/src/_pytest/main.py b/src/_pytest/main.py index f7e47cece..a75e53a0c 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -1,4 +1,5 @@ """Core implementation of the testing process: init, session, runtest loop.""" + import argparse import dataclasses import fnmatch @@ -721,14 +722,12 @@ class Session(nodes.Collector): @overload def perform_collect( self, args: Optional[Sequence[str]] = ..., genitems: "Literal[True]" = ... - ) -> Sequence[nodes.Item]: - ... + ) -> Sequence[nodes.Item]: ... @overload def perform_collect( # noqa: F811 self, args: Optional[Sequence[str]] = ..., genitems: bool = ... - ) -> Sequence[Union[nodes.Item, nodes.Collector]]: - ... + ) -> Sequence[Union[nodes.Item, nodes.Collector]]: ... def perform_collect( # noqa: F811 self, args: Optional[Sequence[str]] = None, genitems: bool = True diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index bcee802f3..ec5023c91 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -1,4 +1,5 @@ """Generic mechanism for marking and selecting python functions.""" + import dataclasses from typing import AbstractSet from typing import Collection diff --git a/src/_pytest/mark/expression.py b/src/_pytest/mark/expression.py index b995518bf..5fa0ccaa7 100644 --- a/src/_pytest/mark/expression.py +++ b/src/_pytest/mark/expression.py @@ -14,6 +14,7 @@ The semantics are: - ident evaluates to True of False according to a provided matcher function. - or/and/not evaluate according to the usual boolean semantics. """ + import ast import dataclasses import enum diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index e3580cf6f..544e1dccf 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -434,12 +434,10 @@ if TYPE_CHECKING: class _SkipMarkDecorator(MarkDecorator): @overload # type: ignore[override,misc,no-overload-impl] - def __call__(self, arg: Markable) -> Markable: - ... + def __call__(self, arg: Markable) -> Markable: ... @overload - def __call__(self, reason: str = ...) -> "MarkDecorator": - ... + def __call__(self, reason: str = ...) -> "MarkDecorator": ... class _SkipifMarkDecorator(MarkDecorator): def __call__( # type: ignore[override] @@ -447,13 +445,11 @@ if TYPE_CHECKING: condition: Union[str, bool] = ..., *conditions: Union[str, bool], reason: str = ..., - ) -> MarkDecorator: - ... + ) -> MarkDecorator: ... class _XfailMarkDecorator(MarkDecorator): @overload # type: ignore[override,misc,no-overload-impl] - def __call__(self, arg: Markable) -> Markable: - ... + def __call__(self, arg: Markable) -> Markable: ... @overload def __call__( @@ -466,8 +462,7 @@ if TYPE_CHECKING: None, Type[BaseException], Tuple[Type[BaseException], ...] ] = ..., strict: bool = ..., - ) -> MarkDecorator: - ... + ) -> MarkDecorator: ... class _ParametrizeMarkDecorator(MarkDecorator): def __call__( # type: ignore[override] @@ -483,8 +478,7 @@ if TYPE_CHECKING: ] ] = ..., scope: Optional[_ScopeName] = ..., - ) -> MarkDecorator: - ... + ) -> MarkDecorator: ... class _UsefixturesMarkDecorator(MarkDecorator): def __call__(self, *fixtures: str) -> MarkDecorator: # type: ignore[override] diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py index 01c74d6eb..7b678017f 100644 --- a/src/_pytest/monkeypatch.py +++ b/src/_pytest/monkeypatch.py @@ -169,8 +169,7 @@ class MonkeyPatch: name: object, value: Notset = ..., raising: bool = ..., - ) -> None: - ... + ) -> None: ... @overload def setattr( @@ -179,8 +178,7 @@ class MonkeyPatch: name: str, value: object, raising: bool = ..., - ) -> None: - ... + ) -> None: ... def setattr( self, diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 2d6ad7b8f..5260b003f 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -41,8 +41,8 @@ from _pytest.warning_types import PytestWarning if TYPE_CHECKING: # Imported here due to circular import. - from _pytest.main import Session from _pytest._code.code import _TracebackStyle + from _pytest.main import Session SEP = "/" @@ -104,6 +104,7 @@ class Node(abc.ABC, metaclass=NodeMeta): ``Collector``\'s are the internal nodes of the tree, and ``Item``\'s are the leaf nodes. """ + # Use __slots__ to make attribute access faster. # Note that __dict__ is still available. __slots__ = ( @@ -325,12 +326,10 @@ class Node(abc.ABC, metaclass=NodeMeta): yield node, mark @overload - def get_closest_marker(self, name: str) -> Optional[Mark]: - ... + def get_closest_marker(self, name: str) -> Optional[Mark]: ... @overload - def get_closest_marker(self, name: str, default: Mark) -> Mark: - ... + def get_closest_marker(self, name: str, default: Mark) -> Mark: ... def get_closest_marker( self, name: str, default: Optional[Mark] = None diff --git a/src/_pytest/outcomes.py b/src/_pytest/outcomes.py index 8710ba3e8..eb51e7f7e 100644 --- a/src/_pytest/outcomes.py +++ b/src/_pytest/outcomes.py @@ -1,5 +1,6 @@ """Exception classes and constants handling test outcomes as well as functions creating them.""" + import sys from typing import Any from typing import Callable diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py index 484703374..440d6ec5f 100644 --- a/src/_pytest/pastebin.py +++ b/src/_pytest/pastebin.py @@ -12,7 +12,6 @@ from _pytest.config.argparsing import Parser from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter - pastebinfile_key = StashKey[IO[bytes]]() @@ -74,8 +73,8 @@ def create_new_paste(contents: Union[str, bytes]) -> str: :returns: URL to the pasted contents, or an error message. """ import re - from urllib.request import urlopen from urllib.parse import urlencode + from urllib.request import urlopen params = {"code": contents, "lexer": "text", "expiry": "1week"} url = "https://bpa.st" diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 69a24c7c9..ae8709e5e 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -244,8 +244,7 @@ class RecordedHookCall: if TYPE_CHECKING: # The class has undetermined attributes, this tells mypy about it. - def __getattr__(self, key: str): - ... + def __getattr__(self, key: str): ... @final @@ -326,15 +325,13 @@ class HookRecorder: def getreports( self, names: "Literal['pytest_collectreport']", - ) -> Sequence[CollectReport]: - ... + ) -> Sequence[CollectReport]: ... @overload def getreports( self, names: "Literal['pytest_runtest_logreport']", - ) -> Sequence[TestReport]: - ... + ) -> Sequence[TestReport]: ... @overload def getreports( @@ -343,8 +340,7 @@ class HookRecorder: "pytest_collectreport", "pytest_runtest_logreport", ), - ) -> Sequence[Union[CollectReport, TestReport]]: - ... + ) -> Sequence[Union[CollectReport, TestReport]]: ... def getreports( self, @@ -391,15 +387,13 @@ class HookRecorder: def getfailures( self, names: "Literal['pytest_collectreport']", - ) -> Sequence[CollectReport]: - ... + ) -> Sequence[CollectReport]: ... @overload def getfailures( self, names: "Literal['pytest_runtest_logreport']", - ) -> Sequence[TestReport]: - ... + ) -> Sequence[TestReport]: ... @overload def getfailures( @@ -408,8 +402,7 @@ class HookRecorder: "pytest_collectreport", "pytest_runtest_logreport", ), - ) -> Sequence[Union[CollectReport, TestReport]]: - ... + ) -> Sequence[Union[CollectReport, TestReport]]: ... def getfailures( self, diff --git a/src/_pytest/pytester_assertions.py b/src/_pytest/pytester_assertions.py index 657e4db5f..d20c2bb59 100644 --- a/src/_pytest/pytester_assertions.py +++ b/src/_pytest/pytester_assertions.py @@ -1,4 +1,5 @@ """Helper plugin for pytester; should not be loaded on its own.""" + # This plugin contains assertions used by pytester. pytester cannot # contain them itself, since it is imported by the `pytest` module, # hence cannot be subject to assertion rewriting, which requires a diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 5fa32260b..d069d7038 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -81,7 +81,6 @@ from _pytest.warning_types import PytestCollectionWarning from _pytest.warning_types import PytestReturnNotNoneWarning from _pytest.warning_types import PytestUnhandledCoroutineWarning - _PYTEST_DIR = Path(_pytest.__file__).parent @@ -1793,9 +1792,11 @@ class Function(PyobjMixin, nodes.Item): if self.config.getoption("tbstyle", "auto") == "auto": if len(ntraceback) > 2: ntraceback = Traceback( - entry - if i == 0 or i == len(ntraceback) - 1 - else entry.with_repr_style("short") + ( + entry + if i == 0 or i == len(ntraceback) - 1 + else entry.with_repr_style("short") + ) for i, entry in enumerate(ntraceback) ) diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index c32d75b44..f398902ff 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -779,8 +779,7 @@ def raises( expected_exception: Union[Type[E], Tuple[Type[E], ...]], *, match: Optional[Union[str, Pattern[str]]] = ..., -) -> "RaisesContext[E]": - ... +) -> "RaisesContext[E]": ... @overload @@ -789,8 +788,7 @@ def raises( # noqa: F811 func: Callable[..., Any], *args: Any, **kwargs: Any, -) -> _pytest._code.ExceptionInfo[E]: - ... +) -> _pytest._code.ExceptionInfo[E]: ... def raises( # noqa: F811 diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index 57d4bb47c..e8c8aff8b 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -22,7 +22,6 @@ from _pytest.deprecated import check_ispytest from _pytest.fixtures import fixture from _pytest.outcomes import fail - T = TypeVar("T") @@ -42,15 +41,13 @@ def recwarn() -> Generator["WarningsRecorder", None, None]: @overload def deprecated_call( *, match: Optional[Union[str, Pattern[str]]] = ... -) -> "WarningsRecorder": - ... +) -> "WarningsRecorder": ... @overload def deprecated_call( # noqa: F811 func: Callable[..., T], *args: Any, **kwargs: Any -) -> T: - ... +) -> T: ... def deprecated_call( # noqa: F811 @@ -92,8 +89,7 @@ def warns( expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = ..., *, match: Optional[Union[str, Pattern[str]]] = ..., -) -> "WarningsChecker": - ... +) -> "WarningsChecker": ... @overload @@ -102,8 +98,7 @@ def warns( # noqa: F811 func: Callable[..., T], *args: Any, **kwargs: Any, -) -> T: - ... +) -> T: ... def warns( # noqa: F811 diff --git a/src/_pytest/reports.py b/src/_pytest/reports.py index ddf7f2983..44eaec908 100644 --- a/src/_pytest/reports.py +++ b/src/_pytest/reports.py @@ -71,8 +71,7 @@ class BaseReport: if TYPE_CHECKING: # Can have arbitrary fields given to __init__(). - def __getattr__(self, key: str) -> Any: - ... + def __getattr__(self, key: str) -> Any: ... def toterminal(self, out: TerminalWriter) -> None: if hasattr(self, "node"): @@ -609,9 +608,9 @@ def _report_kwargs_from_json(reportdict: Dict[str, Any]) -> Dict[str, Any]: description, ) ) - exception_info: Union[ - ExceptionChainRepr, ReprExceptionInfo - ] = ExceptionChainRepr(chain) + exception_info: Union[ExceptionChainRepr, ReprExceptionInfo] = ( + ExceptionChainRepr(chain) + ) else: exception_info = ReprExceptionInfo( reprtraceback=reprtraceback, diff --git a/src/_pytest/scope.py b/src/_pytest/scope.py index 98edaf402..d15c12705 100644 --- a/src/_pytest/scope.py +++ b/src/_pytest/scope.py @@ -7,12 +7,12 @@ would cause circular references. Also this makes the module light to import, as it should. """ + from enum import Enum from functools import total_ordering from typing import Literal from typing import Optional - _ScopeName = Literal["session", "package", "module", "class", "function"] diff --git a/src/_pytest/stash.py b/src/_pytest/stash.py index e61d75b95..7b111981b 100644 --- a/src/_pytest/stash.py +++ b/src/_pytest/stash.py @@ -5,7 +5,6 @@ from typing import Generic from typing import TypeVar from typing import Union - __all__ = ["Stash", "StashKey"] diff --git a/src/_pytest/timing.py b/src/_pytest/timing.py index 925163a58..096a67768 100644 --- a/src/_pytest/timing.py +++ b/src/_pytest/timing.py @@ -5,6 +5,7 @@ pytest runtime information (issue #185). Fixture "mock_timing" also interacts with this module for pytest's own tests. """ + from time import perf_counter from time import sleep from time import time diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py index ce06b7d9b..3bdb0610e 100644 --- a/src/_pytest/unittest.py +++ b/src/_pytest/unittest.py @@ -33,6 +33,7 @@ from _pytest.runner import CallInfo if TYPE_CHECKING: import unittest + import twisted.trial.unittest _SysExcInfoType = Union[ @@ -397,8 +398,8 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]: def check_testcase_implements_trial_reporter(done: List[int] = []) -> None: if done: return - from zope.interface import classImplements from twisted.trial.itrial import IReporter + from zope.interface import classImplements classImplements(TestCaseFunction, IReporter) done.append(1) diff --git a/src/pytest/__main__.py b/src/pytest/__main__.py index b17015293..9e08e3ebc 100644 --- a/src/pytest/__main__.py +++ b/src/pytest/__main__.py @@ -1,4 +1,5 @@ """The pytest entry point.""" + import pytest if __name__ == "__main__": diff --git a/testing/_py/test_local.py b/testing/_py/test_local.py index ba19aef38..b97080ed0 100644 --- a/testing/_py/test_local.py +++ b/testing/_py/test_local.py @@ -7,10 +7,11 @@ import time import warnings from unittest import mock -import pytest from py import error from py.path import local +import pytest + @contextlib.contextmanager def ignore_encoding_warning(): @@ -1367,8 +1368,8 @@ class TestPOSIXLocalPath: assert realpath.basename == "file" def test_owner(self, path1, tmpdir): - from pwd import getpwuid # type:ignore[attr-defined] from grp import getgrgid # type:ignore[attr-defined] + from pwd import getpwuid # type:ignore[attr-defined] stat = path1.stat() assert stat.path == path1 diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index a9982b4f3..36625cfb5 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -24,7 +24,6 @@ from _pytest.pathlib import import_path from _pytest.pytester import LineMatcher from _pytest.pytester import Pytester - if TYPE_CHECKING: from _pytest._code.code import _TracebackStyle diff --git a/testing/example_scripts/unittest/test_unittest_asyncio.py b/testing/example_scripts/unittest/test_unittest_asyncio.py index a82ddaebc..f0c394ee3 100644 --- a/testing/example_scripts/unittest/test_unittest_asyncio.py +++ b/testing/example_scripts/unittest/test_unittest_asyncio.py @@ -2,7 +2,6 @@ from typing import List from unittest import IsolatedAsyncioTestCase - teardowns: List[None] = [] diff --git a/testing/example_scripts/unittest/test_unittest_asynctest.py b/testing/example_scripts/unittest/test_unittest_asynctest.py index b3f03e325..a5a0ec22c 100644 --- a/testing/example_scripts/unittest/test_unittest_asynctest.py +++ b/testing/example_scripts/unittest/test_unittest_asynctest.py @@ -5,7 +5,6 @@ from typing import List import asynctest - teardowns: List[None] = [] diff --git a/testing/freeze/create_executable.py b/testing/freeze/create_executable.py index 998df7b1c..3803b3b24 100644 --- a/testing/freeze/create_executable.py +++ b/testing/freeze/create_executable.py @@ -1,8 +1,10 @@ """Generate an executable with pytest runner embedded using PyInstaller.""" + if __name__ == "__main__": - import pytest import subprocess + import pytest + hidden = [] for x in pytest.freeze_includes(): hidden.extend(["--hidden-import", x]) diff --git a/testing/freeze/runtests_script.py b/testing/freeze/runtests_script.py index 591863016..ef63a2d15 100644 --- a/testing/freeze/runtests_script.py +++ b/testing/freeze/runtests_script.py @@ -5,6 +5,7 @@ pytest main(). if __name__ == "__main__": import sys + import pytest sys.exit(pytest.main()) diff --git a/testing/freeze/tox_run.py b/testing/freeze/tox_run.py index 678a69c85..7fd63cf12 100644 --- a/testing/freeze/tox_run.py +++ b/testing/freeze/tox_run.py @@ -2,6 +2,7 @@ Called by tox.ini: uses the generated executable to run the tests in ./tests/ directory. """ + if __name__ == "__main__": import os import sys diff --git a/testing/io/test_terminalwriter.py b/testing/io/test_terminalwriter.py index a13f9a4bc..0b83b5531 100644 --- a/testing/io/test_terminalwriter.py +++ b/testing/io/test_terminalwriter.py @@ -13,7 +13,6 @@ import pytest from _pytest._io import terminalwriter from _pytest.monkeypatch import MonkeyPatch - # These tests were initially copied from py 1.8.1. diff --git a/testing/logging/test_reporting.py b/testing/logging/test_reporting.py index 92fd72300..f6ac9c3b2 100644 --- a/testing/logging/test_reporting.py +++ b/testing/logging/test_reporting.py @@ -831,9 +831,10 @@ def test_live_logging_suspends_capture( We parametrize the test to also make sure _LiveLoggingStreamHandler works correctly if no capture manager plugin is installed. """ - import logging import contextlib + import logging from functools import partial + from _pytest.logging import _LiveLoggingStreamHandler class MockCaptureManager: diff --git a/testing/python/integration.py b/testing/python/integration.py index dbe1b1a00..3ff92d92f 100644 --- a/testing/python/integration.py +++ b/testing/python/integration.py @@ -43,9 +43,10 @@ class TestMockDecoration: assert values == ("x",) def test_getfuncargnames_patching(self): - from _pytest.compat import getfuncargnames from unittest.mock import patch + from _pytest.compat import getfuncargnames + class T: def original(self, x, y, z): pass diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index a4386b3a8..0d1f9854b 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1037,8 +1037,8 @@ class TestAssertionRewriteHookDetails: assert pytester.runpytest().ret == 0 def test_write_pyc(self, pytester: Pytester, tmp_path) -> None: - from _pytest.assertion.rewrite import _write_pyc from _pytest.assertion import AssertionState + from _pytest.assertion.rewrite import _write_pyc config = pytester.parseconfig() state = AssertionState(config, "rewrite") @@ -1088,6 +1088,7 @@ class TestAssertionRewriteHookDetails: an exception that is propagated to the caller. """ import py_compile + from _pytest.assertion.rewrite import _read_pyc source = tmp_path / "source.py" diff --git a/testing/test_config.py b/testing/test_config.py index 45bcce4ea..5a18b9e41 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -2109,9 +2109,9 @@ class TestPytestPluginsVariable: args = ("--pyargs", "pkg") if use_pyargs else () res = pytester.runpytest(*args) assert res.ret == (0 if use_pyargs else 2) - msg = ( - msg - ) = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported" + msg = msg = ( + "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported" + ) if use_pyargs: assert msg not in res.stdout.str() else: diff --git a/testing/test_debugging.py b/testing/test_debugging.py index 1cd46ae48..c0b99797b 100644 --- a/testing/test_debugging.py +++ b/testing/test_debugging.py @@ -9,7 +9,6 @@ from _pytest.debugging import _validate_usepdb_cls from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester - _ENVIRON_PYTHONBREAKPOINT = os.environ.get("PYTHONBREAKPOINT", "") diff --git a/testing/test_error_diffs.py b/testing/test_error_diffs.py index cad7a17c0..6494a44fb 100644 --- a/testing/test_error_diffs.py +++ b/testing/test_error_diffs.py @@ -4,10 +4,10 @@ Tests and examples for correct "+/-" usage in error diffs. See https://github.com/pytest-dev/pytest/issues/3333 for details. """ + import pytest from _pytest.pytester import Pytester - TESTCASES = [ pytest.param( """ diff --git a/testing/test_faulthandler.py b/testing/test_faulthandler.py index 22545ea21..b7142835d 100644 --- a/testing/test_faulthandler.py +++ b/testing/test_faulthandler.py @@ -114,6 +114,7 @@ def test_cancel_timeout_on_hook(monkeypatch, hook_name) -> None: to timeout before entering pdb (pytest-dev/pytest-faulthandler#12) or any other interactive exception (pytest-dev/pytest-faulthandler#14).""" import faulthandler + from _pytest import faulthandler as faulthandler_plugin called = [] diff --git a/testing/test_mark.py b/testing/test_mark.py index 45acf0504..e37fc6c53 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -943,7 +943,8 @@ def test_parameterset_for_parametrize_marks( ) config = pytester.parseconfig() - from _pytest.mark import pytest_configure, get_empty_parameterset_mark + from _pytest.mark import get_empty_parameterset_mark + from _pytest.mark import pytest_configure pytest_configure(config) result_mark = get_empty_parameterset_mark(config, ["a"], all) @@ -967,7 +968,8 @@ def test_parameterset_for_fail_at_collect(pytester: Pytester) -> None: ) config = pytester.parseconfig() - from _pytest.mark import pytest_configure, get_empty_parameterset_mark + from _pytest.mark import get_empty_parameterset_mark + from _pytest.mark import pytest_configure pytest_configure(config) diff --git a/testing/test_meta.py b/testing/test_meta.py index 9201bd216..40ed95d6b 100644 --- a/testing/test_meta.py +++ b/testing/test_meta.py @@ -3,6 +3,7 @@ This ensures all internal packages can be imported without needing the pytest namespace being set, which is critical for the initialization of xdist. """ + import pkgutil import subprocess import sys diff --git a/testing/test_reports.py b/testing/test_reports.py index ae2b68cdb..d65358a8f 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -296,9 +296,9 @@ class TestReportSerialization: reprec = pytester.inline_run() if report_class is TestReport: - reports: Union[ - Sequence[TestReport], Sequence[CollectReport] - ] = reprec.getreports("pytest_runtest_logreport") + reports: Union[Sequence[TestReport], Sequence[CollectReport]] = ( + reprec.getreports("pytest_runtest_logreport") + ) # we have 3 reports: setup/call/teardown assert len(reports) == 3 # get the call report diff --git a/tox.ini b/tox.ini index e4ad300a9..b5c28029f 100644 --- a/tox.ini +++ b/tox.ini @@ -200,6 +200,8 @@ extend-ignore = D302 ; Docstring Content Issues D400,D401,D401,D402,D405,D406,D407,D408,D409,D410,D411,D412,D413,D414,D415,D416,D417 + ; Unused imports + F401 [isort]