Repository: wntrblm/nox
Pull request #893 (2024-11-12 18:39:05)

chore: add more Ruff checks and fixes
Adding more checks. First commit is stable checks, and the second commit is some from preview (not activated, just fixed the issue if it looked useful).

- **chore: add more Ruff checks and fix issues**
- **chore: add some preview check fixes**


henryiii: Thanks! I've rebased and also bumped to Ruff 0.8, which gets rid of one of our ignores.

Patch:
diff --git a/.github/action_helper.py b/.github/action_helper.py
index e6ab5d9..d2a6fce 100644
--- a/.github/action_helper.py
+++ b/.github/action_helper.py
@@ -22,11 +22,14 @@ def filter_version(version: str) -> str:
 
     version_parts = version_.split(".")
     if len(version_parts) < 2:
-        raise ValueError(f"invalid version: {version}")
+        msg = f"invalid version: {version}"
+        raise ValueError(msg)
     if not version_parts[0].isdigit():
-        raise ValueError(f"invalid major python version: {version}")
+        msg = f"invalid major python version: {version}"
+        raise ValueError(msg)
     if not version_parts[1].isdigit():
-        raise ValueError(f"invalid minor python version: {version}")
+        msg = f"invalid minor python version: {version}"
+        raise ValueError(msg)
     return ".".join(version_parts[:2])
 
 
@@ -36,20 +39,22 @@ def setup_action(input_: str) -> None:
     pypy_versions = [version for version in versions if version.startswith("pypy")]
     pypy_versions_filtered = [filter_version(version) for version in pypy_versions]
     if len(pypy_versions) != len(set(pypy_versions_filtered)):
-        raise ValueError(
+        msg = (
             "multiple versions specified for the same 'major.minor' PyPy interpreter:"
             f" {pypy_versions}"
         )
+        raise ValueError(msg)
 
     cpython_versions = [version for version in versions if version not in pypy_versions]
     cpython_versions_filtered = [
         filter_version(version) for version in cpython_versions
     ]
     if len(cpython_versions) != len(set(cpython_versions_filtered)):
-        raise ValueError(
+        msg = (
             "multiple versions specified for the same 'major.minor' CPython"
             f" interpreter: {cpython_versions}"
         )
+        raise ValueError(msg)
 
     # cpython shall be installed last because
     # other interpreters also define pythonX.Y symlinks.
@@ -70,5 +75,6 @@ def setup_action(input_: str) -> None:
 
 if __name__ == "__main__":
     if len(sys.argv) != 2:
-        raise AssertionError(f"invalid arguments: {sys.argv}")
+        msg = f"invalid arguments: {sys.argv}"
+        raise AssertionError(msg)
     setup_action(sys.argv[1])
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ce78361..a7dda49 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,7 +24,7 @@ repos:
       - id: pyproject-fmt
 
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.7.3
+    rev: v0.8.0
     hooks:
       - id: ruff
         args: ["--fix", "--show-fixes"]
diff --git a/nox/__init__.py b/nox/__init__.py
index 8121e62..5338044 100644
--- a/nox/__init__.py
+++ b/nox/__init__.py
@@ -17,7 +17,7 @@ from __future__ import annotations
 from nox import project
 from nox._cli import main
 from nox._options import noxfile_options as options
-from nox._parametrize import Param as param
+from nox._parametrize import Param as param  # noqa: N813
 from nox._parametrize import parametrize_decorator as parametrize
 from nox.registry import session_decorator as session
 from nox.sessions import Session
@@ -26,11 +26,11 @@ needs_version: str | None = None
 
 __all__ = [
     "Session",
+    "main",
     "needs_version",
     "options",
     "param",
     "parametrize",
     "project",
     "session",
-    "main",
 ]
diff --git a/nox/_decorators.py b/nox/_decorators.py
index 62db145..6de7315 100644
--- a/nox/_decorators.py
+++ b/nox/_decorators.py
@@ -18,12 +18,12 @@ import copy
 import functools
 import inspect
 import types
-from collections.abc import Iterable, Mapping, Sequence
 from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast
 
-from . import _typing
-
 if TYPE_CHECKING:
+    from collections.abc import Iterable, Mapping, Sequence
+
+    from . import _typing
     from ._parametrize import Param
 
 T = TypeVar("T", bound=Callable[..., Any])
@@ -32,12 +32,12 @@ T = TypeVar("T", bound=Callable[..., Any])
 class FunctionDecorator:
     """This is a function decorator."""
 
-    def __new__(
+    def __new__(  # noqa: PYI034
         cls: Any, func: Callable[..., Any], *args: Any, **kwargs: Any
     ) -> FunctionDecorator:
-        obj = super().__new__(cls)
-        functools.update_wrapper(obj, func)
-        return cast(FunctionDecorator, obj)
+        self = super().__new__(cls)
+        functools.update_wrapper(self, func)
+        return cast(FunctionDecorator, self)
 
 
 def _copy_func(src: T, name: str | None = None) -> T:
diff --git a/nox/_option_set.py b/nox/_option_set.py
index 573da60..10597b9 100644
--- a/nox/_option_set.py
+++ b/nox/_option_set.py
@@ -23,13 +23,15 @@ import collections
 import functools
 from argparse import ArgumentError as ArgumentError  # noqa: PLC0414
 from argparse import ArgumentParser, Namespace
-from collections.abc import Callable, Iterable
-from typing import Any, Literal
+from typing import TYPE_CHECKING, Any, Literal
 
 import argcomplete
 import attrs
 import attrs.validators as av
 
+if TYPE_CHECKING:
+    from collections.abc import Callable, Iterable
+
 av_opt_str = av.optional(av.instance_of(str))
 av_opt_list_str = av.optional(
     av.deep_iterable(
@@ -198,6 +200,7 @@ def make_flag_pair(
     name: str,
     enable_flags: tuple[str, str] | tuple[str],
     disable_flags: tuple[str, str] | tuple[str],
+    *,
     default: bool | Callable[[], bool] = False,
     **kwargs: Any,
 ) -> tuple[Option, Option]:
@@ -277,9 +280,8 @@ class OptionSet:
 
             # Every option must have a group (except for hidden options)
             if option.group is None:
-                raise ValueError(
-                    f"Option {option.name} must either have a group or be hidden."
-                )
+                msg = f"Option {option.name} must either have a group or be hidden."
+                raise ValueError(msg)
 
             argument = groups[option.group.name].add_argument(
                 *option.flags, help=option.help, default=option.default, **option.kwargs
@@ -331,7 +333,8 @@ class OptionSet:
         # used in tests.
         for key, value in kwargs.items():
             if key not in args:
-                raise KeyError(f"{key} is not an option.")
+                msg = f"{key} is not an option."
+                raise KeyError(msg)
             args[key] = value
 
         return argparse.Namespace(**args)
diff --git a/nox/_options.py b/nox/_options.py
index 77c5b7f..a98a9bf 100644
--- a/nox/_options.py
+++ b/nox/_options.py
@@ -19,16 +19,19 @@ import functools
 import itertools
 import os
 import sys
-from collections.abc import Iterable
-from typing import Any, Callable, Literal, Sequence
+from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence
 
 import argcomplete
 
 from nox import _option_set
-from nox._option_set import NoxOptions
 from nox.tasks import discover_manifest, filter_manifest, load_nox_module
 from nox.virtualenv import ALL_VENVS
 
+if TYPE_CHECKING:
+    from collections.abc import Iterable
+
+    from nox._option_set import NoxOptions
+
 ReuseVenvType = Literal["no", "yes", "never", "always"]
 
 """All of Nox's configuration options."""
@@ -129,9 +132,8 @@ def _force_venv_backend_merge_func(
             command_args.force_venv_backend is not None
             and command_args.force_venv_backend != "none"
         ):
-            raise ValueError(
-                "You can not use `--no-venv` with a non-none `--force-venv-backend`"
-            )
+            msg = "You can not use `--no-venv` with a non-none `--force-venv-backend`"
+            raise ValueError(msg)
         return "none"
     return command_args.force_venv_backend or noxfile_args.force_venv_backend  # type: ignore[return-value]
 
@@ -191,7 +193,7 @@ def default_env_var_list_factory(env_var: str) -> Callable[[], list[str] | None]
     return _default_list
 
 
-def _color_finalizer(value: bool, args: argparse.Namespace) -> bool:
+def _color_finalizer(_value: bool, args: argparse.Namespace) -> bool:  # noqa: FBT001
     """Figures out the correct value for "color" based on the two color flags.
 
     Args:
@@ -224,7 +226,7 @@ def _force_pythons_finalizer(
     return value
 
 
-def _R_finalizer(value: bool, args: argparse.Namespace) -> bool:
+def _R_finalizer(value: bool, args: argparse.Namespace) -> bool:  # noqa: FBT001
     """Propagate -R to --reuse-existing-virtualenvs and --no-install and --reuse-venv=yes."""
     if value:
         args.reuse_venv = "yes"
@@ -233,7 +235,8 @@ def _R_finalizer(value: bool, args: argparse.Namespace) -> bool:
 
 
 def _reuse_existing_virtualenvs_finalizer(
-    value: bool, args: argparse.Namespace
+    value: bool,  # noqa: FBT001
+    args: argparse.Namespace,
 ) -> bool:
     """Propagate --reuse-existing-virtualenvs to --reuse-venv=yes."""
     if value:
@@ -242,7 +245,7 @@ def _reuse_existing_virtualenvs_finalizer(
 
 
 def _posargs_finalizer(
-    value: Sequence[Any], args: argparse.Namespace
+    value: Sequence[Any], _args: argparse.Namespace
 ) -> Sequence[Any] | list[Any]:
     """Removes the leading "--"s in the posargs array (if any) and asserts that
     remaining arguments came after a "--".
@@ -268,7 +271,9 @@ def _posargs_finalizer(
 
 
 def _python_completer(
-    prefix: str, parsed_args: argparse.Namespace, **kwargs: Any
+    prefix: str,  # noqa: ARG001
+    parsed_args: argparse.Namespace,
+    **kwargs: Any,
 ) -> Iterable[str]:
     module = load_nox_module(parsed_args)
     manifest = discover_manifest(module, parsed_args)
@@ -282,7 +287,9 @@ def _python_completer(
 
 
 def _session_completer(
-    prefix: str, parsed_args: argparse.Namespace, **kwargs: Any
+    prefix: str,  # noqa: ARG001
+    parsed_args: argparse.Namespace,
+    **kwargs: Any,
 ) -> Iterable[str]:
     parsed_args.list_sessions = True
     module = load_nox_module(parsed_args)
@@ -296,7 +303,9 @@ def _session_completer(
 
 
 def _tag_completer(
-    prefix: str, parsed_args: argparse.Namespace, **kwargs: Any
+    prefix: str,  # noqa: ARG001
+    parsed_args: argparse.Namespace,
+    **kwargs: Any,
 ) -> Iterable[str]:
     module = load_nox_module(parsed_args)
     manifest = discover_manifest(module, parsed_args)
diff --git a/nox/_parametrize.py b/nox/_parametrize.py
index 281607f..15f802e 100644
--- a/nox/_parametrize.py
+++ b/nox/_parametrize.py
@@ -16,8 +16,10 @@ from __future__ import annotations
 
 import functools
 import itertools
-from collections.abc import Callable, Sequence
-from typing import Any, Iterable, Union
+from typing import TYPE_CHECKING, Any, Iterable, Union
+
+if TYPE_CHECKING:
+    from collections.abc import Callable, Sequence
 
 
 class Param:
@@ -73,9 +75,9 @@ class Param:
 
     def update(self, other: Param) -> None:
         self.id = ", ".join([str(self), str(other)])
-        self.args = self.args + other.args
-        self.arg_names = self.arg_names + other.arg_names
-        self.tags = self.tags + other.tags
+        self.args += other.args
+        self.arg_names += other.arg_names
+        self.tags += other.tags
 
     def __eq__(self, other: object) -> bool:
         if isinstance(other, self.__class__):
diff --git a/nox/_resolver.py b/nox/_resolver.py
index c5c2a8e..e95af67 100644
--- a/nox/_resolver.py
+++ b/nox/_resolver.py
@@ -28,6 +28,7 @@ class CycleError(ValueError):
 def lazy_stable_topo_sort(
     dependencies: Mapping[Node, Iterable[Node]],
     root: Node,
+    *,
     drop_root: bool = True,
 ) -> Iterator[Node]:
     """Returns the "lazy, stable" topological sort of a dependency graph.
@@ -118,7 +119,7 @@ def lazy_stable_topo_sort(
         ~nox._resolver.CycleError: If a dependency cycle is encountered.
     """
 
-    visited = {node: False for node in dependencies}
+    visited = dict.fromkeys(dependencies, False)
 
     def prepended_by_dependencies(
         node: Node,
@@ -191,7 +192,8 @@ def lazy_stable_topo_sort(
             # Dependency cycle found.
             walk_list = list(walk)
             cycle = walk_list[walk_list.index(node) :] + [node]
-            raise CycleError("Nodes are in a dependency cycle", tuple(cycle))
+            msg = "Nodes are in a dependency cycle"
+            raise CycleError(msg, tuple(cycle))
         walk[node] = None
         return walk
 
diff --git a/nox/_version.py b/nox/_version.py
index 3d1026d..f233c09 100644
--- a/nox/_version.py
+++ b/nox/_version.py
@@ -61,7 +61,7 @@ def _parse_needs_version(source: str, filename: str = "<unknown>") -> str | None
 
 def _read_needs_version(filename: str) -> str | None:
     """Read ``nox.needs_version`` from the user's Noxfile."""
-    with open(filename) as io:
+    with open(filename, encoding="utf-8") as io:
         source = io.read()
 
     return _parse_needs_version(source, filename=filename)
@@ -81,9 +81,8 @@ def _check_nox_version_satisfies(needs_version: str) -> None:
         raise InvalidVersionSpecifier(message) from error
 
     if not specifiers.contains(version, prereleases=True):
-        raise VersionCheckFailed(
-            f"The Noxfile requires Nox {specifiers}, you have {version}"
-        )
+        msg = f"The Noxfile requires Nox {specifiers}, you have {version}"
+        raise VersionCheckFailed(msg)
 
 
 def check_nox_version(filename: str) -> None:
diff --git a/nox/command.py b/nox/command.py
index 1133347..976e7f9 100644
--- a/nox/command.py
+++ b/nox/command.py
@@ -20,14 +20,13 @@ import shutil
 import subprocess
 import sys
 from collections.abc import Iterable, Mapping, Sequence
-from typing import Literal, overload
+from typing import TYPE_CHECKING, Literal, overload
 
 from nox.logger import logger
 from nox.popen import DEFAULT_INTERRUPT_TIMEOUT, DEFAULT_TERMINATE_TIMEOUT, popen
 
-TYPE_CHECKING = False
-
 if TYPE_CHECKING:
+    from collections.abc import Iterable, Mapping, Sequence
     from typing import IO
 
 ExternalType = Literal["error", True, False]
@@ -53,7 +52,8 @@ def which(program: str | os.PathLike[str], paths: Sequence[str] | None) -> str:
         return os.fspath(full_path)
 
     logger.error(f"Program {program} not found.")
-    raise CommandFailed(f"Program {program} not found")
+    msg = f"Program {program} not found"
+    raise CommandFailed(msg)
 
 
 def _clean_env(env: Mapping[str, str | None] | None = None) -> dict[str, str] | None:
@@ -162,7 +162,8 @@ def run(
                     f" at {cmd_path}. Pass external=True into run() to explicitly allow"
                     " this."
                 )
-                raise CommandFailed("External program disallowed.")
+                msg = "External program disallowed."
+                raise CommandFailed(msg)
             if external is False:
                 logger.warning(
                     f"Warning: {cmd} is not installed into the virtualenv, it is"
@@ -192,13 +193,14 @@ def run(
             if silent:
                 sys.stderr.write(output)
 
-            raise CommandFailed(f"Returned code {return_code}")
+            msg = f"Returned code {return_code}"
+            raise CommandFailed(msg)
 
         if output:
             logger.output(output)
 
-        return output if silent else True
-
     except KeyboardInterrupt:
         logger.error("Interrupted...")
         raise
+
+    return output if silent else True
diff --git a/nox/logger.py b/nox/logger.py
index e3ecf65..6dd2360 100644
--- a/nox/logger.py
+++ b/nox/logger.py
@@ -23,7 +23,7 @@ SUCCESS = 25
 OUTPUT = logging.DEBUG - 1
 
 
-def _get_format(colorlog: bool, add_timestamp: bool) -> str:
+def _get_format(*, colorlog: bool, add_timestamp: bool) -> str:
     if colorlog:
         if add_timestamp:
             return "%(cyan)s%(name)s > [%(asctime)s] %(log_color)s%(message)s"
@@ -36,7 +36,7 @@ def _get_format(colorlog: bool, add_timestamp: bool) -> str:
 
 
 class NoxFormatter(logging.Formatter):
-    def __init__(self, add_timestamp: bool = False) -> None:
+    def __init__(self, *, add_timestamp: bool = False) -> None:
         super().__init__(fmt=_get_format(colorlog=False, add_timestamp=add_timestamp))
         self._simple_fmt = logging.Formatter("%(message)s")
 
@@ -49,6 +49,7 @@ class NoxFormatter(logging.Formatter):
 class NoxColoredFormatter(ColoredFormatter):
     def __init__(
         self,
+        *,
         datefmt: Any = None,
         style: Any = None,
         log_colors: Any = None,
@@ -91,7 +92,7 @@ logging.setLoggerClass(LoggerWithSuccessAndOutput)
 logger = cast(LoggerWithSuccessAndOutput, logging.getLogger("nox"))
 
 
-def _get_formatter(color: bool, add_timestamp: bool) -> logging.Formatter:
+def _get_formatter(*, color: bool, add_timestamp: bool) -> logging.Formatter:
     if color:
         return NoxColoredFormatter(
             reset=True,
@@ -111,7 +112,7 @@ def _get_formatter(color: bool, add_timestamp: bool) -> logging.Formatter:
 
 
 def setup_logging(
-    color: bool, verbose: bool = False, add_timestamp: bool = False
+    *, color: bool, verbose: bool = False, add_timestamp: bool = False
 ) -> None:  # pragma: no cover
     """Setup logging.
 
@@ -126,7 +127,7 @@ def setup_logging(
         root_logger.setLevel(logging.DEBUG)
     handler = logging.StreamHandler()
 
-    handler.setFormatter(_get_formatter(color, add_timestamp))
+    handler.setFormatter(_get_formatter(color=color, add_timestamp=add_timestamp))
     root_logger.addHandler(handler)
 
     # Silence noisy loggers
diff --git a/nox/manifest.py b/nox/manifest.py
index 1bb6e00..c3ca9fd 100644
--- a/nox/manifest.py
+++ b/nox/manifest.py
@@ -14,18 +14,20 @@
 
 from __future__ import annotations
 
-import argparse
 import ast
 import itertools
 import operator
 from collections import OrderedDict
-from collections.abc import Iterable, Iterator, Sequence
-from typing import Any, Mapping, cast
+from typing import TYPE_CHECKING, Any, Mapping, cast
 
 from nox._decorators import Call, Func
 from nox._resolver import CycleError, lazy_stable_topo_sort
 from nox.sessions import Session, SessionRunner
 
+if TYPE_CHECKING:
+    import argparse
+    from collections.abc import Iterable, Iterator, Sequence
+
 WARN_PYTHONS_IGNORED = "python_ignored"
 
 
@@ -156,12 +158,12 @@ class Manifest:
         """
         # Filter the sessions remaining in the queue based on
         # whether they are individually specified.
-        queue = []
-        for session_name in specified_sessions:
-            for session in self._queue:
-                if _normalized_session_match(session_name, session):
-                    queue.append(session)
-        self._queue = queue
+        self._queue = [
+            session
+            for session_name in specified_sessions
+            for session in self._queue
+            if _normalized_session_match(session_name, session)
+        ]
 
         # If a session was requested and was not found, complain loudly.
         all_sessions = set(
@@ -181,7 +183,8 @@ class Manifest:
             if _normalize_arg(session_name) not in all_sessions
         ]
         if missing_sessions:
-            raise KeyError(f"Sessions not found: {', '.join(missing_sessions)}")
+            msg = f"Sessions not found: {', '.join(missing_sessions)}"
+            raise KeyError(msg)
 
     def filter_by_default(self) -> None:
         """Filter sessions in the queue based on the default flag."""
@@ -241,7 +244,7 @@ class Manifest:
                 session.signatures[0] for session in parametrized_sessions
             ]
             parent_session = SessionRunner(
-                parent_name, [], parent_func, self._config, self, False
+                parent_name, [], parent_func, self._config, self, multi=False
             )
             parent_sessions.add(parent_session)
             sessions_by_id[parent_name] = parent_session
@@ -272,7 +275,7 @@ class Manifest:
         ]
 
     def make_session(
-        self, name: str, func: Func, multi: bool = False
+        self, name: str, func: Func, *, multi: bool = False
     ) -> list[SessionRunner]:
         """Create a session object from the session function.
 
@@ -338,7 +341,9 @@ class Manifest:
             if func.python:
                 long_names.append(f"{name}-{func.python}")
 
-            return [SessionRunner(name, long_names, func, self._config, self, multi)]
+            return [
+                SessionRunner(name, long_names, func, self._config, self, multi=multi)
+            ]
 
         # Since this function is parametrized, we need to add a distinct
         # session for each permutation.
@@ -354,21 +359,23 @@ class Manifest:
                 long_names.append(f"{name}-{func.python}")
 
             sessions.append(
-                SessionRunner(name, long_names, call, self._config, self, multi)
+                SessionRunner(name, long_names, call, self._config, self, multi=multi)
             )
 
         # Edge case: If the parameters made it such that there were no valid
         # calls, add an empty, do-nothing session.
         if not calls:
             sessions.append(
-                SessionRunner(name, [], _null_session_func, self._config, self, multi)
+                SessionRunner(
+                    name, [], _null_session_func, self._config, self, multi=multi
+                )
             )
 
         # Return the list of sessions.
         return sessions
 
     def next(self) -> SessionRunner:
-        return self.__next__()
+        return next(self)
 
     def notify(
         self, session: str | SessionRunner, posargs: Iterable[str] | None = None
@@ -407,7 +414,8 @@ class Manifest:
                 return True
 
         # The session was not found in the list of sessions.
-        raise ValueError(f"Session {session} not found.")
+        msg = f"Session {session} not found."
+        raise ValueError(msg)
 
 
 class KeywordLocals(Mapping[str, bool]):
@@ -434,8 +442,9 @@ class KeywordLocals(Mapping[str, bool]):
 
 def keyword_match(expression: str, keywords: Iterable[str]) -> Any:
     """See if an expression matches the given set of keywords."""
+    # TODO: see if we can use ast.literal_eval here.
     locals = KeywordLocals(set(keywords))
-    return eval(expression, {}, locals)
+    return eval(expression, {}, locals)  # noqa: S307
 
 
 def _null_session_func_(session: Session) -> None:
diff --git a/nox/popen.py b/nox/popen.py
index 5f32a9e..b6f7bc6 100644
--- a/nox/popen.py
+++ b/nox/popen.py
@@ -18,8 +18,10 @@ import contextlib
 import locale
 import subprocess
 import sys
-from collections.abc import Mapping, Sequence
-from typing import IO
+from typing import IO, TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from collections.abc import Mapping, Sequence
 
 DEFAULT_INTERRUPT_TIMEOUT = 0.3
 DEFAULT_TERMINATE_TIMEOUT = 0.2
@@ -55,7 +57,7 @@ def decode_output(output: bytes) -> str:
         return output.decode("utf-8")
     except UnicodeDecodeError:
         second_encoding = locale.getpreferredencoding()
-        if second_encoding.casefold() in ("utf8", "utf-8"):
+        if second_encoding.casefold() in {"utf8", "utf-8"}:
             raise
 
         return output.decode(second_encoding)
@@ -63,6 +65,7 @@ def decode_output(output: bytes) -> str:
 
 def popen(
     args: Sequence[str],
+    *,
     env: Mapping[str, str] | None = None,
     silent: bool = False,
     stdout: int | IO[str] | None = None,
@@ -71,10 +74,11 @@ def popen(
     terminate_timeout: float | None = DEFAULT_TERMINATE_TIMEOUT,
 ) -> tuple[int, str]:
     if silent and stdout is not None:
-        raise ValueError(
+        msg = (
             "Can not specify silent and stdout; passing a custom stdout always silences"
             " the commands output in Nox's log."
         )
+        raise ValueError(msg)
 
     if silent:
         stdout = subprocess.PIPE
@@ -82,11 +86,11 @@ def popen(
     proc = subprocess.Popen(args, env=env, stdout=stdout, stderr=stderr)
 
     try:
-        out, err = proc.communicate()
+        out, _err = proc.communicate()
         sys.stdout.flush()
 
     except KeyboardInterrupt:
-        out, err = shutdown_process(proc, interrupt_timeout, terminate_timeout)
+        out, _err = shutdown_process(proc, interrupt_timeout, terminate_timeout)
         if proc.returncode != 0:
             raise
 
diff --git a/nox/project.py b/nox/project.py
index 61c6315..d808c9a 100644
--- a/nox/project.py
+++ b/nox/project.py
@@ -1,6 +1,5 @@
 from __future__ import annotations
 
-import os
 import re
 import sys
 from pathlib import Path
@@ -11,6 +10,7 @@ import packaging.specifiers
 from dependency_groups import resolve
 
 if TYPE_CHECKING:
+    import os
     from typing import Any
 
 if sys.version_info < (3, 11):
@@ -19,7 +19,7 @@ else:
     import tomllib
 
 
-__all__ = ["load_toml", "python_versions", "dependency_groups"]
+__all__ = ["dependency_groups", "load_toml", "python_versions"]
 
 
 def __dir__() -> list[str]:
@@ -71,9 +71,11 @@ def _load_script_block(filepath: Path) -> dict[str, Any]:
     matches = list(filter(lambda m: m.group("type") == name, REGEX.finditer(script)))
 
     if not matches:
-        raise ValueError(f"No {name} block found in {filepath}")
+        msg = f"No {name} block found in {filepath}"
+        raise ValueError(msg)
     if len(matches) > 1:
-        raise ValueError(f"Multiple {name} blocks found in {filepath}")
+        msg = f"Multiple {name} blocks found in {filepath}"
+        raise ValueError(msg)
 
     content = "".join(
         line[2:] if line.startswith("# ") else line[1:]
@@ -113,18 +115,21 @@ def python_versions(
         ]
         if from_classifiers:
             return from_classifiers
-        raise ValueError('No Python version classifiers found in "project.classifiers"')
+        msg = 'No Python version classifiers found in "project.classifiers"'
+        raise ValueError(msg)
 
     requires_python_str = pyproject.get("project", {}).get("requires-python", "")
     if not requires_python_str:
-        raise ValueError('No "project.requires-python" value set')
+        msg = 'No "project.requires-python" value set'
+        raise ValueError(msg)
 
     for spec in packaging.specifiers.SpecifierSet(requires_python_str):
         if spec.operator in {">", ">=", "~="}:
             min_minor_version = int(spec.version.split(".")[1])
             break
     else:
-        raise ValueError('No minimum version found in "project.requires-python"')
+        msg = 'No minimum version found in "project.requires-python"'
+        raise ValueError(msg)
 
     max_minor_version = int(max_version.split(".")[1])
 
diff --git a/nox/registry.py b/nox/registry.py
index 1697121..8669b54 100644
--- a/nox/registry.py
+++ b/nox/registry.py
@@ -17,11 +17,14 @@ from __future__ import annotations
 import collections
 import copy
 import functools
-from collections.abc import Sequence
-from typing import Any, Callable, overload
+from typing import TYPE_CHECKING, Any, Callable, overload
 
 from ._decorators import Func
-from ._typing import Python
+
+if TYPE_CHECKING:
+    from collections.abc import Sequence
+
+    from ._typing import Python
 
 RawFunc = Callable[..., Any]
 
@@ -29,12 +32,13 @@ _REGISTRY: collections.OrderedDict[str, Func] = collections.OrderedDict()
 
 
 @overload
-def session_decorator(__func: RawFunc | Func) -> Func: ...
+def session_decorator(func: RawFunc | Func, /) -> Func: ...
 
 
 @overload
 def session_decorator(
-    __func: None = ...,
+    func: None = ...,
+    /,
     python: Python | None = ...,
     py: Python | None = ...,
     reuse_venv: bool | None = ...,
@@ -50,6 +54,7 @@ def session_decorator(
 
 def session_decorator(
     func: Callable[..., Any] | Func | None = None,
+    /,
     python: Python | None = None,
     py: Python | None = None,
     reuse_venv: bool | None = None,
@@ -84,10 +89,11 @@ def session_decorator(
         )
 
     if py is not None and python is not None:
-        raise ValueError(
+        msg = (
             "The py argument to nox.session is an alias for the python "
             "argument, please only specify one."
         )
+        raise ValueError(msg)
 
     if python is None:
         python = py
diff --git a/nox/sessions.py b/nox/sessions.py
index f7819c5..8851c5a 100644
--- a/nox/sessions.py
+++ b/nox/sessions.py
@@ -14,7 +14,6 @@
 
 from __future__ import annotations
 
-import argparse
 import contextlib
 import enum
 import hashlib
@@ -25,15 +24,6 @@ import shutil
 import subprocess
 import sys
 import unicodedata
-from collections.abc import (
-    Callable,
-    Generator,
-    Iterable,
-    Iterator,
-    Mapping,
-    Sequence,
-)
-from types import TracebackType
 from typing import (
     TYPE_CHECKING,
     Any,
@@ -42,7 +32,6 @@ from typing import (
 
 import nox.command
 import nox.virtualenv
-from nox._decorators import Func
 from nox.logger import logger
 from nox.popen import DEFAULT_INTERRUPT_TIMEOUT, DEFAULT_TERMINATE_TIMEOUT
 from nox.virtualenv import (
@@ -54,8 +43,19 @@ from nox.virtualenv import (
 )
 
 if TYPE_CHECKING:
+    import argparse
+    from collections.abc import (
+        Callable,
+        Generator,
+        Iterable,
+        Iterator,
+        Mapping,
+        Sequence,
+    )
+    from types import TracebackType
     from typing import IO
 
+    from nox._decorators import Func
     from nox.command import ExternalType
     from nox.manifest import Manifest
 
@@ -88,7 +88,7 @@ def _normalize_path(envdir: str, path: str | bytes) -> str:
     full_path = os.path.join(envdir, path)
     if len(full_path) > 100 - len("bin/pythonX.Y"):
         if len(envdir) < 100 - 9:
-            path = hashlib.sha1(path.encode("ascii")).hexdigest()[:8]
+            path = hashlib.sha1(path.encode("ascii")).hexdigest()[:8]  # noqa: S324
             full_path = os.path.join(envdir, path)
             logger.warning("The virtualenv name was hashed to avoid being too long.")
         else:
@@ -108,9 +108,8 @@ def _dblquote_pkg_install_args(args: Iterable[str]) -> tuple[str, ...]:
     def _dblquote_pkg_install_arg(pkg_req_str: str) -> str:
         # sanity check: we need an even number of double-quotes
         if pkg_req_str.count('"') % 2 != 0:
-            raise ValueError(
-                f"ill-formatted argument with odd number of quotes: {pkg_req_str}"
-            )
+            msg = f"ill-formatted argument with odd number of quotes: {pkg_req_str}"
+            raise ValueError(msg)
 
         if "<" in pkg_req_str or ">" in pkg_req_str:
             if pkg_req_str[0] == pkg_req_str[-1] == '"':
@@ -118,7 +117,8 @@ def _dblquote_pkg_install_args(args: Iterable[str]) -> tuple[str, ...]:
                 return pkg_req_str
             # need to double-quote string
             if '"' in pkg_req_str:
-                raise ValueError(f"Cannot escape requirement string: {pkg_req_str}")
+                msg = f"Cannot escape requirement string: {pkg_req_str}"
+                raise ValueError(msg)
             return f'"{pkg_req_str}"'
         # no dangerous char: no need to double-quote string
         return pkg_req_str
@@ -147,7 +147,7 @@ class _WorkingDirContext:
         self._prev_working_dir = os.getcwd()
         os.chdir(dir)
 
-    def __enter__(self) -> _WorkingDirContext:
+    def __enter__(self) -> _WorkingDirContext:  # noqa: PYI034
         return self
 
     def __exit__(
@@ -201,7 +201,8 @@ class Session:
         """The virtualenv that all commands are run in."""
         venv = self._runner.venv
         if venv is None:
-            raise ValueError("A virtualenv has not been created for this session")
+            msg = "A virtualenv has not been created for this session"
+            raise ValueError(msg)
         return venv
 
     @property
@@ -227,7 +228,8 @@ class Session:
         """The first bin directory for the virtualenv."""
         paths = self.bin_paths
         if paths is None:
-            raise ValueError("The environment does not have a bin directory.")
+            msg = "The environment does not have a bin directory."
+            raise ValueError(msg)
         return paths[0]
 
     def create_tmp(self) -> str:
@@ -278,6 +280,7 @@ class Session:
             silent=silent,
             success_codes=success_codes,
             external=None,
+            log=log,
             stdout=stdout,
             stderr=stderr,
             interrupt_timeout=interrupt_timeout,
@@ -439,7 +442,8 @@ class Session:
         :type stderr: file or file descriptor
         """
         if not args:
-            raise ValueError("At least one argument required to run().")
+            msg = "At least one argument required to run()."
+            raise ValueError(msg)
 
         if len(args) == 1 and isinstance(args[0], (list, tuple)):
             msg = "First argument to `session.run` is a list. Did you mean to use `session.run(*args)`?"
@@ -529,7 +533,8 @@ class Session:
             return None
 
         if not args:
-            raise ValueError("At least one argument required to run_install().")
+            msg = "At least one argument required to run_install()"
+            raise ValueError(msg)
 
         return self._run(
             *args,
@@ -696,13 +701,15 @@ class Session:
         if isinstance(venv, CondaEnv):
             prefix_args = ("--prefix", venv.location)
         elif not isinstance(venv, PassthroughEnv):
-            raise ValueError(
+            msg = (
                 "A session without a conda environment can not install dependencies"
                 " from conda."
             )
+            raise TypeError(msg)
 
         if not args:
-            raise ValueError("At least one argument required to install().")
+            msg = "At least one argument required to install()."
+            raise ValueError(msg)
 
         if self._runner.global_config.no_install and (
             isinstance(venv, PassthroughEnv) or venv._reused
@@ -756,7 +763,7 @@ class Session:
         silent: bool | None = None,
         success_codes: Iterable[int] | None = None,
         log: bool = True,
-        external: ExternalType | None = None,
+        external: ExternalType | None = None,  # noqa: ARG002
         stdout: int | IO[str] | None = None,
         stderr: int | IO[str] | None = subprocess.STDOUT,
         interrupt_timeout: float | None = DEFAULT_INTERRUPT_TIMEOUT,
@@ -803,20 +810,21 @@ class Session:
         if not isinstance(
             venv, (CondaEnv, VirtualEnv, PassthroughEnv)
         ):  # pragma: no cover
-            raise ValueError(
-                "A session without a virtualenv can not install dependencies."
-            )
+            msg = "A session without a virtualenv can not install dependencies."
+            raise TypeError(msg)
         if isinstance(venv, PassthroughEnv):
             if self._runner.global_config.no_install:
                 return
-            raise ValueError(
+            msg = (
                 f"Session {self.name} does not have a virtual environment, so use of"
                 " session.install() is no longer allowed since it would modify the"
                 " global Python environment. If you're really sure that is what you"
                 ' want to do, use session.run("pip", "install", ...) instead.'
             )
+            raise ValueError(msg)
         if not args:
-            raise ValueError("At least one argument required to install().")
+            msg = "At least one argument required to install()."
+            raise ValueError(msg)
 
         if self._runner.global_config.no_install and venv._reused:
             return
@@ -909,6 +917,7 @@ class SessionRunner:
         func: Func,
         global_config: argparse.Namespace,
         manifest: Manifest,
+        *,
         multi: bool = False,
     ) -> None:
         self.name = name
@@ -985,7 +994,8 @@ class SessionRunner:
             else:
                 yield from map(sessions_by_id.__getitem__, self.func.requires)
         except KeyError as exc:
-            raise KeyError(f"Session not found: {exc.args[0]}") from exc
+            msg = f"Session not found: {exc.args[0]}"
+            raise KeyError(msg) from exc
 
     def _create_venv(self) -> None:
         reuse_existing = self.reuse_existing_venv()
@@ -1135,9 +1145,6 @@ class Result:
     def __bool__(self) -> bool:
         return self.status.value > 0
 
-    def __nonzero__(self) -> bool:
-        return self.__bool__()
-
     @property
     def imperfect(self) -> str:
         """Return the English imperfect tense for the status.
diff --git a/nox/tasks.py b/nox/tasks.py
index 62bee9b..99dd3ee 100644
--- a/nox/tasks.py
+++ b/nox/tasks.py
@@ -19,9 +19,7 @@ import importlib.util
 import json
 import os
 import sys
-import types
-from argparse import Namespace
-from typing import Sequence, TypeVar
+from typing import TYPE_CHECKING, Sequence, TypeVar
 
 from colorlog.escape_codes import parse_colors
 
@@ -33,6 +31,10 @@ from nox.logger import logger
 from nox.manifest import WARN_PYTHONS_IGNORED, Manifest
 from nox.sessions import Result
 
+if TYPE_CHECKING:
+    import types
+    from argparse import Namespace
+
 
 def _load_and_exec_nox_module(global_config: Namespace) -> types.ModuleType:
     """
@@ -281,7 +283,7 @@ def _produce_listing(manifest: Manifest, global_config: Namespace) -> None:
     )
 
 
-def _produce_json_listing(manifest: Manifest, global_config: Namespace) -> None:
+def _produce_json_listing(manifest: Manifest, global_config: Namespace) -> None:  # noqa: ARG001
     report = []
     for session, selected in manifest.list_all_sessions():
         if selected:
@@ -370,7 +372,8 @@ Sequence_Results_T = TypeVar("Sequence_Results_T", bound=Sequence[Result])
 
 
 def print_summary(
-    results: Sequence_Results_T, global_config: Namespace
+    results: Sequence_Results_T,
+    global_config: Namespace,  # noqa: ARG001
 ) -> Sequence_Results_T:
     """Print a summary of the results.
 
@@ -416,7 +419,7 @@ def create_report(
         return results
 
     # Write the JSON report.
-    with open(global_config.report, "w") as report_file:
+    with open(global_config.report, "w", encoding="utf-8") as report_file:
         json.dump(
             {
                 "result": int(all(results)),
@@ -430,7 +433,7 @@ def create_report(
     return results
 
 
-def final_reduce(results: list[Result], global_config: Namespace) -> int:
+def final_reduce(results: list[Result], global_config: Namespace) -> int:  # noqa: ARG001
     """Reduce the results to a final exit code.
 
     Args:
diff --git a/nox/tox_to_nox.py b/nox/tox_to_nox.py
index 34eeaf9..a8e183c 100644
--- a/nox/tox_to_nox.py
+++ b/nox/tox_to_nox.py
@@ -70,7 +70,7 @@ def fixname(envname: str) -> str:
 
 def write_output_to_file(output: str, filename: str) -> None:
     """Write output to a file."""
-    with open(filename, "w") as outfile:
+    with open(filename, "w", encoding="utf-8") as outfile:
         outfile.write(output)
 
 
@@ -81,7 +81,7 @@ def main() -> None:
     args = parser.parse_args()
 
     if TOX4:
-        output = check_output(["tox", "config"], text=True)
+        output = check_output(["tox", "config"], text=True)  # noqa: S607
         original_config = ConfigParser()
         original_config.read_string(output)
         config: dict[str, dict[str, Any]] = {}
@@ -95,11 +95,11 @@ def main() -> None:
             set_env = {}
             for var in section.get("set_env", "").strip().splitlines():
                 k, v = var.split("=")
-                if k not in (
+                if k not in {
                     "PYTHONHASHSEED",
                     "PIP_DISABLE_PIP_VERSION_CHECK",
                     "PYTHONIOENCODING",
-                ):
+                }:
                     set_env[k] = v
 
             config[name]["set_env"] = set_env
diff --git a/nox/virtualenv.py b/nox/virtualenv.py
index 6091e17..2584b90 100644
--- a/nox/virtualenv.py
+++ b/nox/virtualenv.py
@@ -24,18 +24,21 @@ import re
 import shutil
 import subprocess
 import sys
-from collections.abc import Callable, Mapping, Sequence
 from pathlib import Path
 from socket import gethostbyname
-from typing import Any, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
 
 from packaging import version
 
 import nox
 import nox.command
-from nox._typing import Python
 from nox.logger import logger
 
+if TYPE_CHECKING:
+    from collections.abc import Callable, Mapping, Sequence
+
+    from nox._typing import Python
+
 # Problematic environment variables that are stripped from all commands inside
 # of a virtualenv. See https://github.com/theacodes/nox/issues/44
 _BLACKLISTED_ENV_VARS = frozenset(
@@ -151,7 +154,8 @@ class ProcessEnv(abc.ABC):
         """The first bin directory for the virtualenv."""
         paths = self.bin_paths
         if paths is None:
-            raise ValueError("The environment does not have a bin directory.")
+            msg = "The environment does not have a bin directory."
+            raise ValueError(msg)
         return paths[0]
 
     @abc.abstractmethod
@@ -288,9 +292,9 @@ class CondaEnv(ProcessEnv):
         self,
         location: str,
         interpreter: str | None = None,
+        *,
         reuse_existing: bool = False,
         venv_params: Sequence[str] = (),
-        *,
         conda_cmd: str = "conda",
     ):
         self.location_name = location
@@ -386,9 +390,9 @@ class CondaEnv(ProcessEnv):
         try:
             # DNS resolution to detect situation (1) or (2).
             host = gethostbyname("repo.anaconda.com")
-            return host is None
         except BaseException:  # pragma: no cover
             return True
+        return host is None
 
     @property
     def venv_backend(self) -> str:
@@ -422,8 +426,8 @@ class VirtualEnv(ProcessEnv):
         self,
         location: str,
         interpreter: str | None = None,
-        reuse_existing: bool = False,
         *,
+        reuse_existing: bool = False,
         venv_backend: str = "virtualenv",
         venv_params: Sequence[str] = (),
     ):
@@ -435,7 +439,7 @@ class VirtualEnv(ProcessEnv):
         self._venv_backend = venv_backend
         self.venv_params = venv_params or []
         if venv_backend not in {"virtualenv", "venv", "uv"}:
-            msg = f"venv_backend {venv_backend} not recognized"
+            msg = f"venv_backend {venv_backend!r} not recognized"
             raise ValueError(msg)
         super().__init__(env={"VIRTUAL_ENV": self.location, "CONDA_PREFIX": None})
 
@@ -454,7 +458,7 @@ class VirtualEnv(ProcessEnv):
     def _read_pyvenv_cfg(self) -> dict[str, str] | None:
         """Read a pyvenv.cfg file into dict, returns None if missing."""
         path = os.path.join(self.location, "pyvenv.cfg")
-        with contextlib.suppress(FileNotFoundError), open(path) as fp:
+        with contextlib.suppress(FileNotFoundError), open(path, encoding="utf-8") as fp:
             parts = (x.partition("=") for x in fp if "=" in x)
             return {k.strip(): v.strip() for k, _, v in parts}
         return None
diff --git a/nox/workflow.py b/nox/workflow.py
index 3b65325..1f31376 100644
--- a/nox/workflow.py
+++ b/nox/workflow.py
@@ -14,9 +14,11 @@
 
 from __future__ import annotations
 
-import argparse
-from collections.abc import Callable, Iterable
-from typing import Any
+from typing import TYPE_CHECKING, Any
+
+if TYPE_CHECKING:
+    import argparse
+    from collections.abc import Callable, Iterable
 
 
 def execute(
@@ -56,8 +58,8 @@ def execute(
             # and return it.
             if isinstance(return_value, int):
                 return return_value
-
-        # All tasks completed, presumably without error.
-        return 0
     except KeyboardInterrupt:
         return 130  # http://tldp.org/LDP/abs/html/exitcodes.html
+
+    # All tasks completed, presumably without error.
+    return 0
diff --git a/pyproject.toml b/pyproject.toml
index db1b664..f0911e8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -85,28 +85,50 @@ metadata.allow-ambiguous-features = true # disable normalization (tox-to-nox) fo
 
 [tool.ruff]
 lint.extend-select = [
+  # "ANN",  # flake8-annotations
+  "ARG",  # flake8-unused-arguments
   "B",    # flake8-bugbear
   "C4",   # flake8-comprehensions
+  "EM",   # flake8-errmsg
   "EXE",  # flake8-executable
+  "FBT",  # flake8-boolean-trap
+  "FLY",  # flynt
   "FURB", # refurb
   "I",    # isort
   "ICN",  # flake8-import-conventions
   "ISC",  # flake8-implicit-str-concat
+  "N",    # flake8-naming
+  "PERF", # perflint
   "PGH",  # pygrep-hooks
   "PIE",  # flake8-pie
   "PL",   # pylint
-  "RET",  # flake8-return
-  "RUF",  # Ruff-specific
-  "SIM",  # flake8-simplify
-  "UP",   # pyupgrade
-  "YTT",  # flake8-2020
+  "PT",   # flake8-pytest-style
+  # "PTH",  # flake8-use-pathlib
+  "PYI", # flake8-pyi
+  "RET", # flake8-return
+  "RUF", # Ruff-specific
+  "S",   # eval -> literal_eval
+  "SIM", # flake8-simplify
+  "TCH", # flake8-type-checking
+  "TRY", # tryceratops
+  "UP",  # pyupgrade
+  "YTT", # flake8-2020
 ]
 lint.ignore = [
   "ISC001",  # Conflicts with formatter
+  "N802",    # Function name should be lowercase
+  "N818",    # Error suffix for errors
   "PLR09",   # Too many X
   "PLR2004", # Magic value used in comparison
+  "S101",    # Use of assert detected
+  "S603",    # subprocess call - check for execution of untrusted input
 ]
+lint.per-file-ignores."tests/*.py" = [
+  "FBT001", # Boolean args okay for fixtures
+]
+lint.per-file-ignores."tests/resources/**.py" = [ "ARG001", "TRY002" ]
 lint.typing-modules = [ "nox._typing" ]
+lint.flake8-unused-arguments.ignore-variadic-names = true
 
 [tool.pyproject-fmt]
 max_supported_python = "3.13"
@@ -122,10 +144,10 @@ pythonpath = [ ".github/" ]
 
 [tool.coverage]
 run.branch = true
-run.omit = [ "nox/_typing.py" ]
 run.relative_files = true
 run.source_pkgs = [ "nox" ]
 report.exclude_also = [ "def __dir__()", "if TYPE_CHECKING:", "@overload" ]
+report.omit = [ "nox/_typing.py" ]
 
 [tool.mypy]
 python_version = "3.8"


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 3f566c6..4bb2f3a 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -43,7 +43,7 @@ def generate_noxfile_options(tmp_path: Path) -> Callable[..., str]:
         path = Path(RESOURCES) / "noxfile_options.py"
         text = path.read_text(encoding="utf8")
         if option_mapping:
-            for opt, _val in option_mapping.items():
+            for opt in option_mapping:
                 # "uncomment" options with values provided
                 text = re.sub(rf"(# )?nox.options.{opt}", f"nox.options.{opt}", text)
             text = Template(text).safe_substitute(**option_mapping)
diff --git a/tests/resources/noxfile_requires.py b/tests/resources/noxfile_requires.py
index a6acfad..f1e94b1 100644
--- a/tests/resources/noxfile_requires.py
+++ b/tests/resources/noxfile_requires.py
@@ -100,7 +100,8 @@ def q(session):
 @nox.session
 def r(session):
     print(session.name)
-    raise Exception("Fail!")
+    msg = "Fail!"
+    raise Exception(msg)
 
 
 @nox.session(requires=["r"])
diff --git a/tests/test__option_set.py b/tests/test__option_set.py
index fea2ff8..3eb5b15 100644
--- a/tests/test__option_set.py
+++ b/tests/test__option_set.py
@@ -82,7 +82,10 @@ class TestOptionSet:
             _option_set.Option("oh_no_i_have_no_group", group=None, default="meep")
         )
 
-        with pytest.raises(ValueError):
+        with pytest.raises(
+            ValueError,
+            match="Option oh_no_i_have_no_group must either have a group or be hidden",
+        ):
             optionset.parser()
 
     def test_session_completer(self) -> None:
diff --git a/tests/test__parametrize.py b/tests/test__parametrize.py
index 4d1fda5..7c73d13 100644
--- a/tests/test__parametrize.py
+++ b/tests/test__parametrize.py
@@ -23,7 +23,7 @@ from nox import _decorators, _parametrize, parametrize, session
 
 
 @pytest.mark.parametrize(
-    "param, other, expected",
+    ("param", "other", "expected"),
     [
         (_parametrize.Param(1, 2), _parametrize.Param(1, 2), True),
         (_parametrize.Param(1, 2, id="a"), _parametrize.Param(1, 2, id="a"), True),
diff --git a/tests/test__version.py b/tests/test__version.py
index b6db4db..772dd9a 100644
--- a/tests/test__version.py
+++ b/tests/test__version.py
@@ -14,9 +14,8 @@
 
 from __future__ import annotations
 
-from collections.abc import Callable
-from pathlib import Path
 from textwrap import dedent
+from typing import TYPE_CHECKING
 
 import pytest
 
@@ -29,6 +28,10 @@ from nox._version import (
     get_nox_version,
 )
 
+if TYPE_CHECKING:
+    from collections.abc import Callable
+    from pathlib import Path
+
 
 @pytest.fixture
 def temp_noxfile(tmp_path: Path) -> Callable[[str], str]:
@@ -48,12 +51,12 @@ def test_needs_version_default() -> None:
 def test_get_nox_version() -> None:
     """It returns something that looks like a Nox version."""
     result = get_nox_version()
-    year, month, day, *_ = (int(part) for part in result.split("."))
+    year, _month, _day, *_ = (int(part) for part in result.split("."))
     assert year >= 2020
 
 
 @pytest.mark.parametrize(
-    "text,expected",
+    ("text", "expected"),
     [
         ("", None),
         (
diff --git a/tests/test_command.py b/tests/test_command.py
index e798e93..62c783c 100644
--- a/tests/test_command.py
+++ b/tests/test_command.py
@@ -25,15 +25,17 @@ import sys
 import time
 from pathlib import Path
 from textwrap import dedent
-from typing import Any
+from typing import TYPE_CHECKING, Any
 from unittest import mock
 
 import pytest
-from _pytest.compat import LEGACY_PATH
 
 import nox.command
 import nox.popen
 
+if TYPE_CHECKING:
+    from _pytest.compat import LEGACY_PATH
+
 PYTHON = sys.executable
 
 skip_on_windows_primary_console_session = pytest.mark.skipif(
@@ -46,7 +48,7 @@ only_on_windows = pytest.mark.skipif(
 )
 
 
-def test_run_defaults(capsys: pytest.CaptureFixture[str]) -> None:
+def test_run_defaults() -> None:
     result = nox.command.run([PYTHON, "-c", "print(123)"])
 
     assert result is True
@@ -62,7 +64,7 @@ def test_run_silent(capsys: pytest.CaptureFixture[str]) -> None:
 
 
 @pytest.mark.skipif(shutil.which("git") is None, reason="Needs git")
-def test_run_not_in_path(capsys: pytest.CaptureFixture[str]) -> None:
+def test_run_not_in_path() -> None:
     # Paths falls back on the environment PATH if the command is not found.
     result = nox.command.run(["git", "--version"], paths=["."])
     assert result is True
@@ -271,9 +273,9 @@ def test_fail_with_silent(capsys: pytest.CaptureFixture[str]) -> None:
             ],
             silent=True,
         )
-        out, err = capsys.readouterr()
-        assert "out" in err
-        assert "err" in err
+    _out, err = capsys.readouterr()
+    assert "out" in err
+    assert "err" in err
 
 
 @pytest.fixture
@@ -282,7 +284,7 @@ def marker(tmp_path: Path) -> Path:
     return tmp_path / "marker"
 
 
-def enable_ctrl_c(enabled: bool) -> None:
+def enable_ctrl_c(*, enabled: bool) -> None:
     """Enable keyboard interrupts (CTRL-C) on Windows."""
     kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)  # type: ignore[attr-defined]
 
@@ -294,7 +296,7 @@ def interrupt_process(proc: subprocess.Popen[Any]) -> None:
     """Send SIGINT or CTRL_C_EVENT to the process."""
     if platform.system() == "Windows":
         # Disable Ctrl-C so we don't terminate ourselves.
-        enable_ctrl_c(False)
+        enable_ctrl_c(enabled=False)
 
         # Send the keyboard interrupt to all processes attached to the current
         # console session.
@@ -310,7 +312,7 @@ def command_with_keyboard_interrupt(
     """Monkeypatch Popen.communicate to raise KeyboardInterrupt."""
     if platform.system() == "Windows":
         # Enable Ctrl-C because the child inherits the setting from us.
-        enable_ctrl_c(True)
+        enable_ctrl_c(enabled=True)
 
     communicate = subprocess.Popen.communicate
 
@@ -390,8 +392,8 @@ def run_pytest_in_new_console_session(test: str) -> None:
         """,
     ],
 )
+@pytest.mark.usefixtures("command_with_keyboard_interrupt")
 def test_interrupt_raises(
-    command_with_keyboard_interrupt: None,
     program: str,
     marker: Any,
 ) -> None:
@@ -407,7 +409,7 @@ def test_interrupt_raises_on_windows() -> None:
 
 
 @skip_on_windows_primary_console_session
-def test_interrupt_handled(command_with_keyboard_interrupt: None, marker: Any) -> None:
+def test_interrupt_handled(command_with_keyboard_interrupt: None, marker: Any) -> None:  # noqa: ARG001
     """It does not raise if the child handles the keyboard interrupt."""
     program = """
     import signal
@@ -429,7 +431,7 @@ def test_interrupt_handled_on_windows() -> None:
 
 
 def test_custom_stdout(capsys: pytest.CaptureFixture[str], tmpdir: LEGACY_PATH) -> None:
-    with open(str(tmpdir / "out.txt"), "w+t") as stdout:
+    with open(str(tmpdir / "out.txt"), "w+") as stdout:
         nox.command.run(
             [
                 PYTHON,
@@ -451,10 +453,8 @@ def test_custom_stdout(capsys: pytest.CaptureFixture[str], tmpdir: LEGACY_PATH)
         assert "err" in tempfile_contents
 
 
-def test_custom_stdout_silent_flag(
-    capsys: pytest.CaptureFixture[str], tmpdir: LEGACY_PATH
-) -> None:
-    with open(str(tmpdir / "out.txt"), "w+t") as stdout:  # noqa: SIM117
+def test_custom_stdout_silent_flag(tmpdir: LEGACY_PATH) -> None:
+    with open(str(tmpdir / "out.txt"), "w+") as stdout:  # noqa: SIM117
         with pytest.raises(ValueError, match="silent"):
             nox.command.run([PYTHON, "-c", 'print("hi")'], stdout=stdout, silent=True)
 
@@ -462,7 +462,7 @@ def test_custom_stdout_silent_flag(
 def test_custom_stdout_failed_command(
     capsys: pytest.CaptureFixture[str], tmpdir: LEGACY_PATH
 ) -> None:
-    with open(str(tmpdir / "out.txt"), "w+t") as stdout:
+    with open(str(tmpdir / "out.txt"), "w+") as stdout:
         with pytest.raises(nox.command.CommandFailed):
             nox.command.run(
                 [
@@ -486,7 +486,7 @@ def test_custom_stdout_failed_command(
 
 
 def test_custom_stderr(capsys: pytest.CaptureFixture[str], tmpdir: LEGACY_PATH) -> None:
-    with open(str(tmpdir / "err.txt"), "w+t") as stderr:
+    with open(str(tmpdir / "err.txt"), "w+") as stderr:
         nox.command.run(
             [
                 PYTHON,
@@ -511,7 +511,7 @@ def test_custom_stderr(capsys: pytest.CaptureFixture[str], tmpdir: LEGACY_PATH)
 def test_custom_stderr_failed_command(
     capsys: pytest.CaptureFixture[str], tmpdir: LEGACY_PATH
 ) -> None:
-    with open(str(tmpdir / "out.txt"), "w+t") as stderr:
+    with open(str(tmpdir / "out.txt"), "w+") as stderr:
         with pytest.raises(nox.command.CommandFailed):
             nox.command.run(
                 [
diff --git a/tests/test_logger.py b/tests/test_logger.py
index 5b77484..a322675 100644
--- a/tests/test_logger.py
+++ b/tests/test_logger.py
@@ -36,12 +36,12 @@ def test_output() -> None:
 
 def test_formatter(caplog: pytest.LogCaptureFixture) -> None:
     caplog.clear()
-    logger.setup_logging(True, verbose=True)
+    logger.setup_logging(color=True, verbose=True)
     with caplog.at_level(logging.DEBUG):
         logger.logger.info("bar")
         logger.logger.output("foo")
 
-    logs = [rec for rec in caplog.records if rec.levelname in ("INFO", "OUTPUT")]
+    logs = [rec for rec in caplog.records if rec.levelname in {"INFO", "OUTPUT"}]
     assert len(logs) == 1
     assert not hasattr(logs[0], "asctime")
 
@@ -50,7 +50,7 @@ def test_formatter(caplog: pytest.LogCaptureFixture) -> None:
         logger.logger.info("bar")
         logger.logger.output("foo")
 
-    logs = [rec for rec in caplog.records if rec.levelname in ("INFO", "OUTPUT")]
+    logs = [rec for rec in caplog.records if rec.levelname in {"INFO", "OUTPUT"}]
     assert len(logs) == 2
 
     logs = [rec for rec in caplog.records if rec.levelname == "OUTPUT"]
@@ -75,7 +75,7 @@ def test_no_color_timestamp(caplog: pytest.LogCaptureFixture, color: bool) -> No
         logger.logger.info("bar")
         logger.logger.output("foo")
 
-    logs = [rec for rec in caplog.records if rec.levelname in ("INFO", "OUTPUT")]
+    logs = [rec for rec in caplog.records if rec.levelname in {"INFO", "OUTPUT"}]
     assert len(logs) == 1
     assert hasattr(logs[0], "asctime")
 
diff --git a/tests/test_main.py b/tests/test_main.py
index 6a17fea..67cfdbb 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -18,10 +18,9 @@ import contextlib
 import os
 import subprocess
 import sys
-from collections.abc import Callable
 from importlib import metadata
 from pathlib import Path
-from typing import Any, Literal
+from typing import TYPE_CHECKING, Any, Literal
 from unittest import mock
 
 import pytest
@@ -31,6 +30,9 @@ import nox._options
 import nox.registry
 import nox.sessions
 
+if TYPE_CHECKING:
+    from collections.abc import Callable
+
 RESOURCES = os.path.join(os.path.dirname(__file__), "resources")
 VERSION = metadata.version("nox")
 
@@ -221,7 +223,7 @@ def test_main_explicit_sessions_with_spaces_in_names(
 
 
 @pytest.mark.parametrize(
-    "var,option,env,values",
+    ("var", "option", "env", "values"),
     [
         ("NOXSESSION", "sessions", "foo", ["foo"]),
         ("NOXSESSION", "sessions", "foo,bar", ["foo", "bar"]),
@@ -270,7 +272,7 @@ def test_main_list_option_from_nox_env_var(
 
 
 @pytest.mark.parametrize(
-    "options,env,expected",
+    ("options", "env", "expected"),
     [
         (["--default-venv-backend", "conda"], "", "conda"),
         ([], "mamba", "mamba"),
@@ -569,15 +571,11 @@ def test_main_requires_bad_python_parametrization(
     run_nox: Callable[..., tuple[Any, Any, Any]],
 ) -> None:
     noxfile = os.path.join(RESOURCES, "noxfile_requires.py")
-    with pytest.raises(
-        ValueError,
-        match="Cannot parametrize requires",
-    ):
-        returncode, _, _ = run_nox(f"--noxfile={noxfile}", "--session=q")
-        assert returncode != 0
+    with pytest.raises(ValueError, match="Cannot parametrize requires"):
+        run_nox(f"--noxfile={noxfile}", "--session=q")
 
 
-@pytest.mark.parametrize("session", ("s", "t"))
+@pytest.mark.parametrize("session", ["s", "t"])
 def test_main_requires_chain_fail(
     run_nox: Callable[..., tuple[Any, Any, Any]], session: str
 ) -> None:
@@ -587,13 +585,13 @@ def test_main_requires_chain_fail(
     assert "Prerequisite session r was not successful" in stderr
 
 
-@pytest.mark.parametrize("session", ("w", "u"))
+@pytest.mark.parametrize("session", ["w", "u"])
 def test_main_requries_modern_param(
     run_nox: Callable[..., tuple[Any, Any, Any]],
     session: str,
 ) -> None:
     noxfile = os.path.join(RESOURCES, "noxfile_requires.py")
-    returncode, _, stderr = run_nox(f"--noxfile={noxfile}", f"--session={session}")
+    returncode, _, _stderr = run_nox(f"--noxfile={noxfile}", f"--session={session}")
     assert returncode == 0
 
 
@@ -849,11 +847,9 @@ def test_main_reuse_existing_virtualenvs_no_install(
         with mock.patch.object(sys, "exit"):
             nox.main()
         config = execute.call_args[1]["global_config"]
-    assert (
-        config.reuse_existing_virtualenvs
-        and config.no_install
-        and config.reuse_venv == "yes"
-    )
+    assert config.reuse_existing_virtualenvs
+    assert config.no_install
+    assert config.reuse_venv == "yes"
 
 
 @pytest.mark.parametrize(
@@ -914,10 +910,10 @@ def test_main_noxfile_options_with_ci_override(
         "never",
     ],
 )
+@pytest.mark.usefixtures("generate_noxfile_options")
 def test_main_reuse_venv_cli_flags(
     monkeypatch: pytest.MonkeyPatch,
-    generate_noxfile_options: Callable[..., str],
-    reuse_venv: Literal["yes"] | Literal["no"] | Literal["always"] | Literal["never"],
+    reuse_venv: Literal["yes", "no", "always", "never"],
 ) -> None:
     monkeypatch.setattr(sys, "argv", ["nox", "--reuse-venv", reuse_venv])
     with mock.patch("nox.workflow.execute", return_value=0) as execute:
diff --git a/tests/test_manifest.py b/tests/test_manifest.py
index e79a14a..32d3a7f 100644
--- a/tests/test_manifest.py
+++ b/tests/test_manifest.py
@@ -17,7 +17,7 @@ from __future__ import annotations
 import collections
 import typing
 from collections.abc import Sequence
-from typing import Any
+from typing import TYPE_CHECKING, Any
 from unittest import mock
 
 import pytest
@@ -33,6 +33,9 @@ from nox.manifest import (
     _null_session_func,
 )
 
+if TYPE_CHECKING:
+    from collections.abc import Sequence
+
 
 def create_mock_sessions() -> collections.OrderedDict[str, mock.Mock]:
     sessions = collections.OrderedDict()
@@ -148,7 +151,7 @@ def test_iteration() -> None:
 
     # Continuing past the end raises StopIteration.
     with pytest.raises(StopIteration):
-        manifest.__next__()
+        next(manifest)
 
 
 def test_len() -> None:
@@ -205,7 +208,7 @@ def test_filter_by_keyword() -> None:
 
 
 @pytest.mark.parametrize(
-    "tags,session_count",
+    ("tags", "session_count"),
     [
         (["baz", "qux"], 2),
         (["baz"], 2),
@@ -257,7 +260,7 @@ def test_add_session_multiple_pythons() -> None:
 
 
 @pytest.mark.parametrize(
-    "python,extra_pythons,expected",
+    ("python", "extra_pythons", "expected"),
     [
         (None, [], [None]),
         (None, ["3.8"], [None]),
@@ -295,7 +298,7 @@ def test_extra_pythons(
 
 
 @pytest.mark.parametrize(
-    "python,force_pythons,expected",
+    ("python", "force_pythons", "expected"),
     [
         (None, [], [None]),
         (None, ["3.8"], ["3.8"]),
@@ -448,7 +451,7 @@ def test_notify_with_posargs() -> None:
     cfg = create_mock_config()
     manifest = Manifest({}, cfg)
 
-    session = manifest.make_session("my_session", Func(lambda session: None))[0]
+    session = manifest.make_session("my_session", Func(lambda _: None))[0]
     manifest.add_session(session)
 
     # delete my_session from the queue
@@ -461,7 +464,7 @@ def test_notify_with_posargs() -> None:
 
 def test_notify_error() -> None:
     manifest = Manifest({}, create_mock_config())
-    with pytest.raises(ValueError):
+    with pytest.raises(ValueError, match="Session does_not_exist not found"):
         manifest.notify("does_not_exist")
 
 
diff --git a/tests/test_registry.py b/tests/test_registry.py
index 40e14ec..07779ae 100644
--- a/tests/test_registry.py
+++ b/tests/test_registry.py
@@ -14,16 +14,18 @@
 
 from __future__ import annotations
 
-from collections.abc import Generator
-from typing import Literal
+from typing import TYPE_CHECKING, Literal
 
 import pytest
 
 import nox
 from nox import registry
 
+if TYPE_CHECKING:
+    from collections.abc import Generator
 
-@pytest.fixture
+
+@pytest.fixture(autouse=True)
 def cleanup_registry() -> Generator[None, None, None]:
     """Ensure that the session registry is completely empty before and
     after each test.
@@ -35,7 +37,7 @@ def cleanup_registry() -> Generator[None, None, None]:
         registry._REGISTRY.clear()
 
 
-def test_session_decorator(cleanup_registry: None) -> None:
+def test_session_decorator() -> None:
     # Establish that the use of the session decorator will cause the
     # function to be found in the registry.
     @registry.session_decorator
@@ -48,7 +50,7 @@ def test_session_decorator(cleanup_registry: None) -> None:
     assert unit_tests.python is None
 
 
-def test_session_decorator_single_python(cleanup_registry: None) -> None:
+def test_session_decorator_single_python() -> None:
     @registry.session_decorator(python="3.6")
     def unit_tests(session: nox.Session) -> None:
         pass
@@ -56,7 +58,7 @@ def test_session_decorator_single_python(cleanup_registry: None) -> None:
     assert unit_tests.python == "3.6"
 
 
-def test_session_decorator_list_of_pythons(cleanup_registry: None) -> None:
+def test_session_decorator_list_of_pythons() -> None:
     @registry.session_decorator(python=["3.5", "3.6"])
     def unit_tests(session: nox.Session) -> None:
         pass
@@ -64,7 +66,7 @@ def test_session_decorator_list_of_pythons(cleanup_registry: None) -> None:
     assert unit_tests.python == ["3.5", "3.6"]
 
 
-def test_session_decorator_tags(cleanup_registry: None) -> None:
+def test_session_decorator_tags() -> None:
     @registry.session_decorator(tags=["tag-1", "tag-2"])
     def unit_tests(session: nox.Session) -> None:
         pass
@@ -72,7 +74,7 @@ def test_session_decorator_tags(cleanup_registry: None) -> None:
     assert unit_tests.tags == ["tag-1", "tag-2"]
 
 
-def test_session_decorator_py_alias(cleanup_registry: None) -> None:
+def test_session_decorator_py_alias() -> None:
     @registry.session_decorator(py=["3.5", "3.6"])
     def unit_tests(session: nox.Session) -> None:
         pass
@@ -80,7 +82,7 @@ def test_session_decorator_py_alias(cleanup_registry: None) -> None:
     assert unit_tests.python == ["3.5", "3.6"]
 
 
-def test_session_decorator_py_alias_error(cleanup_registry: None) -> None:
+def test_session_decorator_py_alias_error() -> None:
     with pytest.raises(ValueError, match="argument"):
 
         @registry.session_decorator(python=["3.5", "3.6"], py="2.7")
@@ -88,7 +90,7 @@ def test_session_decorator_py_alias_error(cleanup_registry: None) -> None:
             pass
 
 
-def test_session_decorator_reuse(cleanup_registry: None) -> None:
+def test_session_decorator_reuse() -> None:
     @registry.session_decorator(reuse_venv=True)
     def unit_tests(session: nox.Session) -> None:
         pass
@@ -98,8 +100,7 @@ def test_session_decorator_reuse(cleanup_registry: None) -> None:
 
 @pytest.mark.parametrize("name", ["unit-tests", "unit tests", "the unit tests"])
 def test_session_decorator_name(
-    cleanup_registry: None,
-    name: Literal["unit-tests"] | Literal["unit tests"] | Literal["the unit tests"],
+    name: Literal["unit-tests", "unit tests", "the unit tests"],
 ) -> None:
     @registry.session_decorator(name=name)
     def unit_tests(session: nox.Session) -> None:
@@ -112,7 +113,7 @@ def test_session_decorator_name(
     assert unit_tests.python is None
 
 
-def test_get(cleanup_registry: None) -> None:
+def test_get() -> None:
     # Establish that the get method returns a copy of the registry.
     empty = registry.get()
     assert empty == registry._REGISTRY
diff --git a/tests/test_sessions.py b/tests/test_sessions.py
index cd9457d..1ed2352 100644
--- a/tests/test_sessions.py
+++ b/tests/test_sessions.py
@@ -29,7 +29,6 @@ from typing import Any, Literal, NoReturn
 from unittest import mock
 
 import pytest
-from _pytest.compat import LEGACY_PATH
 
 import nox._decorators
 import nox.command
@@ -41,6 +40,9 @@ import nox.virtualenv
 from nox import _options
 from nox.logger import logger
 
+if typing.TYPE_CHECKING:
+    from _pytest.compat import LEGACY_PATH
+
 HAS_CONDA = shutil.which("conda") is not None
 has_conda = pytest.mark.skipif(not HAS_CONDA, reason="Missing conda command.")
 
@@ -190,7 +192,7 @@ class TestSession:
         assert session.venv_backend == "none"
 
     def test_interactive(self) -> None:
-        session, runner = self.make_session_and_runner()
+        session, _runner = self.make_session_and_runner()
 
         with mock.patch("nox.sessions.sys.stdin.isatty") as m_isatty:
             m_isatty.return_value = True
@@ -271,7 +273,8 @@ class TestSession:
         session, _ = self.make_session_and_runner()
 
         def raise_value_error() -> NoReturn:
-            raise ValueError("meep")
+            msg = "meep"
+            raise ValueError(msg)
 
         with pytest.raises(nox.command.CommandFailed):
             assert session.run(raise_value_error)  # type: ignore[arg-type]
@@ -430,12 +433,11 @@ class TestSession:
     def test_run_install_bad_args(self) -> None:
         session, _ = self.make_session_and_runner()
 
-        with pytest.raises(ValueError) as exc_info:
+        with pytest.raises(
+            ValueError, match="At least one argument required to run_install"
+        ):
             session.run_install()
 
-        exc_args = exc_info.value.args
-        assert exc_args == ("At least one argument required to run_install().",)
-
     def test_run_no_install_passthrough(self) -> None:
         session, runner = self.make_session_and_runner()
         runner.venv = nox.virtualenv.PassthroughEnv()
@@ -445,9 +447,9 @@ class TestSession:
         session.conda_install("numpy")
 
     def test_run_no_conda_install(self) -> None:
-        session, runner = self.make_session_and_runner()
+        session, _runner = self.make_session_and_runner()
 
-        with pytest.raises(ValueError, match="A session without a conda"):
+        with pytest.raises(TypeError, match="A session without a conda"):
             session.conda_install("numpy")
 
     def test_run_install_success(self) -> None:
@@ -455,7 +457,7 @@ class TestSession:
 
         assert session.run_install(operator.add, 1300, 37) == 1337  # type: ignore[arg-type]
 
-    def test_run_install_install_only(self, caplog: pytest.LogCaptureFixture) -> None:
+    def test_run_install_install_only(self) -> None:
         session, runner = self.make_session_and_runner()
         runner.global_config.install_only = True
 
@@ -479,8 +481,8 @@ class TestSession:
         self,
         interrupt_timeout_setting: Literal["default"] | int | None,
         terminate_timeout_setting: Literal["default"] | int | None,
-        interrupt_timeout_expected: float | int | None,
-        terminate_timeout_expected: float | int | None,
+        interrupt_timeout_expected: float | None,
+        terminate_timeout_expected: float | None,
     ) -> None:
         session, runner = self.make_session_and_runner()
 
@@ -567,7 +569,7 @@ class TestSession:
 
         runner.venv = None
 
-        with pytest.raises(ValueError, match="conda environment"):
+        with pytest.raises(TypeError, match="conda environment"):
             session.conda_install()
 
     @pytest.mark.parametrize(
@@ -712,7 +714,7 @@ class TestSession:
 
         runner.venv = None
 
-        with pytest.raises(ValueError, match="virtualenv"):
+        with pytest.raises(TypeError, match="virtualenv"):
             session.install()
 
     def test_install(self) -> None:
@@ -815,7 +817,7 @@ class TestSession:
         runner.manifest.notify.assert_called_with("other", ["--an-arg"])  # type: ignore[attr-defined]
 
     def test_posargs_are_not_shared_between_sessions(
-        self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
+        self, monkeypatch: pytest.MonkeyPatch
     ) -> None:
         registry: dict[str, nox._decorators.Func] = {}
         monkeypatch.setattr("nox.registry._REGISTRY", registry)
@@ -827,7 +829,8 @@ class TestSession:
         @nox.session(venv_backend="none")
         def lint(session: nox.Session) -> None:
             if "-x" in session.posargs:
-                raise RuntimeError("invalid option: -x")
+                msg = "invalid option: -x"
+                raise RuntimeError(msg)
 
         config = _options.options.namespace(posargs=[], envdir=".nox")
         manifest = nox.manifest.Manifest(registry, config)
@@ -948,7 +951,7 @@ class TestSession:
         session = SessionNoSlots(runner=runner)
 
         monkeypatch.setattr(nox.virtualenv, "UV", "/some/uv")
-        monkeypatch.setattr(shutil, "which", lambda x, path=None: None)
+        monkeypatch.setattr(shutil, "which", lambda x, path=None: None)  # noqa: ARG005
 
         with mock.patch.object(nox.command, "run", autospec=True) as run:
             session.install("requests", "urllib3", silent=False)
@@ -996,7 +999,9 @@ class TestSession:
     def test_first_arg_list(self) -> None:
         session, _ = self.make_session_and_runner()
 
-        with pytest.raises(ValueError):
+        with pytest.raises(
+            ValueError, match="First argument to `session.run` is a list. Did you mean"
+        ):
             session.run(["ls", "-al"])  # type: ignore[arg-type]
 
 
@@ -1088,7 +1093,7 @@ class TestSessionRunner:
         assert runner.venv.reuse_existing is False
 
     @pytest.mark.parametrize(
-        "create_method,venv_backend,expected_backend",
+        ("create_method", "venv_backend", "expected_backend"),
         [
             ("nox.virtualenv.VirtualEnv.create", None, nox.virtualenv.VirtualEnv),
             (
@@ -1109,8 +1114,7 @@ class TestSessionRunner:
         self,
         create_method: str,
         venv_backend: None | str,
-        expected_backend: type[nox.virtualenv.VirtualEnv]
-        | type[nox.virtualenv.CondaEnv],
+        expected_backend: type[nox.virtualenv.VirtualEnv | nox.virtualenv.CondaEnv],
     ) -> None:
         runner = self.make_runner()
         runner.func.python = "coolpython"
@@ -1171,7 +1175,10 @@ class TestSessionRunner:
         )
         with mock.patch(
             "nox.virtualenv.VirtualEnv.create", autospec=True
-        ), pytest.raises(ValueError):
+        ), pytest.raises(
+            ValueError,
+            match="No backends present|Only optional backends|Expected venv_backend",
+        ):
             runner._create_venv()
 
     @pytest.mark.parametrize(
@@ -1307,7 +1314,7 @@ class TestSessionRunner:
     def test_execute_failed(self) -> None:
         runner = self.make_runner_with_mock_venv()
 
-        def func(session: nox.Session) -> None:
+        def func(session: nox.Session) -> None:  # noqa: ARG001
             raise nox.command.CommandFailed()
 
         func.requires = []  # type: ignore[attr-defined]
@@ -1320,7 +1327,7 @@ class TestSessionRunner:
     def test_execute_interrupted(self) -> None:
         runner = self.make_runner_with_mock_venv()
 
-        def func(session: nox.Session) -> None:
+        def func(session: nox.Session) -> None:  # noqa: ARG001
             raise KeyboardInterrupt()
 
         func.requires = []  # type: ignore[attr-defined]
@@ -1332,8 +1339,9 @@ class TestSessionRunner:
     def test_execute_exception(self) -> None:
         runner = self.make_runner_with_mock_venv()
 
-        def func(session: nox.Session) -> None:
-            raise ValueError("meep")
+        def func(session: nox.Session) -> None:  # noqa: ARG001
+            msg = "meep"
+            raise ValueError(msg)
 
         func.requires = []  # type: ignore[attr-defined]
         runner.func = func  # type: ignore[assignment]
@@ -1375,8 +1383,6 @@ class TestResult:
                 session=typing.cast(nox.sessions.SessionRunner, object()), status=status
             )
             assert bool(result)
-            assert result.__bool__()
-            assert result.__nonzero__()
 
     def test__bool_false(self) -> None:
         for status in (nox.sessions.Status.FAILED, nox.sessions.Status.ABORTED):
@@ -1384,8 +1390,6 @@ class TestResult:
                 session=typing.cast(nox.sessions.SessionRunner, object()), status=status
             )
             assert not bool(result)
-            assert not result.__bool__()
-            assert not result.__nonzero__()
 
     def test__imperfect(self) -> None:
         result = nox.sessions.Result(
diff --git a/tests/test_tasks.py b/tests/test_tasks.py
index 67457fd..28f8325 100644
--- a/tests/test_tasks.py
+++ b/tests/test_tasks.py
@@ -21,8 +21,6 @@ import json
 import os
 import platform
 import typing
-from collections.abc import Callable, Generator
-from pathlib import Path
 from textwrap import dedent
 from types import ModuleType
 from unittest import mock
@@ -34,6 +32,10 @@ import nox._decorators
 from nox import _options, sessions, tasks
 from nox.manifest import WARN_PYTHONS_IGNORED, Manifest
 
+if typing.TYPE_CHECKING:
+    from collections.abc import Callable, Generator
+    from pathlib import Path
+
 RESOURCES = os.path.join(os.path.dirname(__file__), "resources")
 
 
@@ -124,7 +126,7 @@ def test_load_nox_module_os_error(caplog: pytest.LogCaptureFixture) -> None:
         assert f"Failed to load Noxfile {noxfile}" in caplog.text
 
 
-@pytest.fixture
+@pytest.fixture(autouse=True)
 def reset_needs_version() -> Generator[None, None, None]:
     """Do not leak ``nox.needs_version`` between tests."""
     try:
@@ -138,9 +140,7 @@ def reset_global_nox_options() -> None:
     nox.options = _options.options.noxfile_namespace()
 
 
-def test_load_nox_module_needs_version_static(
-    reset_needs_version: None, tmp_path: Path
-) -> None:
+def test_load_nox_module_needs_version_static(tmp_path: Path) -> None:
     text = dedent(
         """
         import nox
@@ -153,9 +153,7 @@ def test_load_nox_module_needs_version_static(
     assert tasks.load_nox_module(config) == 2
 
 
-def test_load_nox_module_needs_version_dynamic(
-    reset_needs_version: None, tmp_path: Path
-) -> None:
+def test_load_nox_module_needs_version_dynamic(tmp_path: Path) -> None:
     text = dedent(
         """
         import nox
@@ -283,7 +281,7 @@ def test_filter_manifest_keywords_syntax_error() -> None:
 
 
 @pytest.mark.parametrize(
-    "tags,session_count",
+    ("tags", "session_count"),
     [
         (None, 8),
         (["foo"], 7),
@@ -297,11 +295,7 @@ def test_filter_manifest_keywords_syntax_error() -> None:
 )
 def test_filter_manifest_tags(
     tags: None | builtins.list[builtins.str],
-    session_count: builtins.int
-    | builtins.int
-    | builtins.int
-    | builtins.int
-    | builtins.int,
+    session_count: builtins.int,
 ) -> None:
     @nox.session(tags=["foo"])
     def qux() -> None:
@@ -370,9 +364,8 @@ def test_filter_manifest_tags_not_found(
     assert "Tag selection caused no sessions to be selected." in caplog.text
 
 
-def test_merge_sessions_and_tags(
-    reset_global_nox_options: None, generate_noxfile_options: Callable[..., str]
-) -> None:
+@pytest.mark.usefixtures("reset_global_nox_options")
+def test_merge_sessions_and_tags(generate_noxfile_options: Callable[..., str]) -> None:
     @nox.session(tags=["foobar"])
     def test() -> None:
         pass
@@ -441,7 +434,7 @@ def test_honor_list_request_noop() -> None:
 
 
 @pytest.mark.parametrize(
-    "description, module_docstring",
+    ("description", "module_docstring"),
     [
         (None, None),
         (None, "hello docstring"),
@@ -595,9 +588,7 @@ def test_empty_session_list_in_noxfile(
     assert "No sessions selected." in capsys.readouterr().out
 
 
-def test_empty_session_None_in_noxfile(
-    capsys: pytest.CaptureFixture[builtins.str],
-) -> None:
+def test_empty_session_None_in_noxfile() -> None:
     config = _options.options.namespace(noxfile="noxfile.py", sessions=None, posargs=[])
     manifest = Manifest({"session": session_func}, config)
     return_value = tasks.filter_manifest(manifest, global_config=config)
@@ -763,13 +754,13 @@ def test_create_report() -> None:
                 mock.ANY,
                 indent=2,
             )
-        open_.assert_called_once_with("/path/to/report", "w")
+        open_.assert_called_once_with("/path/to/report", "w", encoding="utf-8")
 
 
 def test_final_reduce() -> None:
     config = argparse.Namespace()
-    true = typing.cast(sessions.Result, True)
-    false = typing.cast(sessions.Result, False)
+    true = typing.cast(sessions.Result, True)  # noqa: FBT003
+    false = typing.cast(sessions.Result, False)  # noqa: FBT003
     assert tasks.final_reduce([true, true], config) == 0
     assert tasks.final_reduce([true, false], config) == 1
     assert tasks.final_reduce([], config) == 0
diff --git a/tests/test_tox_to_nox.py b/tests/test_tox_to_nox.py
index c5110b2..048b5d5 100644
--- a/tests/test_tox_to_nox.py
+++ b/tests/test_tox_to_nox.py
@@ -16,11 +16,14 @@ from __future__ import annotations
 
 import sys
 import textwrap
-from collections.abc import Callable
-from typing import Any
+from typing import TYPE_CHECKING, Any
 
 import pytest
-from _pytest.compat import LEGACY_PATH
+
+if TYPE_CHECKING:
+    from collections.abc import Callable
+
+    from _pytest.compat import LEGACY_PATH
 
 tox_to_nox = pytest.importorskip("nox.tox_to_nox")
 
diff --git a/tests/test_virtualenv.py b/tests/test_virtualenv.py
index 7c8e020..04282fd 100644
--- a/tests/test_virtualenv.py
+++ b/tests/test_virtualenv.py
@@ -21,20 +21,24 @@ import shutil
 import subprocess
 import sys
 import types
-from collections.abc import Callable
 from importlib import metadata
 from pathlib import Path
 from textwrap import dedent
-from typing import Any, NamedTuple, NoReturn
+from typing import TYPE_CHECKING, Any, NamedTuple, NoReturn
 from unittest import mock
 
 import pytest
-from _pytest.compat import LEGACY_PATH
 from packaging import version
 
 import nox.command
 import nox.virtualenv
-from nox.virtualenv import CondaEnv, ProcessEnv, VirtualEnv
+
+if TYPE_CHECKING:
+    from collections.abc import Callable
+
+    from _pytest.compat import LEGACY_PATH
+
+    from nox.virtualenv import CondaEnv, ProcessEnv, VirtualEnv
 
 IS_WINDOWS = nox.virtualenv._SYSTEM == "Windows"
 HAS_CONDA = shutil.which("conda") is not None
@@ -107,7 +111,7 @@ def patch_sysfind(
                 Use the global ``RAISE_ERROR`` to have ``sysexec`` fail.
         """
 
-        def special_which(name: str, path: Any = None) -> str | None:
+        def special_which(name: str, path: Any = None) -> str | None:  # noqa: ARG001
             if sysfind_result is None:
                 return None
             if name.lower() in only_find:
@@ -116,7 +120,7 @@ def patch_sysfind(
 
         monkeypatch.setattr(shutil, "which", special_which)
 
-        def special_run(cmd: Any, *args: Any, **kwargs: Any) -> TextProcessResult:
+        def special_run(cmd: Any, *args: Any, **kwargs: Any) -> TextProcessResult:  # noqa: ARG001
             return TextProcessResult(sysexec_result)
 
         monkeypatch.setattr(subprocess, "run", special_run)
@@ -149,7 +153,7 @@ def test_invalid_venv_create(
         ..., tuple[nox.virtualenv.VirtualEnv | nox.virtualenv.ProcessEnv, LEGACY_PATH]
     ],
 ) -> None:
-    with pytest.raises(ValueError):
+    with pytest.raises(ValueError, match="venv_backend 'invalid' not recognized"):
         make_one(venv_backend="invalid")
 
 
@@ -234,18 +238,18 @@ def test_condaenv_create_interpreter(
 def test_conda_env_create_verbose(
     make_conda: Callable[..., tuple[CondaEnv, Any]],
 ) -> None:
-    venv, dir_ = make_conda()
+    venv, _dir = make_conda()
     with mock.patch("nox.virtualenv.nox.command.run") as mock_run:
         venv.create()
 
-    args, kwargs = mock_run.call_args
+    _args, kwargs = mock_run.call_args
     assert kwargs["log"] is False
 
     nox.options.verbose = True
     with mock.patch("nox.virtualenv.nox.command.run") as mock_run:
         venv.create()
 
-    args, kwargs = mock_run.call_args
+    _args, kwargs = mock_run.call_args
     assert kwargs["log"]
 
 
@@ -264,7 +268,7 @@ def test_condaenv_bin_windows(make_conda: Callable[..., tuple[CondaEnv, Any]]) -
 
 @has_conda
 def test_condaenv_(make_conda: Callable[..., tuple[CondaEnv, Any]]) -> None:
-    venv, dir_ = make_conda()
+    venv, _dir = make_conda()
     assert not venv.is_offline()
 
 
@@ -462,7 +466,7 @@ def test_create(
 def test_create_reuse_environment(
     make_one: Callable[..., tuple[VirtualEnv | ProcessEnv, Any]],
 ) -> None:
-    venv, location = make_one(reuse_existing=True)
+    venv, _location = make_one(reuse_existing=True)
     venv.create()
 
     reused = not venv.create()
@@ -522,10 +526,10 @@ def test_not_stale_virtualenv_environment(
     # Making the reuse requirement more strict
     monkeypatch.setenv("NOX_ENABLE_STALENESS_CHECK", "1")
 
-    venv, location = make_one(reuse_existing=True, venv_backend="virtualenv")
+    venv, _location = make_one(reuse_existing=True, venv_backend="virtualenv")
     venv.create()
 
-    venv, location = make_one(reuse_existing=True, venv_backend="virtualenv")
+    venv, _location = make_one(reuse_existing=True, venv_backend="virtualenv")
     reused = not venv.create()
 
     assert reused
@@ -535,10 +539,10 @@ def test_not_stale_virtualenv_environment(
 def test_stale_virtualenv_to_conda_environment(
     make_one: Callable[..., tuple[VirtualEnv | ProcessEnv, Any]],
 ) -> None:
-    venv, location = make_one(reuse_existing=True, venv_backend="virtualenv")
+    venv, _location = make_one(reuse_existing=True, venv_backend="virtualenv")
     venv.create()
 
-    venv, location = make_one(reuse_existing=True, venv_backend="conda")
+    venv, _location = make_one(reuse_existing=True, venv_backend="conda")
     reused = not venv.create()
 
     # The environment is not reused because it is now conda style
@@ -696,7 +700,7 @@ UV_IN_PIPX_VENV = "/home/user/.local/pipx/venvs/nox/bin/uv"
 
 
 @pytest.mark.parametrize(
-    ["which_result", "find_uv_bin_result", "found", "path"],
+    ("which_result", "find_uv_bin_result", "found", "path"),
     [
         ("/usr/bin/uv", UV_IN_PIPX_VENV, True, UV_IN_PIPX_VENV),
         ("/usr/bin/uv", None, True, "uv"),
@@ -726,7 +730,7 @@ def test_find_uv(
 
 
 @pytest.mark.parametrize(
-    ["return_code", "stdout", "expected_result"],
+    ("return_code", "stdout", "expected_result"),
     [
         (0, '{"version": "0.2.3", "commit_info": null}', "0.2.3"),
         (1, None, "0.0"),
@@ -759,7 +763,7 @@ def test_uv_version_no_uv(monkeypatch: pytest.MonkeyPatch) -> None:
 
 
 @pytest.mark.parametrize(
-    ["requested_python", "expected_result"],
+    ("requested_python", "expected_result"),
     [
         ("3.11", True),
         ("pypy3.8", True),
@@ -849,7 +853,7 @@ def test_inner_functions_reusing_venv(
 def test_create_reuse_python2_environment(
     make_one: Callable[..., tuple[VirtualEnv, Any]],
 ) -> None:
-    venv, location = make_one(reuse_existing=True, interpreter="2.7")
+    venv, _location = make_one(reuse_existing=True, interpreter="2.7")
 
     try:
         venv.create()
@@ -864,7 +868,7 @@ def test_create_reuse_python2_environment(
 def test_create_venv_backend(
     make_one: Callable[..., tuple[VirtualEnv, Any]],
 ) -> None:
-    venv, dir_ = make_one(venv_backend="venv")
+    venv, _dir = make_one(venv_backend="venv")
     venv.create()
 
 
@@ -888,7 +892,7 @@ def test__resolved_interpreter_none(
 
 
 @pytest.mark.parametrize(
-    ["input_", "expected"],
+    ("input_", "expected"),
     [
         ("3", "python3"),
         ("3.6", "python3.6"),
@@ -967,7 +971,7 @@ def test__resolved_interpreter_windows_full_path(
 
 
 @pytest.mark.parametrize(
-    ["input_", "expected"],
+    ("input_", "expected"),
     [
         ("3.7", r"c:\python37-x64\python.exe"),
         ("python3.6", r"c:\python36-x64\python.exe"),
@@ -1021,7 +1025,7 @@ def test__resolved_interpreter_windows_pyexe_fails(
     # Trick the nox.virtualenv._SYSTEM into thinking that it cannot find python3.6
     # (it likely will on Unix). Also, when the nox.virtualenv._SYSTEM looks for the
     # py launcher, give it a dummy that fails.
-    def special_run(cmd: str, *args: str, **kwargs: object) -> TextProcessResult:
+    def special_run(cmd: str, *args: str, **kwargs: object) -> TextProcessResult:  # noqa: ARG001
         return TextProcessResult("", 1)
 
     run.side_effect = special_run
@@ -1105,7 +1109,7 @@ def test__resolved_interpreter_not_found(
 
 
 @mock.patch("nox.virtualenv._SYSTEM", new="Windows")
-@mock.patch("nox.virtualenv.locate_via_py", new=lambda _: None)  # type: ignore[misc]
+@mock.patch("nox.virtualenv.locate_via_py", new=lambda _: None)  # type: ignore[misc]  # noqa: PT008
 def test__resolved_interpreter_nonstandard(
     make_one: Callable[..., tuple[VirtualEnv, Any]],
 ) -> None: