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]