From a98b603bd99d3aa1343df93946efafebd6764376 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Wed, 31 Jan 2024 21:12:33 +0100 Subject: [PATCH] Migrate from autoflake, black, isort, pyupgrade, flake8 and pydocstyle, to ruff ruff is faster and handle everything we had prior. isort configuration done based on the indication from https://github.com/astral-sh/ruff/issues/4670, previousely based on reorder-python-import (#11896) flake8-docstrings was a wrapper around pydocstyle (now archived) that explicitly asks to use ruff in https://github.com/PyCQA/pydocstyle/pull/658. flake8-typing-import is useful mainly for project that support python 3.7 and the one useful check will be implemented in https://github.com/astral-sh/ruff/issues/2302 We need to keep blacken-doc because ruff does not handle detection of python code inside .md and .rst. The direct link to the repo is now used to avoid a redirection. Manual fixes: - Lines that became too long - % formatting that was not done automatically - type: ignore that were moved around - noqa of hard to fix issues (UP031 generally) - fmt: off and fmt: on that is not really identical between black and ruff - autofix re-order in pre-commit from faster to slower Co-authored-by: Ran Benita --- .pre-commit-config.yaml | 46 ++------- README.rst | 3 - bench/bench.py | 1 + bench/bench_argcomplete.py | 1 + bench/skip.py | 1 + bench/unit_test.py | 1 + doc/en/conf.py | 1 + .../global_testmodule_config/conftest.py | 1 + doc/en/example/assertion/test_failures.py | 1 + doc/en/example/multipython.py | 21 ++-- doc/en/example/xfail_demo.py | 1 + extra/get_issues.py | 1 + pyproject.toml | 55 +++++++++++ scripts/generate-gh-release-notes.py | 2 +- scripts/prepare-release-pr.py | 2 +- scripts/towncrier-draft-to-file.py | 2 +- scripts/update-plugin-list.py | 7 +- src/_pytest/_argcomplete.py | 2 +- src/_pytest/_code/__init__.py | 1 + src/_pytest/_code/code.py | 56 +++++------ src/_pytest/_code/source.py | 10 +- src/_pytest/_io/__init__.py | 1 + src/_pytest/_io/pprint.py | 2 +- src/_pytest/_io/saferepr.py | 5 +- src/_pytest/_io/terminalwriter.py | 7 +- src/_pytest/_io/wcwidth.py | 2 +- src/_pytest/_py/error.py | 1 + src/_pytest/_py/path.py | 43 ++++---- src/_pytest/assertion/__init__.py | 2 +- src/_pytest/assertion/rewrite.py | 37 +++---- src/_pytest/assertion/truncate.py | 1 + src/_pytest/assertion/util.py | 7 +- src/_pytest/cacheprovider.py | 9 +- src/_pytest/capture.py | 11 +-- src/_pytest/compat.py | 9 +- src/_pytest/config/__init__.py | 26 +++-- src/_pytest/config/argparsing.py | 9 +- src/_pytest/config/compat.py | 3 +- src/_pytest/config/findpaths.py | 7 +- src/_pytest/debugging.py | 6 +- src/_pytest/deprecated.py | 1 + src/_pytest/doctest.py | 11 ++- src/_pytest/faulthandler.py | 3 +- src/_pytest/fixtures.py | 54 +++++----- src/_pytest/helpconfig.py | 8 +- src/_pytest/hookspec.py | 3 +- src/_pytest/junitxml.py | 12 +-- src/_pytest/legacypath.py | 3 +- src/_pytest/logging.py | 17 ++-- src/_pytest/main.py | 12 ++- src/_pytest/mark/__init__.py | 5 +- src/_pytest/mark/expression.py | 1 + src/_pytest/mark/structures.py | 31 +++--- src/_pytest/monkeypatch.py | 23 ++--- src/_pytest/nodes.py | 17 ++-- src/_pytest/outcomes.py | 5 +- src/_pytest/pastebin.py | 5 +- src/_pytest/pathlib.py | 25 +++-- src/_pytest/pytester.py | 50 +++++----- src/_pytest/python.py | 31 +++--- src/_pytest/python_api.py | 30 +++--- src/_pytest/recwarn.py | 17 ++-- src/_pytest/reports.py | 26 +++-- src/_pytest/runner.py | 4 +- src/_pytest/scope.py | 1 + src/_pytest/setuponly.py | 4 +- src/_pytest/setupplan.py | 2 +- src/_pytest/skipping.py | 6 +- src/_pytest/stash.py | 1 + src/_pytest/stepwise.py | 3 +- src/_pytest/terminal.py | 21 ++-- src/_pytest/threadexception.py | 2 +- src/_pytest/timing.py | 1 + src/_pytest/tmpdir.py | 6 +- src/_pytest/unittest.py | 11 ++- src/_pytest/unraisableexception.py | 2 +- src/_pytest/warning_types.py | 8 +- src/_pytest/warnings.py | 6 +- src/py.py | 1 + src/pytest/__init__.py | 1 + src/pytest/__main__.py | 1 + testing/_py/test_local.py | 6 +- testing/acceptance_test.py | 2 +- testing/code/test_code.py | 2 +- testing/code/test_excinfo.py | 25 ++--- testing/conftest.py | 3 +- testing/deprecated_test.py | 4 +- .../acceptance/fixture_mock_integration.py | 1 + .../collect_stats/generate_folders.py | 1 + .../unittest/test_unittest_asyncio.py | 1 + .../unittest/test_unittest_asynctest.py | 1 + testing/io/test_pprint.py | 4 +- testing/io/test_saferepr.py | 14 +-- testing/io/test_terminalwriter.py | 5 +- testing/io/test_wcwidth.py | 2 +- testing/logging/test_fixture.py | 3 +- testing/logging/test_reporting.py | 68 +++++-------- testing/python/approx.py | 9 +- testing/python/collect.py | 10 +- testing/python/fixtures.py | 20 ++-- testing/python/integration.py | 2 +- testing/python/metafunc.py | 15 ++- testing/python/raises.py | 2 +- testing/test_argcomplete.py | 5 +- testing/test_assertion.py | 15 +-- testing/test_assertrewrite.py | 21 ++-- testing/test_cacheprovider.py | 39 +++----- testing/test_capture.py | 61 +++++------- testing/test_collection.py | 20 ++-- testing/test_compat.py | 5 +- testing/test_config.py | 30 +++--- testing/test_conftest.py | 4 +- testing/test_debugging.py | 10 +- testing/test_doctest.py | 98 +++++++------------ testing/test_error_diffs.py | 3 +- testing/test_faulthandler.py | 2 +- testing/test_findpaths.py | 2 +- testing/test_helpconfig.py | 2 +- testing/test_junitxml.py | 48 ++++----- testing/test_legacypath.py | 2 +- testing/test_link_resolve.py | 6 +- testing/test_main.py | 18 ++-- testing/test_mark.py | 18 ++-- testing/test_mark_expression.py | 2 +- testing/test_monkeypatch.py | 4 +- testing/test_nodes.py | 7 +- testing/test_nose.py | 2 +- testing/test_parseopt.py | 12 +-- testing/test_pastebin.py | 2 +- testing/test_pathlib.py | 6 +- testing/test_pluginmanager.py | 2 +- testing/test_pytester.py | 10 +- testing/test_python_path.py | 2 +- testing/test_recwarn.py | 4 +- testing/test_reports.py | 16 ++- testing/test_runner.py | 7 +- testing/test_runner_xunit.py | 8 +- testing/test_scope.py | 2 +- testing/test_session.py | 2 +- testing/test_setuponly.py | 2 +- testing/test_skipping.py | 19 ++-- testing/test_stash.py | 2 +- testing/test_stepwise.py | 2 +- testing/test_terminal.py | 43 ++++---- testing/test_threadexception.py | 2 +- testing/test_tmpdir.py | 15 ++- testing/test_unittest.py | 38 +++---- testing/test_unraisableexception.py | 3 +- testing/test_warning_types.py | 5 +- testing/test_warnings.py | 17 ++-- tox.ini | 24 ----- 151 files changed, 789 insertions(+), 955 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f0e369d0ddd..1c29d88cc09 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,14 +1,10 @@ repos: -- repo: https://github.com/psf/black - rev: 24.1.1 - hooks: - - id: black - args: [--safe, --quiet] -- repo: https://github.com/asottile/blacken-docs - rev: 1.16.0 - hooks: - - id: blacken-docs - additional_dependencies: [black==24.1.1] +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.1.15" + hooks: + - id: ruff + args: ["--fix"] + - id: ruff-format - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: @@ -20,33 +16,11 @@ repos: - id: debug-statements exclude: _pytest/(debugging|hookspec).py language_version: python3 -- repo: https://github.com/PyCQA/autoflake - rev: v2.2.1 - hooks: - - id: autoflake - name: autoflake - args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"] - language: python - files: \.py$ -- repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - language_version: python3 - additional_dependencies: - - flake8-typing-imports==1.12.0 - - flake8-docstrings==1.5.0 -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - name: isort - args: [--force-single-line, --profile=black] -- repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 +- repo: https://github.com/adamchainz/blacken-docs + rev: 1.16.0 hooks: - - id: pyupgrade - args: [--py38-plus] + - id: blacken-docs + additional_dependencies: [black==24.1.1] - repo: https://github.com/asottile/setup-cfg-fmt rev: v2.5.0 hooks: diff --git a/README.rst b/README.rst index bbf41a18399..11c77a3d4c0 100644 --- a/README.rst +++ b/README.rst @@ -27,9 +27,6 @@ :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main :alt: pre-commit.ci status -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - .. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg :target: https://www.codetriage.com/pytest-dev/pytest diff --git a/bench/bench.py b/bench/bench.py index c314b4f56bf..91e380a80d7 100644 --- a/bench/bench.py +++ b/bench/bench.py @@ -1,5 +1,6 @@ import sys + if __name__ == "__main__": import cProfile import pstats diff --git a/bench/bench_argcomplete.py b/bench/bench_argcomplete.py index 335733df72b..459a12f9314 100644 --- a/bench/bench_argcomplete.py +++ b/bench/bench_argcomplete.py @@ -4,6 +4,7 @@ # FastFilesCompleter 0.7383 1.0760 import timeit + imports = [ "from argcomplete.completers import FilesCompleter as completer", "from _pytest._argcomplete import FastFilesCompleter as completer", diff --git a/bench/skip.py b/bench/skip.py index f0c9d1ddbef..fd5c292d92c 100644 --- a/bench/skip.py +++ b/bench/skip.py @@ -1,5 +1,6 @@ import pytest + SKIP = True diff --git a/bench/unit_test.py b/bench/unit_test.py index ad52069dbfd..d3db111e1ae 100644 --- a/bench/unit_test.py +++ b/bench/unit_test.py @@ -1,5 +1,6 @@ from unittest import TestCase # noqa: F401 + for i in range(15000): exec( f""" diff --git a/doc/en/conf.py b/doc/en/conf.py index 2fa932555e8..8059c359fc1 100644 --- a/doc/en/conf.py +++ b/doc/en/conf.py @@ -23,6 +23,7 @@ from _pytest import __version__ as version + if TYPE_CHECKING: import sphinx.application diff --git a/doc/en/example/assertion/global_testmodule_config/conftest.py b/doc/en/example/assertion/global_testmodule_config/conftest.py index 7cdf18cdbc1..4aa7ec23bd1 100644 --- a/doc/en/example/assertion/global_testmodule_config/conftest.py +++ b/doc/en/example/assertion/global_testmodule_config/conftest.py @@ -2,6 +2,7 @@ import pytest + mydir = os.path.dirname(__file__) diff --git a/doc/en/example/assertion/test_failures.py b/doc/en/example/assertion/test_failures.py index 350518b43c7..19d862f60b7 100644 --- a/doc/en/example/assertion/test_failures.py +++ b/doc/en/example/assertion/test_failures.py @@ -1,6 +1,7 @@ import os.path import shutil + failure_demo = os.path.join(os.path.dirname(__file__), "failure_demo.py") pytest_plugins = ("pytester",) diff --git a/doc/en/example/multipython.py b/doc/en/example/multipython.py index 1354cb37c45..861ae9e528d 100644 --- a/doc/en/example/multipython.py +++ b/doc/en/example/multipython.py @@ -7,6 +7,7 @@ import pytest + pythonlist = ["python3.9", "python3.10", "python3.11"] @@ -32,14 +33,12 @@ def dumps(self, obj): dumpfile = self.picklefile.with_name("dump.py") dumpfile.write_text( textwrap.dedent( - r""" + rf""" import pickle - f = open({!r}, 'wb') - s = pickle.dump({!r}, f, protocol=2) + f = open({str(self.picklefile)!r}, 'wb') + s = pickle.dump({obj!r}, f, protocol=2) f.close() - """.format( - str(self.picklefile), obj - ) + """ ) ) subprocess.run((self.pythonpath, str(dumpfile)), check=True) @@ -48,17 +47,15 @@ def load_and_is_true(self, expression): loadfile = self.picklefile.with_name("load.py") loadfile.write_text( textwrap.dedent( - r""" + rf""" import pickle - f = open({!r}, 'rb') + f = open({str(self.picklefile)!r}, 'rb') obj = pickle.load(f) f.close() - res = eval({!r}) + res = eval({expression!r}) if not res: raise SystemExit(1) - """.format( - str(self.picklefile), expression - ) + """ ) ) print(loadfile) diff --git a/doc/en/example/xfail_demo.py b/doc/en/example/xfail_demo.py index 01e6da1ad2e..1040c89298d 100644 --- a/doc/en/example/xfail_demo.py +++ b/doc/en/example/xfail_demo.py @@ -1,5 +1,6 @@ import pytest + xfail = pytest.mark.xfail diff --git a/extra/get_issues.py b/extra/get_issues.py index 4aaa3c3ec31..716233ccba1 100644 --- a/extra/get_issues.py +++ b/extra/get_issues.py @@ -3,6 +3,7 @@ import requests + issues_url = "https://api.github.com/repos/pytest-dev/pytest/issues" diff --git a/pyproject.toml b/pyproject.toml index d45597b77c8..8affd86997e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,3 +123,58 @@ target-version = ['py38'] [tool.check-wheel-contents] # W009: Wheel contains multiple toplevel library entries ignore = "W009" + +[tool.ruff] +src = ["src"] +line-length = 88 +select = [ + "D", # pydocstyle + "E", # pycodestyle + "F", # pyflakes + "I", # isort + "UP", # pyupgrade + "W", # pycodestyle +] +ignore = [ + # pycodestyle ignore + # pytest can do weird low-level things, and we usually know + # what we're doing when we use type(..) is ... + "E721", # Do not compare types, use `isinstance()` + # pydocstyle ignore + "D100", # Missing docstring in public module + "D101", # Missing docstring in public class + "D102", # Missing docstring in public method + "D103", # Missing docstring in public function + "D104", # Missing docstring in public package + "D105", # Missing docstring in magic method + "D106", # Missing docstring in public nested class + "D107", # Missing docstring in `__init__` + "D209", # [*] Multi-line docstring closing quotes should be on a separate line + "D205", # 1 blank line required between summary line and description + "D400", # First line should end with a period + "D401", # First line of docstring should be in imperative mood + "D402", # First line should not be the function's signature + "D404", # First word of the docstring should not be "This" + "D415", # First line should end with a period, question mark, or exclamation point + # Temp for backport 8.0.x + "E501", + "UP031", +] + +[tool.ruff.format] +docstring-code-format = true + +[tool.ruff.lint.pycodestyle] +# In order to be able to format for 88 char in ruff format +max-line-length = 120 + +[tool.ruff.lint.pydocstyle] +convention = "pep257" + +[tool.ruff.lint.isort] +force-single-line = true +combine-as-imports = true +force-sort-within-sections = true +order-by-type = false +known-local-folder = ["pytest", "_pytest"] +lines-after-imports = 2 diff --git a/scripts/generate-gh-release-notes.py b/scripts/generate-gh-release-notes.py index d22a5cf4c44..c27f5774b6e 100644 --- a/scripts/generate-gh-release-notes.py +++ b/scripts/generate-gh-release-notes.py @@ -8,9 +8,9 @@ Requires Python3.6+. """ +from pathlib import Path import re import sys -from pathlib import Path from typing import Sequence import pypandoc diff --git a/scripts/prepare-release-pr.py b/scripts/prepare-release-pr.py index ce8242a74a3..d2216b6fca3 100644 --- a/scripts/prepare-release-pr.py +++ b/scripts/prepare-release-pr.py @@ -14,8 +14,8 @@ `pytest bot ` commit author. """ import argparse -import re from pathlib import Path +import re from subprocess import check_call from subprocess import check_output from subprocess import run diff --git a/scripts/towncrier-draft-to-file.py b/scripts/towncrier-draft-to-file.py index 7b2748aa840..f771295a01f 100644 --- a/scripts/towncrier-draft-to-file.py +++ b/scripts/towncrier-draft-to-file.py @@ -1,6 +1,6 @@ # mypy: disallow-untyped-defs -import sys from subprocess import call +import sys def main() -> int: diff --git a/scripts/update-plugin-list.py b/scripts/update-plugin-list.py index 287073f576e..7c5ac927796 100644 --- a/scripts/update-plugin-list.py +++ b/scripts/update-plugin-list.py @@ -11,13 +11,14 @@ import packaging.version import platformdirs -import tabulate -import wcwidth from requests_cache import CachedResponse from requests_cache import CachedSession from requests_cache import OriginalResponse from requests_cache import SQLiteCache +import tabulate from tqdm import tqdm +import wcwidth + FILE_HEAD = r""" .. Note this file is autogenerated by scripts/update-plugin-list.py - usually weekly via github action @@ -85,7 +86,6 @@ def project_response_with_refresh( force refresh in case of last serial mismatch """ - response = session.get(f"https://pypi.org/pypi/{name}/json") if int(response.headers.get("X-PyPI-Last-Serial", -1)) != last_serial: response = session.get(f"https://pypi.org/pypi/{name}/json", refresh=True) @@ -184,7 +184,6 @@ def version_sort_key(version_string: str) -> Any: def plugin_definitions(plugins: Iterable[PluginInfo]) -> Iterator[str]: """Return RST for the plugin list that fits better on a vertical page.""" - for plugin in plugins: yield dedent( f""" diff --git a/src/_pytest/_argcomplete.py b/src/_pytest/_argcomplete.py index c2ec1797fbc..c24f925202a 100644 --- a/src/_pytest/_argcomplete.py +++ b/src/_pytest/_argcomplete.py @@ -63,9 +63,9 @@ """ import argparse +from glob import glob import os import sys -from glob import glob from typing import Any from typing import List from typing import Optional diff --git a/src/_pytest/_code/__init__.py b/src/_pytest/_code/__init__.py index f82c3d2b030..b0a418e9555 100644 --- a/src/_pytest/_code/__init__.py +++ b/src/_pytest/_code/__init__.py @@ -10,6 +10,7 @@ from .source import getrawcode from .source import Source + __all__ = [ "Code", "ExceptionInfo", diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index af120ff57cf..4b0a2a385e2 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -1,14 +1,14 @@ import ast import dataclasses import inspect -import os -import re -import sys -import traceback from inspect import CO_VARARGS from inspect import CO_VARKEYWORDS from io import StringIO +import os from pathlib import Path +import re +import sys +import traceback from traceback import format_exception_only from types import CodeType from types import FrameType @@ -50,6 +50,7 @@ from _pytest.pathlib import absolutepath from _pytest.pathlib import bestrelpath + if sys.version_info[:2] < (3, 11): from exceptiongroup import BaseExceptionGroup @@ -277,9 +278,9 @@ def ishidden(self, excinfo: Optional["ExceptionInfo[BaseException]"]) -> bool: 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 @@ -376,10 +377,12 @@ def cut( 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] @@ -484,9 +487,10 @@ def from_exception( .. versionadded:: 7.4 """ - assert ( - exception.__traceback__ - ), "Exceptions passed to ExcInfo.from_exception(...) must have a non-None __traceback__." + assert exception.__traceback__, ( + "Exceptions passed to ExcInfo.from_exception(...)" + " must have a non-None __traceback__." + ) exc_info = (type(exception), exception, exception.__traceback__) return cls.from_exc_info(exc_info, exprinfo) @@ -585,9 +589,7 @@ def traceback(self, value: Traceback) -> None: def __repr__(self) -> str: if self._excinfo is None: return "" - return "<{} {} tblen={}>".format( - self.__class__.__name__, saferepr(self._excinfo[1]), len(self.traceback) - ) + return f"<{self.__class__.__name__} {saferepr(self._excinfo[1])} tblen={len(self.traceback)}>" def exconly(self, tryshort: bool = False) -> str: """Return the exception as a string. @@ -1015,13 +1017,8 @@ def _truncate_recursive_traceback( extraline: Optional[str] = ( "!!! Recursion error detected, but an error occurred locating the origin of recursion.\n" " The following exception happened when comparing locals in the stack frame:\n" - " {exc_type}: {exc_msg}\n" - " Displaying first and last {max_frames} stack frames out of {total}." - ).format( - exc_type=type(e).__name__, - exc_msg=str(e), - max_frames=max_frames, - total=len(traceback), + f" {type(e).__name__}: {str(e)}\n" + f" Displaying first and last {max_frames} stack frames out of {len(traceback)}." ) # Type ignored because adding two instances of a List subtype # currently incorrectly has type List instead of the subtype. @@ -1053,13 +1050,13 @@ def repr_excinfo( # 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: @@ -1228,7 +1225,6 @@ def _write_entry_lines(self, tw: TerminalWriter) -> None: the "E" prefix) using syntax highlighting, taking care to not highlighting the ">" character, as doing so might break line continuations. """ - if not self.lines: return diff --git a/src/_pytest/_code/source.py b/src/_pytest/_code/source.py index 7c4783cb5c1..359da868c2d 100644 --- a/src/_pytest/_code/source.py +++ b/src/_pytest/_code/source.py @@ -1,10 +1,9 @@ import ast +from bisect import bisect_right import inspect import textwrap import tokenize import types -import warnings -from bisect import bisect_right from typing import Iterable from typing import Iterator from typing import List @@ -12,6 +11,7 @@ from typing import overload from typing import Tuple from typing import Union +import warnings class Source: @@ -46,10 +46,12 @@ def __eq__(self, other: object) -> bool: __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 a804cb549b4..db001e918cb 100644 --- a/src/_pytest/_io/__init__.py +++ b/src/_pytest/_io/__init__.py @@ -1,6 +1,7 @@ from .terminalwriter import get_terminal_width from .terminalwriter import TerminalWriter + __all__ = [ "TerminalWriter", "get_terminal_width", diff --git a/src/_pytest/_io/pprint.py b/src/_pytest/_io/pprint.py index 7559c6778df..61fc8ba9b24 100644 --- a/src/_pytest/_io/pprint.py +++ b/src/_pytest/_io/pprint.py @@ -14,9 +14,9 @@ # useful, thank small children who sleep at night. import collections as _collections import dataclasses as _dataclasses +from io import StringIO as _StringIO import re import types as _types -from io import StringIO as _StringIO from typing import Any from typing import Callable from typing import Dict diff --git a/src/_pytest/_io/saferepr.py b/src/_pytest/_io/saferepr.py index c51578ed488..9f33fced676 100644 --- a/src/_pytest/_io/saferepr.py +++ b/src/_pytest/_io/saferepr.py @@ -19,8 +19,8 @@ def _format_repr_exception(exc: BaseException, obj: object) -> str: raise except BaseException as exc: exc_info = f"unpresentable exception ({_try_repr_or_str(exc)})" - return "<[{} raised in repr()] {} object at 0x{:x}>".format( - exc_info, type(obj).__name__, id(obj) + return ( + f"<[{exc_info} raised in repr()] {type(obj).__name__} object at 0x{id(obj):x}>" ) @@ -108,7 +108,6 @@ def saferepr( This function is a wrapper around the Repr/reprlib functionality of the stdlib. """ - return SafeRepr(maxsize, use_ascii).repr(obj) diff --git a/src/_pytest/_io/terminalwriter.py b/src/_pytest/_io/terminalwriter.py index 89221796aea..16449b780c7 100644 --- a/src/_pytest/_io/terminalwriter.py +++ b/src/_pytest/_io/terminalwriter.py @@ -11,6 +11,7 @@ from .wcwidth import wcswidth + # This code was initially copied from py 1.8.1, file _io/terminalwriter.py. @@ -183,9 +184,7 @@ def _write_source(self, lines: Sequence[str], indents: Sequence[str] = ()) -> No """ if indents and len(indents) != len(lines): raise ValueError( - "indents size ({}) should have same size as lines ({})".format( - len(indents), len(lines) - ) + f"indents size ({len(indents)}) should have same size as lines ({len(lines)})" ) if not indents: indents = [""] * len(lines) @@ -210,8 +209,8 @@ def _highlight( from pygments.lexers.python import PythonLexer as Lexer elif lexer == "diff": from pygments.lexers.diff import DiffLexer as Lexer - import pygments.util from pygments import highlight + import pygments.util except ImportError: return source else: diff --git a/src/_pytest/_io/wcwidth.py b/src/_pytest/_io/wcwidth.py index e5c7bf4d868..53803133519 100644 --- a/src/_pytest/_io/wcwidth.py +++ b/src/_pytest/_io/wcwidth.py @@ -1,5 +1,5 @@ -import unicodedata from functools import lru_cache +import unicodedata @lru_cache(100) diff --git a/src/_pytest/_py/error.py b/src/_pytest/_py/error.py index 4b08d3b7a2e..68f1eed7ec0 100644 --- a/src/_pytest/_py/error.py +++ b/src/_pytest/_py/error.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING from typing import TypeVar + if TYPE_CHECKING: from typing_extensions import ParamSpec diff --git a/src/_pytest/_py/path.py b/src/_pytest/_py/path.py index dad1a9fd4aa..232be617ae5 100644 --- a/src/_pytest/_py/path.py +++ b/src/_pytest/_py/path.py @@ -3,15 +3,11 @@ from __future__ import annotations import atexit +from contextlib import contextmanager import fnmatch import importlib.util import io import os -import posixpath -import sys -import uuid -import warnings -from contextlib import contextmanager from os.path import abspath from os.path import dirname from os.path import exists @@ -20,18 +16,23 @@ from os.path import isfile from os.path import islink from os.path import normpath +import posixpath from stat import S_ISDIR from stat import S_ISLNK from stat import S_ISREG +import sys from typing import Any from typing import Callable from typing import cast from typing import Literal from typing import overload from typing import TYPE_CHECKING +import uuid +import warnings from . import error + # Moved from local.py. iswin32 = sys.platform == "win32" or (getattr(os, "_name", False) == "nt") @@ -204,10 +205,12 @@ 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) @@ -674,7 +677,7 @@ def new(self, **kw): else: kw.setdefault("dirname", dirname) kw.setdefault("sep", self.sep) - obj.strpath = normpath("%(dirname)s%(sep)s%(basename)s" % kw) + obj.strpath = normpath("{dirname}{sep}{basename}".format(**kw)) return obj def _getbyspec(self, spec: str) -> list[str]: @@ -759,7 +762,10 @@ def open(self, mode="r", ensure=False, encoding=None): # expected "Callable[[str, Any, Any], TextIOWrapper]" [arg-type] # Which seems incorrect, given io.open supports the given argument types. return error.checked_call( - io.open, self.strpath, mode, encoding=encoding # type:ignore[arg-type] + io.open, + self.strpath, + mode, + encoding=encoding, # type:ignore[arg-type] ) return error.checked_call(open, self.strpath, mode) @@ -778,11 +784,11 @@ def check(self, **kw): valid checkers:: - file=1 # is a file - file=0 # is not a file (may not even exist) - dir=1 # is a dir - link=1 # is a link - exists=1 # exists + file = 1 # is a file + file = 0 # is not a file (may not even exist) + dir = 1 # is a dir + link = 1 # is a link + exists = 1 # exists You can specify multiple checker definitions, for example:: @@ -960,10 +966,12 @@ def ensure(self, *args, **kwargs): 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.""" @@ -1275,7 +1283,8 @@ def mkdtemp(cls, rootdir=None): # error: Argument 1 has incompatible type overloaded function; expected "Callable[[str], str]" [arg-type] # Which seems incorrect, given tempfile.mkdtemp supports the given argument types. path = error.checked_call( - tempfile.mkdtemp, dir=str(rootdir) # type:ignore[arg-type] + tempfile.mkdtemp, + dir=str(rootdir), # type:ignore[arg-type] ) return cls(path) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 107d40b35eb..2bce0ec7cb5 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -16,6 +16,7 @@ from _pytest.config.argparsing import Parser from _pytest.nodes import Item + if TYPE_CHECKING: from _pytest.main import Session @@ -129,7 +130,6 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]: reporting via the pytest_assertrepr_compare hook. This sets up this custom comparison for the test. """ - ihook = item.ihook def callbinrepr(op, left: object, right: object) -> Optional[str]: diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index c24263e0663..0ab6eaa1393 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -1,6 +1,7 @@ """Rewrite assertion AST to produce nice error messages.""" import ast +from collections import defaultdict import errno import functools import importlib.abc @@ -10,13 +11,12 @@ import itertools import marshal import os +from pathlib import Path +from pathlib import PurePath import struct import sys import tokenize import types -from collections import defaultdict -from pathlib import Path -from pathlib import PurePath from typing import Callable from typing import Dict from typing import IO @@ -40,6 +40,7 @@ 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 @@ -671,9 +672,9 @@ def __init__( 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.""" @@ -1019,9 +1020,7 @@ def visit_BoolOp(self, boolop: ast.BoolOp) -> Tuple[ast.Name, str]: ] ): pytest_temp = self.variable() - self.variables_overwrite[self.scope][ - v.left.target.id - ] = v.left # type:ignore[assignment] + self.variables_overwrite[self.scope][v.left.target.id] = v.left # type:ignore[assignment] v.left.target.id = pytest_temp self.push_format_context() res, expl = self.visit(v) @@ -1065,9 +1064,7 @@ def visit_Call(self, call: ast.Call) -> Tuple[ast.Name, str]: if isinstance(arg, ast.Name) and arg.id in self.variables_overwrite.get( self.scope, {} ): - arg = self.variables_overwrite[self.scope][ - arg.id - ] # type:ignore[assignment] + arg = self.variables_overwrite[self.scope][arg.id] # type:ignore[assignment] res, expl = self.visit(arg) arg_expls.append(expl) new_args.append(res) @@ -1075,9 +1072,7 @@ def visit_Call(self, call: ast.Call) -> Tuple[ast.Name, str]: if isinstance( keyword.value, ast.Name ) and keyword.value.id in self.variables_overwrite.get(self.scope, {}): - keyword.value = self.variables_overwrite[self.scope][ - keyword.value.id - ] # type:ignore[assignment] + keyword.value = self.variables_overwrite[self.scope][keyword.value.id] # type:ignore[assignment] res, expl = self.visit(keyword.value) new_kwargs.append(ast.keyword(keyword.arg, res)) if keyword.arg: @@ -1114,13 +1109,9 @@ def visit_Compare(self, comp: ast.Compare) -> Tuple[ast.expr, str]: if isinstance( comp.left, ast.Name ) and comp.left.id in self.variables_overwrite.get(self.scope, {}): - comp.left = self.variables_overwrite[self.scope][ - comp.left.id - ] # type:ignore[assignment] + comp.left = self.variables_overwrite[self.scope][comp.left.id] # type:ignore[assignment] if isinstance(comp.left, ast.NamedExpr): - self.variables_overwrite[self.scope][ - comp.left.target.id - ] = comp.left # type:ignore[assignment] + self.variables_overwrite[self.scope][comp.left.target.id] = comp.left # type:ignore[assignment] left_res, left_expl = self.visit(comp.left) if isinstance(comp.left, (ast.Compare, ast.BoolOp)): left_expl = f"({left_expl})" @@ -1138,9 +1129,7 @@ def visit_Compare(self, comp: ast.Compare) -> Tuple[ast.expr, str]: and next_operand.target.id == left_res.id ): next_operand.target.id = self.variable() - self.variables_overwrite[self.scope][ - left_res.id - ] = next_operand # type:ignore[assignment] + self.variables_overwrite[self.scope][left_res.id] = next_operand # type:ignore[assignment] next_res, next_expl = self.visit(next_operand) if isinstance(next_operand, (ast.Compare, ast.BoolOp)): next_expl = f"({next_expl})" diff --git a/src/_pytest/assertion/truncate.py b/src/_pytest/assertion/truncate.py index 1e586567240..902d4baf846 100644 --- a/src/_pytest/assertion/truncate.py +++ b/src/_pytest/assertion/truncate.py @@ -11,6 +11,7 @@ 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/assertion/util.py b/src/_pytest/assertion/util.py index 2e4ba108a04..a7074115d65 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -15,13 +15,14 @@ from typing import Sequence from unicodedata import normalize -import _pytest._code from _pytest import outcomes +import _pytest._code from _pytest._io.pprint import PrettyPrinter from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr_unlimited from _pytest.config import Config + # The _reprcompare attribute on the util module is used by the new assertion # interpretation code and assertion rewriter to detect this plugin was # loaded and in turn call the hooks defined here as part of the @@ -302,8 +303,8 @@ def _diff_text(left: str, right: str, verbose: int = 0) -> List[str]: if i > 42: i -= 10 # Provide some context explanation += [ - "Skipping {} identical trailing " - "characters in diff, use -v to show".format(i) + f"Skipping {i} identical trailing " + "characters in diff, use -v to show" ] left = left[:-i] right = right[:-i] diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py index e6350836901..49e38ed533f 100755 --- a/src/_pytest/cacheprovider.py +++ b/src/_pytest/cacheprovider.py @@ -32,6 +32,7 @@ from _pytest.nodes import File from _pytest.reports import TestReport + README_CONTENT = """\ # pytest cache directory # @@ -368,15 +369,13 @@ def pytest_collection_modifyitems( noun = "failure" if self._previously_failed_count == 1 else "failures" suffix = " first" if self.config.getoption("failedfirst") else "" - self._report_status = "rerun previous {count} {noun}{suffix}".format( - count=self._previously_failed_count, suffix=suffix, noun=noun + self._report_status = ( + f"rerun previous {self._previously_failed_count} {noun}{suffix}" ) if self._skipped_files > 0: files_noun = "file" if self._skipped_files == 1 else "files" - self._report_status += " (skipped {files} {files_noun})".format( - files=self._skipped_files, files_noun=files_noun - ) + self._report_status += f" (skipped {self._skipped_files} {files_noun})" else: self._report_status = "no previously failed tests, " if self.config.getoption("last_failed_no_failures") == "none": diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 6e3f3833d59..d4cabedba29 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -4,9 +4,9 @@ import collections import contextlib import io +from io import UnsupportedOperation import os import sys -from io import UnsupportedOperation from tempfile import TemporaryFile from types import TracebackType from typing import Any @@ -39,6 +39,7 @@ from _pytest.nodes import Item from _pytest.reports import CollectReport + _CaptureMethod = Literal["fd", "sys", "no", "tee-sys"] @@ -790,9 +791,7 @@ def set_fixture(self, capture_fixture: "CaptureFixture[Any]") -> None: current_fixture = self._capture_fixture.request.fixturename requested_fixture = capture_fixture.request.fixturename capture_fixture.request.raiseerror( - "cannot use {} and {} at the same time".format( - requested_fixture, current_fixture - ) + f"cannot use {requested_fixture} and {current_fixture} at the same time" ) self._capture_fixture = capture_fixture @@ -988,7 +987,6 @@ def capsys(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: Returns an instance of :class:`CaptureFixture[str] `. Example: - .. code-block:: python def test_output(capsys): @@ -1016,7 +1014,6 @@ def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, Returns an instance of :class:`CaptureFixture[bytes] `. Example: - .. code-block:: python def test_output(capsysbinary): @@ -1044,7 +1041,6 @@ def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: Returns an instance of :class:`CaptureFixture[str] `. Example: - .. code-block:: python def test_system_echo(capfd): @@ -1072,7 +1068,6 @@ def capfdbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, N Returns an instance of :class:`CaptureFixture[bytes] `. Example: - .. code-block:: python def test_system_echo(capfdbinary): diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index d11a5f5e5cc..c0fb229c297 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -6,11 +6,11 @@ import enum import functools import inspect -import os -import sys from inspect import Parameter from inspect import signature +import os from pathlib import Path +import sys from typing import Any from typing import Callable from typing import Final @@ -19,6 +19,7 @@ import py + _T = TypeVar("_T") _S = TypeVar("_S") @@ -258,9 +259,7 @@ def get_real_func(obj): from _pytest._io.saferepr import saferepr raise ValueError( - ("could not find real function of {start}\nstopped at {current}").format( - start=saferepr(start_obj), current=saferepr(obj) - ) + f"could not find real function of {saferepr(start_obj)}\nstopped at {saferepr(obj)}" ) if isinstance(obj, functools.partial): obj = obj.func diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index bcc48bdc655..d0afa356324 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -5,18 +5,17 @@ import copy import dataclasses import enum +from functools import lru_cache import glob import importlib.metadata import inspect import os +from pathlib import Path import re import shlex import sys -import types -import warnings -from functools import lru_cache -from pathlib import Path from textwrap import dedent +import types from types import FunctionType from types import TracebackType from typing import Any @@ -38,6 +37,7 @@ from typing import Type from typing import TYPE_CHECKING from typing import Union +import warnings import pluggy from pluggy import HookimplMarker @@ -46,16 +46,16 @@ from pluggy import HookspecOpts from pluggy import PluginManager -import _pytest._code -import _pytest.deprecated -import _pytest.hookspec from .compat import PathAwareHookProxy from .exceptions import PrintHelp as PrintHelp from .exceptions import UsageError as UsageError from .findpaths import determine_setup +import _pytest._code from _pytest._code import ExceptionInfo from _pytest._code import filter_traceback from _pytest._io import TerminalWriter +import _pytest.deprecated +import _pytest.hookspec from _pytest.outcomes import fail from _pytest.outcomes import Skipped from _pytest.pathlib import absolutepath @@ -68,6 +68,7 @@ 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 @@ -123,9 +124,7 @@ def __init__( self.excinfo = excinfo def __str__(self) -> str: - return "{}: {} (from {})".format( - self.excinfo[0].__name__, self.excinfo[1], self.path - ) + return f"{self.excinfo[0].__name__}: {self.excinfo[1]} (from {self.path})" def filter_traceback_for_conftest_import_failure( @@ -814,7 +813,7 @@ def import_plugin(self, modname: str, consider_entry_points: bool = False) -> No def _get_plugin_specs_as_list( - specs: Union[None, types.ModuleType, str, Sequence[str]] + specs: Union[None, types.ModuleType, str, Sequence[str]], ) -> List[str]: """Parse a plugins specification into a list of plugin names.""" # None means empty. @@ -1626,9 +1625,7 @@ def _get_override_ini_value(self, name: str) -> Optional[str]: key, user_ini_value = ini_config.split("=", 1) except ValueError as e: raise UsageError( - "-o/--override-ini expects option=value style (got: {!r}).".format( - ini_config - ) + f"-o/--override-ini expects option=value style (got: {ini_config!r})." ) from e else: if key == name: @@ -1686,7 +1683,6 @@ def get_verbosity(self, verbosity_type: Optional[str] = None) -> int: can be used to explicitly use the global verbosity level. Example: - .. code-block:: ini # content of pytest.ini diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index 331abb85d00..0f91dc0fe91 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -1,8 +1,7 @@ import argparse +from gettext import gettext import os import sys -import warnings -from gettext import gettext from typing import Any from typing import Callable from typing import cast @@ -16,6 +15,7 @@ from typing import Sequence from typing import Tuple from typing import Union +import warnings import _pytest._io from _pytest.config.exceptions import UsageError @@ -24,6 +24,7 @@ from _pytest.deprecated import ARGUMENT_TYPE_STR_CHOICE from _pytest.deprecated import check_ispytest + FILE_OR_DIR = "file_or_dir" @@ -219,7 +220,7 @@ def addini( def get_ini_default_for_type( - type: Optional[Literal["string", "paths", "pathlist", "args", "linelist", "bool"]] + type: Optional[Literal["string", "paths", "pathlist", "args", "linelist", "bool"]], ) -> Any: """ Used by addini to get the default value for a given ini-option type, when @@ -480,7 +481,7 @@ def _parse_optional( ) -> Optional[Tuple[Optional[argparse.Action], str, Optional[str]]]: if not arg_string: return None - if not arg_string[0] in self.prefix_chars: + if arg_string[0] not in self.prefix_chars: return None if arg_string in self._option_string_actions: action = self._option_string_actions[arg_string] diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py index afb38bbcc62..65e46c3679a 100644 --- a/src/_pytest/config/compat.py +++ b/src/_pytest/config/compat.py @@ -1,9 +1,9 @@ from __future__ import annotations import functools -import warnings from pathlib import Path from typing import Mapping +import warnings import pluggy @@ -11,6 +11,7 @@ from ..compat import legacy_path from ..deprecated import HOOK_LEGACY_PATH_ARG + # hookname: (Path, LEGACY_PATH) imply_paths_hooks: Mapping[str, tuple[str, str]] = { "pytest_ignore_collect": ("collection_path", "path"), diff --git a/src/_pytest/config/findpaths.py b/src/_pytest/config/findpaths.py index fc30533b6e4..0151014c4f4 100644 --- a/src/_pytest/config/findpaths.py +++ b/src/_pytest/config/findpaths.py @@ -1,6 +1,6 @@ import os -import sys from pathlib import Path +import sys from typing import Dict from typing import Iterable from typing import List @@ -37,7 +37,6 @@ def load_config_dict_from_file( Return None if the file does not contain valid pytest configuration. """ - # Configuration from ini files are obtained from the [pytest] section, if present. if filepath.suffix == ".ini": iniconfig = _parse_ini_config(filepath) @@ -211,9 +210,7 @@ def determine_setup( rootdir = absolutepath(os.path.expandvars(rootdir_cmd_arg)) if not rootdir.is_dir(): raise UsageError( - "Directory '{}' not found. Check your '--rootdir' option.".format( - rootdir - ) + f"Directory '{rootdir}' not found. Check your '--rootdir' option." ) assert rootdir is not None return rootdir, inipath, inicfg or {} diff --git a/src/_pytest/debugging.py b/src/_pytest/debugging.py index dcc82a07856..dc402accccf 100644 --- a/src/_pytest/debugging.py +++ b/src/_pytest/debugging.py @@ -4,7 +4,6 @@ import functools import sys import types -import unittest from typing import Any from typing import Callable from typing import Generator @@ -14,6 +13,7 @@ from typing import Type from typing import TYPE_CHECKING from typing import Union +import unittest from _pytest import outcomes from _pytest._code import ExceptionInfo @@ -26,6 +26,7 @@ from _pytest.nodes import Node from _pytest.reports import BaseReport + if TYPE_CHECKING: from _pytest.capture import CaptureManager from _pytest.runner import CallInfo @@ -264,8 +265,7 @@ def _init_pdb(cls, method, *args, **kwargs): elif capturing: tw.sep( ">", - "PDB %s (IO-capturing turned off for %s)" - % (method, capturing), + f"PDB {method} (IO-capturing turned off for {capturing})", ) else: tw.sep(">", f"PDB {method}") diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 900b59206cb..76170c8c0e8 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -16,6 +16,7 @@ from _pytest.warning_types import PytestRemovedIn9Warning from _pytest.warning_types import UnformattedWarning + # set of plugins which have been integrated into the core; we use this list to ignore # them during registration to avoid conflicts DEPRECATED_EXTERNAL_PLUGINS = { diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index ef24bfbd9a2..61f13834c46 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -1,16 +1,15 @@ """Discover and run doctests in modules and test files.""" import bdb +from contextlib import contextmanager import functools import inspect import os +from pathlib import Path import platform import sys import traceback import types -import warnings -from contextlib import contextmanager -from pathlib import Path from typing import Any from typing import Callable from typing import Dict @@ -24,6 +23,7 @@ from typing import Type from typing import TYPE_CHECKING from typing import Union +import warnings from _pytest import outcomes from _pytest._code.code import ExceptionInfo @@ -45,6 +45,7 @@ from _pytest.python_api import approx from _pytest.warning_types import PytestWarning + if TYPE_CHECKING: import doctest @@ -486,9 +487,9 @@ def _mock_aware_unwrap( return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func)) except Exception as e: warnings.warn( - "Got %r when unwrapping %r. This is usually caused " + f"Got {e!r} when unwrapping {func!r}. This is usually caused " "by a violation of Python's object protocol; see e.g. " - "https://github.com/pytest-dev/pytest/issues/5080" % (e, func), + "https://github.com/pytest-dev/pytest/issues/5080", PytestWarning, ) raise diff --git a/src/_pytest/faulthandler.py b/src/_pytest/faulthandler.py index 824aec58eea..083bcb83739 100644 --- a/src/_pytest/faulthandler.py +++ b/src/_pytest/faulthandler.py @@ -2,11 +2,12 @@ import sys from typing import Generator -import pytest from _pytest.config import Config from _pytest.config.argparsing import Parser from _pytest.nodes import Item from _pytest.stash import StashKey +import pytest + 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 8f61838d4d6..dabdf0e4283 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -1,12 +1,11 @@ import abc +from collections import defaultdict +from collections import deque +from contextlib import suppress import dataclasses import functools import inspect import os -import warnings -from collections import defaultdict -from collections import deque -from contextlib import suppress from pathlib import Path from typing import AbstractSet from typing import Any @@ -30,6 +29,7 @@ from typing import TYPE_CHECKING from typing import TypeVar from typing import Union +import warnings import _pytest from _pytest import nodes @@ -66,6 +66,7 @@ from _pytest.scope import HIGH_SCOPES from _pytest.scope import Scope + if TYPE_CHECKING: from typing import Deque @@ -606,13 +607,9 @@ def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None: fixtures_not_supported = getattr(funcitem, "nofuncargs", False) if has_params and fixtures_not_supported: msg = ( - "{name} does not support fixtures, maybe unittest.TestCase subclass?\n" - "Node id: {nodeid}\n" - "Function type: {typename}" - ).format( - name=funcitem.name, - nodeid=funcitem.nodeid, - typename=type(funcitem).__name__, + f"{funcitem.name} does not support fixtures, maybe unittest.TestCase subclass?\n" + f"Node id: {funcitem.nodeid}\n" + f"Function type: {type(funcitem).__name__}" ) fail(msg, pytrace=False) if has_params: @@ -745,9 +742,7 @@ def node(self): if node is None and scope is Scope.Class: # Fallback to function item itself. node = self._pyfuncitem - assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format( - scope, self._pyfuncitem - ) + assert node, f'Could not obtain a node for scope "{scope}" for function {self._pyfuncitem!r}' return node def _check_scope( @@ -851,8 +846,8 @@ def formatrepr(self) -> "FixtureLookupErrorRepr": if faclist: available.add(name) if self.argname in available: - msg = " recursive dependency involving fixture '{}' detected".format( - self.argname + msg = ( + f" recursive dependency involving fixture '{self.argname}' detected" ) else: msg = f"fixture '{self.argname}' not found" @@ -946,15 +941,13 @@ def _eval_scope_callable( result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg] except Exception as e: raise TypeError( - "Error evaluating {} while defining fixture '{}'.\n" - "Expected a function with the signature (*, fixture_name, config)".format( - scope_callable, fixture_name - ) + f"Error evaluating {scope_callable} while defining fixture '{fixture_name}'.\n" + "Expected a function with the signature (*, fixture_name, config)" ) from e if not isinstance(result, str): fail( - "Expected {} to return a 'str' while defining fixture '{}', but it returned:\n" - "{!r}".format(scope_callable, fixture_name, result), + f"Expected {scope_callable} to return a 'str' while defining fixture '{fixture_name}', but it returned:\n" + f"{result!r}", pytrace=False, ) return result @@ -1098,9 +1091,7 @@ def cache_key(self, request: SubRequest) -> object: return request.param_index if not hasattr(request, "param") else request.param def __repr__(self) -> str: - return "".format( - self.argname, self.scope, self.baseid - ) + return f"" def resolve_fixture_function( @@ -1121,7 +1112,8 @@ def resolve_fixture_function( # Handle the case where fixture is defined not in a test class, but some other class # (for example a plugin class with a fixture), see #2270. if hasattr(fixturefunc, "__self__") and not isinstance( - request.instance, fixturefunc.__self__.__class__ # type: ignore[union-attr] + request.instance, + fixturefunc.__self__.__class__, # type: ignore[union-attr] ): return fixturefunc fixturefunc = getimfunc(fixturedef.func) @@ -1216,9 +1208,7 @@ def __call__(self, function: FixtureFunction) -> FixtureFunction: if name == "request": location = getlocation(function) fail( - "'request' is a reserved word for fixtures, use another name:\n {}".format( - location - ), + f"'request' is a reserved word for fixtures, use another name:\n {location}", pytrace=False, ) @@ -1238,7 +1228,8 @@ def fixture( Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] ] = ..., name: Optional[str] = ..., -) -> FixtureFunction: ... +) -> FixtureFunction: + ... @overload @@ -1252,7 +1243,8 @@ 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/helpconfig.py b/src/_pytest/helpconfig.py index f0a7eda8c02..d61c5942b5a 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -1,19 +1,19 @@ """Version info, help messages, tracing configuration.""" +from argparse import Action import os import sys -from argparse import Action from typing import Generator from typing import List from typing import Optional from typing import Union -import pytest from _pytest.config import Config from _pytest.config import ExitCode from _pytest.config import PrintHelp from _pytest.config.argparsing import Parser from _pytest.terminal import TerminalReporter +import pytest class HelpAction(Action): @@ -136,9 +136,7 @@ def unset_tracing() -> None: def showversion(config: Config) -> None: if config.option.version > 1: sys.stdout.write( - "This is pytest version {}, imported from {}\n".format( - pytest.__version__, pytest.__file__ - ) + f"This is pytest version {pytest.__version__}, imported from {pytest.__file__}\n" ) plugininfo = getpluginversioninfo(config) if plugininfo: diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index 976efa7a264..cccd86d26c8 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -16,10 +16,11 @@ from _pytest.deprecated import WARNING_CMDLINE_PREPARSE_HOOK + if TYPE_CHECKING: import pdb - import warnings from typing import Literal + import warnings from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionRepr diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 9bc24b12bcb..9009ec7aa0a 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -7,12 +7,11 @@ https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd """ +from datetime import datetime import functools import os import platform import re -import xml.etree.ElementTree as ET -from datetime import datetime from typing import Callable from typing import Dict from typing import List @@ -20,8 +19,8 @@ from typing import Optional from typing import Tuple from typing import Union +import xml.etree.ElementTree as ET -import pytest from _pytest import nodes from _pytest import timing from _pytest._code.code import ExceptionRepr @@ -33,6 +32,8 @@ from _pytest.reports import TestReport from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter +import pytest + xml_key = StashKey["LogXML"]() @@ -273,9 +274,7 @@ def _warn_incompatibility_with_xunit2( if xml is not None and xml.family not in ("xunit1", "legacy"): request.node.warn( PytestWarning( - "{fixture_name} is incompatible with junit_family '{family}' (use 'legacy' or 'xunit1')".format( - fixture_name=fixture_name, family=xml.family - ) + f"{fixture_name} is incompatible with junit_family '{xml.family}' (use 'legacy' or 'xunit1')" ) ) @@ -367,7 +366,6 @@ def test_foo(record_testsuite_property): `pytest-xdist `__ plugin. See :issue:`7767` for details. """ - __tracebackhide__ = True def record_func(name: str, value: object) -> None: diff --git a/src/_pytest/legacypath.py b/src/_pytest/legacypath.py index f0b9e933941..c459c59aac3 100644 --- a/src/_pytest/legacypath.py +++ b/src/_pytest/legacypath.py @@ -1,9 +1,9 @@ """Add backward compatibility support for the legacy py path type.""" import dataclasses +from pathlib import Path import shlex import subprocess -from pathlib import Path from typing import Final from typing import final from typing import List @@ -33,6 +33,7 @@ from _pytest.terminal import TerminalReporter from _pytest.tmpdir import TempPathFactory + if TYPE_CHECKING: import pexpect diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 39e10132551..ad7c2dfff42 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -1,17 +1,17 @@ """Access and control log capturing.""" -import io -import logging -import os -import re from contextlib import contextmanager from contextlib import nullcontext from datetime import datetime from datetime import timedelta from datetime import timezone +import io from io import StringIO +import logging from logging import LogRecord +import os from pathlib import Path +import re from types import TracebackType from typing import AbstractSet from typing import Dict @@ -44,6 +44,7 @@ from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter + if TYPE_CHECKING: logging_StreamHandler = logging.StreamHandler[StringIO] else: @@ -116,7 +117,6 @@ def add_color_level(self, level: int, *color_opts: str) -> None: .. warning:: This is an experimental API. """ - assert self._fmt is not None levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt) if not levelname_fmt_match: @@ -183,7 +183,6 @@ def _get_auto_indent(auto_indent_option: Union[int, str, bool, None]) -> int: 0 (auto-indent turned off) or >0 (explicitly set indentation position). """ - if auto_indent_option is None: return 0 elif isinstance(auto_indent_option, bool): @@ -625,9 +624,9 @@ def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[i except ValueError as e: # Python logging does not recognise this as a logging level raise UsageError( - "'{}' is not recognized as a logging level name for " - "'{}'. Please consider passing the " - "logging level num instead.".format(log_level, setting_name) + f"'{log_level}' is not recognized as a logging level name for " + f"'{setting_name}'. Please consider passing the " + "logging level num instead." ) from e diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 7c801ff53a8..0a0df070f9c 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -6,9 +6,8 @@ import functools import importlib import os -import sys -import warnings from pathlib import Path +import sys from typing import AbstractSet from typing import Callable from typing import Dict @@ -23,11 +22,12 @@ from typing import Sequence from typing import Tuple from typing import Union +import warnings import pluggy -import _pytest._code from _pytest import nodes +import _pytest._code from _pytest.config import Config from _pytest.config import directory_arg from _pytest.config import ExitCode @@ -723,12 +723,14 @@ def _collect_path( @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 41c2808540b..4bd9f6563c7 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -24,6 +24,7 @@ from _pytest.config.argparsing import Parser from _pytest.stash import StashKey + if TYPE_CHECKING: from _pytest.nodes import Item @@ -268,8 +269,8 @@ def pytest_configure(config: Config) -> None: if empty_parameterset not in ("skip", "xfail", "fail_at_collect", None, ""): raise UsageError( - "{!s} must be one of skip, xfail or fail_at_collect" - " but it is {!r}".format(EMPTY_PARAMETERSET_OPTION, empty_parameterset) + f"{EMPTY_PARAMETERSET_OPTION!s} must be one of skip, xfail or fail_at_collect" + f" but it is {empty_parameterset!r}" ) diff --git a/src/_pytest/mark/expression.py b/src/_pytest/mark/expression.py index 5fa0ccaa7b5..78b7fda696b 100644 --- a/src/_pytest/mark/expression.py +++ b/src/_pytest/mark/expression.py @@ -27,6 +27,7 @@ from typing import Optional from typing import Sequence + __all__ = [ "Expression", "ParseError", diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index b0517fb73dd..679c0fa3bfe 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -1,7 +1,6 @@ import collections.abc import dataclasses import inspect -import warnings from typing import Any from typing import Callable from typing import Collection @@ -21,6 +20,7 @@ from typing import TYPE_CHECKING from typing import TypeVar from typing import Union +import warnings from .._code import getfslineno from ..compat import ascii_escaped @@ -32,6 +32,7 @@ from _pytest.outcomes import fail from _pytest.warning_types import PytestUnknownMarkWarning + if TYPE_CHECKING: from ..nodes import Node @@ -111,7 +112,6 @@ def extract_from( Enforce tuple wrapping so single argument tuple values don't get decomposed and break tests. """ - if isinstance(parameterset, cls): return parameterset if force_tuple: @@ -271,8 +271,8 @@ class MarkDecorator: ``MarkDecorators`` are created with ``pytest.mark``:: - mark1 = pytest.mark.NAME # Simple MarkDecorator - mark2 = pytest.mark.NAME(name1=value) # Parametrized MarkDecorator + mark1 = pytest.mark.NAME # Simple MarkDecorator + mark2 = pytest.mark.NAME(name1=value) # Parametrized MarkDecorator and can then be applied as decorators to test functions:: @@ -393,7 +393,7 @@ def get_unpacked_marks( def normalize_mark_list( - mark_list: Iterable[Union[Mark, MarkDecorator]] + mark_list: Iterable[Union[Mark, MarkDecorator]], ) -> Iterable[Mark]: """ Normalize an iterable of Mark or MarkDecorator objects into a list of marks @@ -433,10 +433,12 @@ def store_mark(obj, mark: Mark) -> None: 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] @@ -444,11 +446,13 @@ def __call__( # type: ignore[override] 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__( @@ -461,7 +465,8 @@ def __call__( None, Type[BaseException], Tuple[Type[BaseException], ...] ] = ..., strict: bool = ..., - ) -> MarkDecorator: ... + ) -> MarkDecorator: + ... class _ParametrizeMarkDecorator(MarkDecorator): def __call__( # type: ignore[override] @@ -477,7 +482,8 @@ def __call__( # type: ignore[override] ] ] = ..., scope: Optional[_ScopeName] = ..., - ) -> MarkDecorator: ... + ) -> MarkDecorator: + ... class _UsefixturesMarkDecorator(MarkDecorator): def __call__(self, *fixtures: str) -> MarkDecorator: # type: ignore[override] @@ -497,9 +503,10 @@ class MarkGenerator: import pytest + @pytest.mark.slowtest def test_function(): - pass + pass applies a 'slowtest' :class:`Mark` on ``test_function``. """ diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py index ab172da45fc..3e5ec3d21dd 100644 --- a/src/_pytest/monkeypatch.py +++ b/src/_pytest/monkeypatch.py @@ -1,10 +1,9 @@ """Monkeypatching and mocking functionality.""" +from contextlib import contextmanager import os import re import sys -import warnings -from contextlib import contextmanager from typing import Any from typing import final from typing import Generator @@ -16,10 +15,12 @@ from typing import Tuple from typing import TypeVar from typing import Union +import warnings from _pytest.fixtures import fixture from _pytest.warning_types import PytestWarning + RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$") @@ -90,9 +91,7 @@ def annotated_getattr(obj: object, name: str, ann: str) -> object: obj = getattr(obj, name) except AttributeError as e: raise AttributeError( - "{!r} object at {} has no attribute {!r}".format( - type(obj).__name__, ann, name - ) + f"{type(obj).__name__!r} object at {ann} has no attribute {name!r}" ) from e return obj @@ -142,7 +141,6 @@ def context(cls) -> Generator["MonkeyPatch", None, None]: which undoes any patching done inside the ``with`` block upon exit. Example: - .. code-block:: python import functools @@ -169,7 +167,8 @@ def setattr( name: object, value: Notset = ..., raising: bool = ..., - ) -> None: ... + ) -> None: + ... @overload def setattr( @@ -178,7 +177,8 @@ def setattr( name: str, value: object, raising: bool = ..., - ) -> None: ... + ) -> None: + ... def setattr( self, @@ -320,10 +320,8 @@ def setenv(self, name: str, value: str, prepend: Optional[str] = None) -> None: if not isinstance(value, str): warnings.warn( # type: ignore[unreachable] PytestWarning( - "Value of environment variable {name} type should be str, but got " - "{value!r} (type: {type}); converted to str implicitly".format( - name=name, value=value, type=type(value).__name__ - ) + f"Value of environment variable {name} type should be str, but got " + f"{value!r} (type: {type(value).__name__}); converted to str implicitly" ), stacklevel=2, ) @@ -343,7 +341,6 @@ def delenv(self, name: str, raising: bool = True) -> None: def syspath_prepend(self, path) -> None: """Prepend ``path`` to ``sys.path`` list of import locations.""" - if self._savesyspath is None: self._savesyspath = sys.path[:] sys.path.insert(0, str(path)) diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index ac78761802d..73efe156e2f 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -1,9 +1,8 @@ import abc -import os -import pathlib -import warnings from functools import cached_property from inspect import signature +import os +import pathlib from pathlib import Path from typing import Any from typing import Callable @@ -20,6 +19,7 @@ from typing import TYPE_CHECKING from typing import TypeVar from typing import Union +import warnings import pluggy @@ -43,6 +43,7 @@ from _pytest.stash import Stash from _pytest.warning_types import PytestWarning + if TYPE_CHECKING: # Imported here due to circular import. from _pytest._code.code import _TracebackStyle @@ -306,9 +307,7 @@ def warn(self, warning: Warning) -> None: # enforce type checks here to avoid getting a generic type error later otherwise. if not isinstance(warning, Warning): raise ValueError( - "warning must be an instance of Warning or subclass, got {!r}".format( - warning - ) + f"warning must be an instance of Warning or subclass, got {warning!r}" ) path, lineno = get_fslocation_from_item(self) assert lineno is not None @@ -395,10 +394,12 @@ def iter_markers_with_node( 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 a2093b91d77..afdefa2a1b0 100644 --- a/src/_pytest/outcomes.py +++ b/src/_pytest/outcomes.py @@ -2,7 +2,6 @@ functions creating them.""" import sys -import warnings from typing import Any from typing import Callable from typing import cast @@ -11,6 +10,7 @@ from typing import Protocol from typing import Type from typing import TypeVar +import warnings from _pytest.deprecated import KEYWORD_MSG_ARG @@ -297,8 +297,7 @@ def importorskip( if verattr is None or Version(verattr) < Version(minversion): raise Skipped( - "module %r has __version__ %r, required is: %r" - % (modname, verattr, minversion), + f"module {modname!r} has __version__ {verattr!r}, required is: {minversion!r}", allow_module_level=True, ) return mod diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py index 46844cbafa2..06b1f9ca99d 100644 --- a/src/_pytest/pastebin.py +++ b/src/_pytest/pastebin.py @@ -1,16 +1,17 @@ """Submit failure or test session information to a pastebin service.""" -import tempfile from io import StringIO +import tempfile from typing import IO from typing import Union -import pytest from _pytest.config import Config from _pytest.config import create_terminal_writer from _pytest.config.argparsing import Parser from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter +import pytest + pastebinfile_key = StashKey[IO[bytes]]() diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py index 4cd635ed7e1..afe880944f0 100644 --- a/src/_pytest/pathlib.py +++ b/src/_pytest/pathlib.py @@ -1,20 +1,15 @@ import atexit import contextlib -import fnmatch -import importlib.util -import itertools -import os -import shutil -import sys -import types -import uuid -import warnings from enum import Enum from errno import EBADF from errno import ELOOP from errno import ENOENT from errno import ENOTDIR +import fnmatch from functools import partial +import importlib.util +import itertools +import os from os.path import expanduser from os.path import expandvars from os.path import isabs @@ -22,6 +17,9 @@ from pathlib import Path from pathlib import PurePath from posixpath import sep as posix_sep +import shutil +import sys +import types from types import ModuleType from typing import Callable from typing import Dict @@ -34,11 +32,14 @@ from typing import Type from typing import TypeVar from typing import Union +import uuid +import warnings from _pytest.compat import assert_never from _pytest.outcomes import skip from _pytest.warning_types import PytestWarning + LOCK_TIMEOUT = 60 * 60 * 24 * 3 @@ -101,9 +102,7 @@ def on_rm_rf_error( if func not in (os.open,): warnings.warn( PytestWarning( - "(rm_rf) unknown function {} when removing {}:\n{}: {}".format( - func, path, type(exc), exc - ) + f"(rm_rf) unknown function {func} when removing {path}:\n{type(exc)}: {exc}" ) ) return False @@ -242,7 +241,7 @@ def make_numbered_dir(root: Path, prefix: str, mode: int = 0o700) -> Path: else: raise OSError( "could not create numbered dir with prefix " - "{prefix} in {root} after 10 tries".format(prefix=prefix, root=root) + f"{prefix} in {root} after 10 tries" ) diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 42c9773eb98..00bd7b02cbd 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -5,19 +5,19 @@ import collections.abc import contextlib +from fnmatch import fnmatch import gc import importlib +from io import StringIO import locale import os +from pathlib import Path import platform import re import shutil import subprocess import sys import traceback -from fnmatch import fnmatch -from io import StringIO -from pathlib import Path from typing import Any from typing import Callable from typing import Dict @@ -70,6 +70,7 @@ from _pytest.tmpdir import TempPathFactory from _pytest.warning_types import PytestWarning + if TYPE_CHECKING: import pexpect @@ -187,7 +188,7 @@ def pytest_runtest_protocol(self, item: Item) -> Generator[None, object, object] "*** After:", *(str(f) for f in lines2), "***** %s FD leakage detected" % len(leaked_files), - "*** function %s:%s: %s " % item.location, + "*** function {}:{}: {} ".format(*item.location), "See issue #2366", ] item.warn(PytestWarning("\n".join(error))) @@ -244,7 +245,8 @@ def __repr__(self) -> str: if TYPE_CHECKING: # The class has undetermined attributes, this tells mypy about it. - def __getattr__(self, key: str): ... + def __getattr__(self, key: str): + ... @final @@ -325,13 +327,15 @@ def getcall(self, name: str) -> RecordedHookCall: 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( @@ -340,7 +344,8 @@ def getreports( "pytest_collectreport", "pytest_runtest_logreport", ), - ) -> Sequence[Union[CollectReport, TestReport]]: ... + ) -> Sequence[Union[CollectReport, TestReport]]: + ... def getreports( self, @@ -372,14 +377,12 @@ def matchreport( values.append(rep) if not values: raise ValueError( - "could not find test report matching %r: " - "no test reports at all!" % (inamepart,) + f"could not find test report matching {inamepart!r}: " + "no test reports at all!" ) if len(values) > 1: raise ValueError( - "found 2 or more testreports matching {!r}: {}".format( - inamepart, values - ) + f"found 2 or more testreports matching {inamepart!r}: {values}" ) return values[0] @@ -387,13 +390,15 @@ def matchreport( 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( @@ -402,7 +407,8 @@ def getfailures( "pytest_collectreport", "pytest_runtest_logreport", ), - ) -> Sequence[Union[CollectReport, TestReport]]: ... + ) -> Sequence[Union[CollectReport, TestReport]]: + ... def getfailures( self, @@ -801,7 +807,6 @@ def makefile(self, ext: str, *args: str, **kwargs: str) -> Path: The first created file. Examples: - .. code-block:: python pytester.makefile(".txt", "line1", "line2") @@ -855,7 +860,6 @@ def makepyfile(self, *args, **kwargs) -> Path: existing files. Examples: - .. code-block:: python def test_something(pytester): @@ -875,7 +879,6 @@ def maketxtfile(self, *args, **kwargs) -> Path: existing files. Examples: - .. code-block:: python def test_something(pytester): @@ -1265,9 +1268,7 @@ def getitem( for item in items: if item.name == funcname: return item - assert 0, "{!r} item not found in module:\n{}\nitems: {}".format( - funcname, source, items - ) + assert 0, f"{funcname!r} item not found in module:\n{source}\nitems: {items}" def getitems(self, source: Union[str, "os.PathLike[str]"]) -> List[Item]: """Return all test items collected from the module. @@ -1426,10 +1427,7 @@ def run( def handle_timeout() -> None: __tracebackhide__ = True - timeout_message = ( - "{seconds} second timeout expired running:" - " {command}".format(seconds=timeout, command=cmdargs) - ) + timeout_message = f"{timeout} second timeout expired running: {cmdargs}" popen.kill() popen.wait() diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 849243be3ee..895b4381c70 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1,19 +1,18 @@ """Python test discovery, setup and run of test functions.""" import abc +from collections import Counter +from collections import defaultdict import dataclasses import enum import fnmatch +from functools import partial import inspect import itertools import os +from pathlib import Path import sys import types -import warnings -from collections import Counter -from collections import defaultdict -from functools import partial -from pathlib import Path from typing import Any from typing import Callable from typing import Dict @@ -30,6 +29,7 @@ from typing import Set from typing import Tuple from typing import Union +import warnings import _pytest from _pytest import fixtures @@ -85,6 +85,7 @@ from _pytest.warning_types import PytestReturnNotNoneWarning from _pytest.warning_types import PytestUnhandledCoroutineWarning + _PYTEST_DIR = Path(_pytest.__file__).parent @@ -267,8 +268,8 @@ def pytest_pycollect_makeitem( elif getattr(obj, "__test__", True): if is_generator(obj): res: Function = Function.from_parent(collector, name=name) - reason = "yield tests were removed in pytest 4.0 - {name} will be ignored".format( - name=name + reason = ( + f"yield tests were removed in pytest 4.0 - {name} will be ignored" ) res.add_marker(MARK_GEN.xfail(run=False, reason=reason)) res.warn(PytestCollectionWarning(reason)) @@ -560,10 +561,10 @@ def importtestmodule( ) formatted_tb = str(exc_repr) raise nodes.Collector.CollectError( - "ImportError while importing test module '{path}'.\n" + f"ImportError while importing test module '{path}'.\n" "Hint: make sure your test modules/packages have valid Python names.\n" "Traceback:\n" - "{traceback}".format(path=path, traceback=formatted_tb) + f"{formatted_tb}" ) from e except skip.Exception as e: if e.allow_module_level: @@ -1496,17 +1497,13 @@ def _resolve_args_directness( for arg in indirect: if arg not in argnames: fail( - "In {}: indirect fixture '{}' doesn't exist".format( - self.function.__name__, arg - ), + f"In {self.function.__name__}: indirect fixture '{arg}' doesn't exist", pytrace=False, ) arg_directness[arg] = "indirect" else: fail( - "In {func}: expected Sequence or boolean for indirect, got {type}".format( - type=type(indirect).__name__, func=self.function.__name__ - ), + f"In {self.function.__name__}: expected Sequence or boolean for indirect, got {type(indirect).__name__}", pytrace=False, ) return arg_directness @@ -1528,9 +1525,7 @@ def _validate_if_using_arg_names( if arg not in self.fixturenames: if arg in default_arg_names: fail( - "In {}: function already takes an argument '{}' with a default value".format( - func_name, arg - ), + f"In {func_name}: function already takes an argument '{arg}' with a default value", pytrace=False, ) else: diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index 02830c18004..2c0ba09bb1d 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -1,9 +1,9 @@ -import math -import pprint from collections.abc import Collection from collections.abc import Sized from decimal import Decimal +import math from numbers import Complex +import pprint from types import TracebackType from typing import Any from typing import Callable @@ -26,6 +26,7 @@ from _pytest.compat import STRING_TYPES from _pytest.outcomes import fail + if TYPE_CHECKING: from numpy import ndarray @@ -237,9 +238,7 @@ class ApproxMapping(ApproxBase): with numeric values (the keys can be anything).""" def __repr__(self) -> str: - return "approx({!r})".format( - {k: self._approx_scalar(v) for k, v in self.expected.items()} - ) + return f"approx({({k: self._approx_scalar(v) for k, v in self.expected.items()})!r})" def _repr_compare(self, other_side: Mapping[object, float]) -> List[str]: import math @@ -314,9 +313,7 @@ def __repr__(self) -> str: seq_type = type(self.expected) if seq_type not in (tuple, list): seq_type = list - return "approx({!r})".format( - seq_type(self._approx_scalar(x) for x in self.expected) - ) + return f"approx({seq_type(self._approx_scalar(x) for x in self.expected)!r})" def _repr_compare(self, other_side: Sequence[float]) -> List[str]: import math @@ -696,7 +693,6 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase: ``approx`` falls back to strict equality for nonnumeric types instead of raising ``TypeError``. """ - # Delegate the comparison to a class that knows how to deal with the type # of the expected value (e.g. int, float, list, dict, numpy.array, etc). # @@ -778,7 +774,8 @@ def raises( expected_exception: Union[Type[E], Tuple[Type[E], ...]], *, match: Optional[Union[str, Pattern[str]]] = ..., -) -> "RaisesContext[E]": ... +) -> "RaisesContext[E]": + ... @overload @@ -787,7 +784,8 @@ def raises( # noqa: F811 func: Callable[..., Any], *args: Any, **kwargs: Any, -) -> _pytest._code.ExceptionInfo[E]: ... +) -> _pytest._code.ExceptionInfo[E]: + ... def raises( # noqa: F811 @@ -836,10 +834,10 @@ def raises( # noqa: F811 The ``match`` argument searches the formatted exception string, which includes any `PEP-678 `__ ``__notes__``: - >>> with pytest.raises(ValueError, match=r'had a note added'): # doctest: +SKIP - ... e = ValueError("value must be 42") - ... e.add_note("had a note added") - ... raise e + >>> with pytest.raises(ValueError, match=r"had a note added"): # doctest: +SKIP + ... e = ValueError("value must be 42") + ... e.add_note("had a note added") + ... raise e The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the details of the captured exception:: @@ -854,7 +852,7 @@ def raises( # noqa: F811 Given that ``pytest.raises`` matches subclasses, be wary of using it to match :class:`Exception` like this:: with pytest.raises(Exception): # Careful, this will catch ANY exception raised. - some_function() + some_function() Because :class:`Exception` is the base class of almost all exceptions, it is easy for this to hide real bugs, where the user wrote this expecting a specific exception, but some other exception is being diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index bce0ce10ead..ae9df014e50 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -1,8 +1,7 @@ """Record warnings during test function execution.""" -import re -import warnings from pprint import pformat +import re from types import TracebackType from typing import Any from typing import Callable @@ -17,12 +16,14 @@ from typing import Type from typing import TypeVar from typing import Union +import warnings from _pytest.deprecated import check_ispytest from _pytest.deprecated import WARNS_NONE_ARG from _pytest.fixtures import fixture from _pytest.outcomes import fail + T = TypeVar("T") @@ -42,13 +43,15 @@ 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 @@ -90,7 +93,8 @@ def warns( expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = ..., *, match: Optional[Union[str, Pattern[str]]] = ..., -) -> "WarningsChecker": ... +) -> "WarningsChecker": + ... @overload @@ -99,7 +103,8 @@ 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 690ae903a79..4c3ac0391cc 100644 --- a/src/_pytest/reports.py +++ b/src/_pytest/reports.py @@ -1,6 +1,6 @@ import dataclasses -import os from io import StringIO +import os from pprint import pprint from typing import Any from typing import cast @@ -36,6 +36,7 @@ from _pytest.nodes import Item from _pytest.outcomes import skip + if TYPE_CHECKING: from _pytest.runner import CallInfo @@ -45,7 +46,7 @@ def getworkerinfoline(node): return node._workerinfocache except AttributeError: d = node.workerinfo - ver = "%s.%s.%s" % d["version_info"][:3] + ver = "{}.{}.{}".format(*d["version_info"][:3]) node._workerinfocache = s = "[{}] {} -- Python {} {}".format( d["id"], d["sysplatform"], ver, d["executable"] ) @@ -70,7 +71,8 @@ def __init__(self, **kw: Any) -> None: 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"): @@ -312,9 +314,7 @@ def __init__( self.__dict__.update(extra) def __repr__(self) -> str: - return "<{} {!r} when={!r} outcome={!r}>".format( - self.__class__.__name__, self.nodeid, self.when, self.outcome - ) + return f"<{self.__class__.__name__} {self.nodeid!r} when={self.when!r} outcome={self.outcome!r}>" @classmethod def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport": @@ -429,9 +429,7 @@ def location( # type:ignore[override] return (self.fspath, None, self.fspath) def __repr__(self) -> str: - return "".format( - self.nodeid, len(self.result), self.outcome - ) + return f"" class CollectErrorRepr(TerminalRepr): @@ -443,7 +441,7 @@ def toterminal(self, out: TerminalWriter) -> None: def pytest_report_to_serializable( - report: Union[CollectReport, TestReport] + report: Union[CollectReport, TestReport], ) -> Optional[Dict[str, Any]]: if isinstance(report, (TestReport, CollectReport)): data = report._to_json() @@ -475,7 +473,7 @@ def _report_to_json(report: BaseReport) -> Dict[str, Any]: """ def serialize_repr_entry( - entry: Union[ReprEntry, ReprEntryNative] + entry: Union[ReprEntry, ReprEntryNative], ) -> Dict[str, Any]: data = dataclasses.asdict(entry) for key, value in data.items(): @@ -607,9 +605,9 @@ def deserialize_repr_crash(repr_crash_dict: Optional[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/runner.py b/src/_pytest/runner.py index f776ee82440..131b125ed59 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -37,6 +37,7 @@ from _pytest.outcomes import Skipped from _pytest.outcomes import TEST_OUTCOME + if sys.version_info[:2] < (3, 11): from exceptiongroup import BaseExceptionGroup @@ -94,8 +95,7 @@ def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None: if verbose < 2 and rep.duration < durations_min: tr.write_line("") tr.write_line( - "(%s durations < %gs hidden. Use -vv to show these durations.)" - % (len(dlist) - i, durations_min) + f"({len(dlist) - i} durations < {durations_min:g}s hidden. Use -vv to show these durations.)" ) break tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}") diff --git a/src/_pytest/scope.py b/src/_pytest/scope.py index d15c12705cd..2c6e23208f2 100644 --- a/src/_pytest/scope.py +++ b/src/_pytest/scope.py @@ -13,6 +13,7 @@ from typing import Literal from typing import Optional + _ScopeName = Literal["session", "package", "module", "class", "function"] diff --git a/src/_pytest/setuponly.py b/src/_pytest/setuponly.py index 0f8be899af2..6c73860aa42 100644 --- a/src/_pytest/setuponly.py +++ b/src/_pytest/setuponly.py @@ -2,7 +2,6 @@ from typing import Optional from typing import Union -import pytest from _pytest._io.saferepr import saferepr from _pytest.config import Config from _pytest.config import ExitCode @@ -10,6 +9,7 @@ from _pytest.fixtures import FixtureDef from _pytest.fixtures import SubRequest from _pytest.scope import Scope +import pytest def pytest_addoption(parser: Parser) -> None: @@ -71,7 +71,7 @@ def _show_fixture_action(fixturedef: FixtureDef[object], msg: str) -> None: scope_indent = list(reversed(Scope)).index(fixturedef._scope) tw.write(" " * 2 * scope_indent) tw.write( - "{step} {scope} {fixture}".format( + "{step} {scope} {fixture}".format( # noqa: UP032 (Readability) step=msg.ljust(8), # align the output to TEARDOWN scope=fixturedef.scope[0].upper(), fixture=fixturedef.argname, diff --git a/src/_pytest/setupplan.py b/src/_pytest/setupplan.py index 1a4ebdd99ca..13c0df84ea1 100644 --- a/src/_pytest/setupplan.py +++ b/src/_pytest/setupplan.py @@ -1,12 +1,12 @@ from typing import Optional from typing import Union -import pytest from _pytest.config import Config from _pytest.config import ExitCode from _pytest.config.argparsing import Parser from _pytest.fixtures import FixtureDef from _pytest.fixtures import SubRequest +import pytest def pytest_addoption(parser: Parser) -> None: diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index a14e6c9722c..76d523d7060 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -1,11 +1,11 @@ """Support for skip/xfail functions and markers.""" +from collections.abc import Mapping import dataclasses import os import platform import sys import traceback -from collections.abc import Mapping from typing import Generator from typing import Optional from typing import Tuple @@ -105,9 +105,7 @@ def evaluate_condition(item: Item, mark: Mark, condition: object) -> Tuple[bool, ): if not isinstance(dictionary, Mapping): raise ValueError( - "pytest_markeval_namespace() needs to return a dict, got {!r}".format( - dictionary - ) + f"pytest_markeval_namespace() needs to return a dict, got {dictionary!r}" ) globals_.update(dictionary) if hasattr(item, "obj"): diff --git a/src/_pytest/stash.py b/src/_pytest/stash.py index 7b111981bb0..e61d75b95f7 100644 --- a/src/_pytest/stash.py +++ b/src/_pytest/stash.py @@ -5,6 +5,7 @@ from typing import TypeVar from typing import Union + __all__ = ["Stash", "StashKey"] diff --git a/src/_pytest/stepwise.py b/src/_pytest/stepwise.py index 74ad9dbd4dd..3ebebc288f8 100644 --- a/src/_pytest/stepwise.py +++ b/src/_pytest/stepwise.py @@ -2,12 +2,13 @@ from typing import Optional from typing import TYPE_CHECKING -import pytest from _pytest import nodes from _pytest.config import Config from _pytest.config.argparsing import Parser from _pytest.main import Session from _pytest.reports import TestReport +import pytest + if TYPE_CHECKING: from _pytest.cacheprovider import Cache diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 26e4a3acef5..84ce8d8c6c6 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -4,16 +4,15 @@ """ import argparse +from collections import Counter import dataclasses import datetime +from functools import partial import inspect +from pathlib import Path import platform import sys import textwrap -import warnings -from collections import Counter -from functools import partial -from pathlib import Path from typing import Any from typing import Callable from typing import ClassVar @@ -31,16 +30,17 @@ from typing import Tuple from typing import TYPE_CHECKING from typing import Union +import warnings import pluggy -import _pytest._version from _pytest import nodes from _pytest import timing from _pytest._code import ExceptionInfo from _pytest._code.code import ExceptionRepr from _pytest._io import TerminalWriter from _pytest._io.wcwidth import wcswidth +import _pytest._version from _pytest.assertion.util import running_on_ci from _pytest.config import _PluggyPlugin from _pytest.config import Config @@ -55,6 +55,7 @@ from _pytest.reports import CollectReport from _pytest.reports import TestReport + if TYPE_CHECKING: from _pytest.main import Session @@ -671,8 +672,8 @@ def _get_progress_information_message(self) -> str: return f" [ {collected} / {collected} ]" else: if collected: - return " [{:3d}%]".format( - len(self._progress_nodeids_reported) * 100 // collected + return ( + f" [{len(self._progress_nodeids_reported) * 100 // collected:3d}%]" ) return " [100%]" @@ -757,9 +758,7 @@ def pytest_sessionstart(self, session: "Session") -> None: if pypy_version_info: verinfo = ".".join(map(str, pypy_version_info[:3])) msg += f"[pypy-{verinfo}-{pypy_version_info[3]}]" - msg += ", pytest-{}, pluggy-{}".format( - _pytest._version.version, pluggy.__version__ - ) + msg += f", pytest-{_pytest._version.version}, pluggy-{pluggy.__version__}" if ( self.verbosity > 0 or self.config.option.debug @@ -1464,7 +1463,7 @@ def _plugin_nameversions(plugininfo) -> List[str]: values: List[str] = [] for plugin, dist in plugininfo: # Gets us name and version! - name = "{dist.project_name}-{dist.version}".format(dist=dist) + name = f"{dist.project_name}-{dist.version}" # Questionable convenience, but it keeps things short. if name.startswith("pytest-"): name = name[7:] diff --git a/src/_pytest/threadexception.py b/src/_pytest/threadexception.py index 0b5902d66a8..09faf661b91 100644 --- a/src/_pytest/threadexception.py +++ b/src/_pytest/threadexception.py @@ -1,12 +1,12 @@ import threading import traceback -import warnings from types import TracebackType from typing import Any from typing import Callable from typing import Generator from typing import Optional from typing import Type +import warnings import pytest diff --git a/src/_pytest/timing.py b/src/_pytest/timing.py index 096a6776873..0541dc8e0a1 100644 --- a/src/_pytest/timing.py +++ b/src/_pytest/timing.py @@ -10,4 +10,5 @@ from time import sleep from time import time + __all__ = ["perf_counter", "sleep", "time"] diff --git a/src/_pytest/tmpdir.py b/src/_pytest/tmpdir.py index 34899520313..986824ccb72 100644 --- a/src/_pytest/tmpdir.py +++ b/src/_pytest/tmpdir.py @@ -2,10 +2,10 @@ import dataclasses import os -import re -import tempfile from pathlib import Path +import re from shutil import rmtree +import tempfile from typing import Any from typing import Dict from typing import final @@ -32,6 +32,7 @@ from _pytest.reports import TestReport from _pytest.stash import StashKey + tmppath_result_key = StashKey[Dict[str, bool]]() RetentionType = Literal["all", "failed", "none"] @@ -268,7 +269,6 @@ def tmp_path( The returned object is a :class:`pathlib.Path` object. """ - path = _mk_tmp(request, tmp_path_factory) yield path diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py index fd3fc231b8e..de68f396537 100644 --- a/src/_pytest/unittest.py +++ b/src/_pytest/unittest.py @@ -15,7 +15,6 @@ from typing import Union import _pytest._code -import pytest from _pytest.compat import getimfunc from _pytest.compat import is_async_function from _pytest.config import hookimpl @@ -31,6 +30,8 @@ from _pytest.python import Module from _pytest.runner import CallInfo from _pytest.scope import Scope +import pytest + if TYPE_CHECKING: import unittest @@ -219,7 +220,9 @@ def _addexcinfo(self, rawexcinfo: "_SysExcInfoType") -> None: # Unwrap potential exception info (see twisted trial support below). rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo) try: - excinfo = _pytest._code.ExceptionInfo[BaseException].from_exc_info(rawexcinfo) # type: ignore[arg-type] + excinfo = _pytest._code.ExceptionInfo[BaseException].from_exc_info( + rawexcinfo # type: ignore[arg-type] + ) # Invoke the attributes to trigger storing the traceback # trial causes some issue there. excinfo.value @@ -364,9 +367,7 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None: # handled internally, and doesn't reach here. unittest = sys.modules.get("unittest") if ( - unittest - and call.excinfo - and isinstance(call.excinfo.value, unittest.SkipTest) # type: ignore[attr-defined] + unittest and call.excinfo and isinstance(call.excinfo.value, unittest.SkipTest) # type: ignore[attr-defined] ): excinfo = call.excinfo call2 = CallInfo[None].from_call( diff --git a/src/_pytest/unraisableexception.py b/src/_pytest/unraisableexception.py index 8c0a2d9ae95..f649267abf1 100644 --- a/src/_pytest/unraisableexception.py +++ b/src/_pytest/unraisableexception.py @@ -1,12 +1,12 @@ import sys import traceback -import warnings from types import TracebackType from typing import Any from typing import Callable from typing import Generator from typing import Optional from typing import Type +import warnings import pytest diff --git a/src/_pytest/warning_types.py b/src/_pytest/warning_types.py index 4219f1439a2..ae00ccfa613 100644 --- a/src/_pytest/warning_types.py +++ b/src/_pytest/warning_types.py @@ -1,12 +1,12 @@ import dataclasses import inspect -import warnings from types import FunctionType from typing import Any from typing import final from typing import Generic from typing import Type from typing import TypeVar +import warnings class PytestWarning(UserWarning): @@ -79,11 +79,7 @@ class PytestExperimentalApiWarning(PytestWarning, FutureWarning): @classmethod def simple(cls, apiname: str) -> "PytestExperimentalApiWarning": - return cls( - "{apiname} is an experimental api that may change over time".format( - apiname=apiname - ) - ) + return cls(f"{apiname} is an experimental api that may change over time") @final diff --git a/src/_pytest/warnings.py b/src/_pytest/warnings.py index 6f20a872cca..f45163fa2e6 100644 --- a/src/_pytest/warnings.py +++ b/src/_pytest/warnings.py @@ -1,17 +1,17 @@ -import sys -import warnings from contextlib import contextmanager +import sys from typing import Generator from typing import Literal from typing import Optional +import warnings -import pytest from _pytest.config import apply_warning_filters from _pytest.config import Config from _pytest.config import parse_warning_filter from _pytest.main import Session from _pytest.nodes import Item from _pytest.terminal import TerminalReporter +import pytest def pytest_configure(config: Config) -> None: diff --git a/src/py.py b/src/py.py index c997903363a..d1c39d203a8 100644 --- a/src/py.py +++ b/src/py.py @@ -6,6 +6,7 @@ import _pytest._py.error as error import _pytest._py.path as path + sys.modules["py.error"] = error sys.modules["py.path"] = path diff --git a/src/pytest/__init__.py b/src/pytest/__init__.py index 4e0c23ddbe7..d37b76505f9 100644 --- a/src/pytest/__init__.py +++ b/src/pytest/__init__.py @@ -84,6 +84,7 @@ from _pytest.warning_types import PytestUnraisableExceptionWarning from _pytest.warning_types import PytestWarning + set_trace = __pytestPDB.set_trace diff --git a/src/pytest/__main__.py b/src/pytest/__main__.py index 9e08e3ebc20..e4cb67d5dd5 100644 --- a/src/pytest/__main__.py +++ b/src/pytest/__main__.py @@ -2,5 +2,6 @@ import pytest + if __name__ == "__main__": raise SystemExit(pytest.console_main()) diff --git a/testing/_py/test_local.py b/testing/_py/test_local.py index 0c7f377e4fb..735e81d8f7c 100644 --- a/testing/_py/test_local.py +++ b/testing/_py/test_local.py @@ -3,8 +3,8 @@ import os import sys import time -import warnings from unittest import mock +import warnings from py import error from py.path import local @@ -182,7 +182,7 @@ def test_listdir_fnmatchstring(self, path1): def test_listdir_filter(self, path1): p = path1.listdir(lambda x: x.check(dir=1)) assert path1.join("sampledir") in p - assert not path1.join("samplefile") in p + assert path1.join("samplefile") not in p def test_listdir_sorted(self, path1): p = path1.listdir(lambda x: x.check(basestarts="sample"), sort=True) @@ -202,7 +202,7 @@ def test_visit_norecurse(self, path1): for i in path1.visit(None, lambda x: x.basename != "sampledir"): lst.append(i.relto(path1)) assert "sampledir" in lst - assert not path1.sep.join(["sampledir", "otherfile"]) in lst + assert path1.sep.join(["sampledir", "otherfile"]) not in lst @pytest.mark.parametrize( "fil", diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index b875b8f6631..798c153ffcc 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -5,10 +5,10 @@ import sys import types -import pytest from _pytest.config import ExitCode from _pytest.pathlib import symlink_or_skip from _pytest.pytester import Pytester +import pytest def prepend_pythonpath(*dirs) -> str: diff --git a/testing/code/test_code.py b/testing/code/test_code.py index 33809528a06..4bcc2b145cd 100644 --- a/testing/code/test_code.py +++ b/testing/code/test_code.py @@ -3,13 +3,13 @@ from types import FrameType from unittest import mock -import pytest from _pytest._code import Code from _pytest._code import ExceptionInfo from _pytest._code import Frame from _pytest._code import Source from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ReprFuncArgs +import pytest def test_ne() -> None: diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index a2911e1331e..afc897b9636 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -3,16 +3,15 @@ import importlib import io import operator +from pathlib import Path import queue import re import sys import textwrap -from pathlib import Path from typing import Any from typing import TYPE_CHECKING import _pytest._code -import pytest from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionInfo from _pytest._code.code import FormattedExcinfo @@ -22,6 +21,8 @@ from _pytest.pathlib import import_path from _pytest.pytester import LineMatcher from _pytest.pytester import Pytester +import pytest + if TYPE_CHECKING: from _pytest._code.code import _TracebackStyle @@ -1172,9 +1173,7 @@ def f(): "funcargs": funcargs, "tbfilter": tbfilter, }, - id="style={},showlocals={},funcargs={},tbfilter={}".format( - style, showlocals, funcargs, tbfilter - ), + id=f"style={style},showlocals={showlocals},funcargs={funcargs},tbfilter={tbfilter}", ) for style in ["long", "short", "line", "no", "native", "value", "auto"] for showlocals in (True, False) @@ -1338,7 +1337,7 @@ def test_exc_repr_chain_suppression(self, importasmod, mode, tw_mock): """ raise_suffix = " from None" if mode == "from_none" else "" mod = importasmod( - """ + f""" def f(): try: g() @@ -1346,9 +1345,7 @@ def f(): raise AttributeError(){raise_suffix} def g(): raise ValueError() - """.format( - raise_suffix=raise_suffix - ) + """ ) excinfo = pytest.raises(AttributeError, mod.f) r = excinfo.getrepr(style="long", chain=mode != "explicit_suppress") @@ -1360,9 +1357,7 @@ def g(): assert tw_mock.lines[2] == " try:" assert tw_mock.lines[3] == " g()" assert tw_mock.lines[4] == " except Exception:" - assert tw_mock.lines[5] == "> raise AttributeError(){}".format( - raise_suffix - ) + assert tw_mock.lines[5] == f"> raise AttributeError(){raise_suffix}" assert tw_mock.lines[6] == "E AttributeError" assert tw_mock.lines[7] == "" line = tw_mock.get_write_msg(8) @@ -1393,7 +1388,7 @@ def test_exc_chain_repr_without_traceback(self, importasmod, reason, description """ exc_handling_code = " from e" if reason == "cause" else "" mod = importasmod( - """ + f""" def f(): try: g() @@ -1401,9 +1396,7 @@ def f(): raise RuntimeError('runtime problem'){exc_handling_code} def g(): raise ValueError('invalid value') - """.format( - exc_handling_code=exc_handling_code - ) + """ ) with pytest.raises(RuntimeError) as excinfo: diff --git a/testing/conftest.py b/testing/conftest.py index bcb05339b62..b61270dbe55 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -4,9 +4,10 @@ from typing import Generator from typing import List -import pytest from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest + if sys.gettrace(): diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 0736ed1dcc1..b058fbcca38 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -1,12 +1,12 @@ +from pathlib import Path import re import sys import warnings -from pathlib import Path -import pytest from _pytest import deprecated from _pytest.compat import legacy_path from _pytest.pytester import Pytester +import pytest from pytest import PytestDeprecationWarning diff --git a/testing/example_scripts/acceptance/fixture_mock_integration.py b/testing/example_scripts/acceptance/fixture_mock_integration.py index 73fd383150b..f13ba9772a2 100644 --- a/testing/example_scripts/acceptance/fixture_mock_integration.py +++ b/testing/example_scripts/acceptance/fixture_mock_integration.py @@ -4,6 +4,7 @@ import pytest + config = {"mykey": "ORIGINAL"} diff --git a/testing/example_scripts/perf_examples/collect_stats/generate_folders.py b/testing/example_scripts/perf_examples/collect_stats/generate_folders.py index ff1eaf7d6bb..94b3f013fd8 100644 --- a/testing/example_scripts/perf_examples/collect_stats/generate_folders.py +++ b/testing/example_scripts/perf_examples/collect_stats/generate_folders.py @@ -1,6 +1,7 @@ import argparse import pathlib + HERE = pathlib.Path(__file__).parent TEST_CONTENT = (HERE / "template_test.py").read_bytes() diff --git a/testing/example_scripts/unittest/test_unittest_asyncio.py b/testing/example_scripts/unittest/test_unittest_asyncio.py index e4b4a56c7eb..1cd2168604c 100644 --- a/testing/example_scripts/unittest/test_unittest_asyncio.py +++ b/testing/example_scripts/unittest/test_unittest_asyncio.py @@ -1,6 +1,7 @@ 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 81341961785..85d93d32c9d 100644 --- a/testing/example_scripts/unittest/test_unittest_asynctest.py +++ b/testing/example_scripts/unittest/test_unittest_asynctest.py @@ -5,6 +5,7 @@ import asynctest + teardowns: List[None] = [] diff --git a/testing/io/test_pprint.py b/testing/io/test_pprint.py index 3432c63f688..15fe6611280 100644 --- a/testing/io/test_pprint.py +++ b/testing/io/test_pprint.py @@ -1,16 +1,16 @@ -import textwrap from collections import ChainMap from collections import Counter from collections import defaultdict from collections import deque from collections import OrderedDict from dataclasses import dataclass +import textwrap from types import MappingProxyType from types import SimpleNamespace from typing import Any -import pytest from _pytest._io.pprint import PrettyPrinter +import pytest @dataclass diff --git a/testing/io/test_saferepr.py b/testing/io/test_saferepr.py index d94faa4f194..5e055c5a37b 100644 --- a/testing/io/test_saferepr.py +++ b/testing/io/test_saferepr.py @@ -1,7 +1,7 @@ -import pytest from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr_unlimited +import pytest def test_simple_repr(): @@ -58,9 +58,7 @@ class BrokenReprException(Exception): obj = BrokenRepr(BrokenReprException("omg even worse")) s2 = saferepr(obj) assert s2 == ( - "<[unpresentable exception ({!s}) raised in repr()] BrokenRepr object at 0x{:x}>".format( - exp_exc, id(obj) - ) + f"<[unpresentable exception ({exp_exc!s}) raised in repr()] BrokenRepr object at 0x{id(obj):x}>" ) @@ -98,14 +96,12 @@ def __repr__(self): baseexc_str = BaseException("__str__") obj = BrokenObj(RaisingOnStrRepr([BaseException])) assert saferepr(obj) == ( - "<[unpresentable exception ({!r}) " - "raised in repr()] BrokenObj object at 0x{:x}>".format(baseexc_str, id(obj)) + f"<[unpresentable exception ({baseexc_str!r}) " + f"raised in repr()] BrokenObj object at 0x{id(obj):x}>" ) obj = BrokenObj(RaisingOnStrRepr([RaisingOnStrRepr([BaseException])])) assert saferepr(obj) == ( - "<[{!r} raised in repr()] BrokenObj object at 0x{:x}>".format( - baseexc_str, id(obj) - ) + f"<[{baseexc_str!r} raised in repr()] BrokenObj object at 0x{id(obj):x}>" ) with pytest.raises(KeyboardInterrupt): diff --git a/testing/io/test_terminalwriter.py b/testing/io/test_terminalwriter.py index c2b875e9244..7f01db8e1d8 100644 --- a/testing/io/test_terminalwriter.py +++ b/testing/io/test_terminalwriter.py @@ -1,16 +1,17 @@ import io import os +from pathlib import Path import re import shutil import sys -from pathlib import Path from typing import Generator from typing import Optional from unittest import mock -import pytest from _pytest._io import terminalwriter from _pytest.monkeypatch import MonkeyPatch +import pytest + # These tests were initially copied from py 1.8.1. diff --git a/testing/io/test_wcwidth.py b/testing/io/test_wcwidth.py index 7cc74df5d07..9ed2a6d3c49 100644 --- a/testing/io/test_wcwidth.py +++ b/testing/io/test_wcwidth.py @@ -1,6 +1,6 @@ -import pytest from _pytest._io.wcwidth import wcswidth from _pytest._io.wcwidth import wcwidth +import pytest @pytest.mark.parametrize( diff --git a/testing/logging/test_fixture.py b/testing/logging/test_fixture.py index f4912aecce4..2e16913f099 100644 --- a/testing/logging/test_fixture.py +++ b/testing/logging/test_fixture.py @@ -3,9 +3,10 @@ import logging from typing import Iterator -import pytest from _pytest.logging import caplog_records_key from _pytest.pytester import Pytester +import pytest + logger = logging.getLogger(__name__) sublogger = logging.getLogger(__name__ + ".baz") diff --git a/testing/logging/test_reporting.py b/testing/logging/test_reporting.py index 70144cef0fa..f0165e2bb7c 100644 --- a/testing/logging/test_reporting.py +++ b/testing/logging/test_reporting.py @@ -3,12 +3,12 @@ import re from typing import cast -import pytest from _pytest.capture import CaptureManager from _pytest.config import ExitCode from _pytest.fixtures import FixtureRequest from _pytest.pytester import Pytester from _pytest.terminal import TerminalReporter +import pytest def test_nothing_logged(pytester: Pytester) -> None: @@ -176,13 +176,11 @@ def teardown_function(function): def test_log_cli_enabled_disabled(pytester: Pytester, enabled: bool) -> None: msg = "critical message logged by test" pytester.makepyfile( - """ + f""" import logging def test_log_cli(): - logging.critical("{}") - """.format( - msg - ) + logging.critical("{msg}") + """ ) if enabled: pytester.makeini( @@ -709,13 +707,11 @@ def test_log_file_ini(pytester: Pytester) -> None: log_file = str(pytester.path.joinpath("pytest.log")) pytester.makeini( - """ + f""" [pytest] - log_file={} + log_file={log_file} log_file_level=WARNING - """.format( - log_file - ) + """ ) pytester.makepyfile( """ @@ -748,13 +744,11 @@ def test_log_file_ini_level(pytester: Pytester) -> None: log_file = str(pytester.path.joinpath("pytest.log")) pytester.makeini( - """ + f""" [pytest] - log_file={} + log_file={log_file} log_file_level = INFO - """.format( - log_file - ) + """ ) pytester.makepyfile( """ @@ -787,13 +781,11 @@ def test_log_file_unicode(pytester: Pytester) -> None: log_file = str(pytester.path.joinpath("pytest.log")) pytester.makeini( - """ + f""" [pytest] - log_file={} + log_file={log_file} log_file_level = INFO - """.format( - log_file - ) + """ ) pytester.makepyfile( """\ @@ -831,8 +823,8 @@ def test_live_logging_suspends_capture( is installed. """ import contextlib - import logging from functools import partial + import logging from _pytest.logging import _LiveLoggingStreamHandler @@ -923,13 +915,11 @@ def test_collection_logging_to_file(pytester: Pytester) -> None: log_file = str(pytester.path.joinpath("pytest.log")) pytester.makeini( - """ + f""" [pytest] - log_file={} + log_file={log_file} log_file_level = INFO - """.format( - log_file - ) + """ ) pytester.makepyfile( @@ -961,14 +951,12 @@ def test_log_in_hooks(pytester: Pytester) -> None: log_file = str(pytester.path.joinpath("pytest.log")) pytester.makeini( - """ + f""" [pytest] - log_file={} + log_file={log_file} log_file_level = INFO log_cli=true - """.format( - log_file - ) + """ ) pytester.makeconftest( """ @@ -997,14 +985,12 @@ def test_log_in_runtest_logreport(pytester: Pytester) -> None: log_file = str(pytester.path.joinpath("pytest.log")) pytester.makeini( - """ + f""" [pytest] - log_file={} + log_file={log_file} log_file_level = INFO log_cli=true - """.format( - log_file - ) + """ ) pytester.makeconftest( """ @@ -1038,19 +1024,17 @@ def test_log_set_path(pytester: Pytester) -> None: """ ) pytester.makeconftest( - """ + f""" import os import pytest @pytest.hookimpl(wrapper=True, tryfirst=True) def pytest_runtest_setup(item): config = item.config logging_plugin = config.pluginmanager.get_plugin("logging-plugin") - report_file = os.path.join({}, item._request.node.name) + report_file = os.path.join({repr(report_dir_base)}, item._request.node.name) logging_plugin.set_log_path(report_file) return (yield) - """.format( - repr(report_dir_base) - ) + """ ) pytester.makepyfile( """ diff --git a/testing/python/approx.py b/testing/python/approx.py index 3b87e58f91a..c883b2030c2 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -1,17 +1,18 @@ -import operator from contextlib import contextmanager from decimal import Decimal from fractions import Fraction from math import sqrt +import operator from operator import eq from operator import ne from typing import Optional -import pytest from _pytest.pytester import Pytester from _pytest.python_api import _recursive_sequence_map +import pytest from pytest import approx + inf, nan = float("inf"), float("nan") @@ -37,9 +38,7 @@ def set_continue(self): class MyDocTestRunner(doctest.DocTestRunner): def report_failure(self, out, test, example, got): raise AssertionError( - "'{}' evaluates to '{}', not '{}'".format( - example.source.strip(), got.strip(), example.want.strip() - ) + f"'{example.source.strip()}' evaluates to '{got.strip()}', not '{example.want.strip()}'" ) return MyDocTestRunner() diff --git a/testing/python/collect.py b/testing/python/collect.py index da11dd34a9a..124019b1664 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -5,7 +5,6 @@ from typing import Dict import _pytest._code -import pytest from _pytest.config import ExitCode from _pytest.main import Session from _pytest.monkeypatch import MonkeyPatch @@ -13,6 +12,7 @@ from _pytest.pytester import Pytester from _pytest.python import Class from _pytest.python import Function +import pytest class TestModule: @@ -53,13 +53,11 @@ def test_import_prepend_append( monkeypatch.syspath_prepend(str(root1)) p.write_text( textwrap.dedent( - """\ + f"""\ import x456 def test(): - assert x456.__file__.startswith({!r}) - """.format( - str(root2) - ) + assert x456.__file__.startswith({str(root2)!r}) + """ ), encoding="utf-8", ) diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 775056a8e98..5512b602dc7 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -1,9 +1,8 @@ import os +from pathlib import Path import sys import textwrap -from pathlib import Path -import pytest from _pytest.compat import getfuncargnames from _pytest.config import ExitCode from _pytest.fixtures import deduplicate_names @@ -12,6 +11,7 @@ from _pytest.pytester import get_public_names from _pytest.pytester import Pytester from _pytest.python import Function +import pytest def test_getfuncargnames_functions(): @@ -1287,7 +1287,7 @@ def test_nothing(badscope): @pytest.mark.parametrize("scope", ["function", "session"]) def test_parameters_without_eq_semantics(self, scope, pytester: Pytester) -> None: pytester.makepyfile( - """ + f""" class NoEq1: # fails on `a == b` statement def __eq__(self, _): raise RuntimeError @@ -1309,9 +1309,7 @@ def test1(no_eq): def test2(no_eq): pass - """.format( - scope=scope - ) + """ ) result = pytester.runpytest() result.stdout.fnmatch_lines(["*4 passed*"]) @@ -2198,7 +2196,7 @@ def test_arg(arg2): pass def test_check(): assert values == ["new1", "new2", "fin2", "fin1"] - """ + """ # noqa: UP031 (python syntax issues) % locals() ) reprec = pytester.inline_run("-s") @@ -3086,8 +3084,8 @@ def test_baz(base, fix2): pass def test_other(): pass - """ - % {"scope": scope} + """ # noqa: UP031 (python syntax issues) + % {"scope": scope} # noqa: UP031 (python syntax issues) ) reprec = pytester.inline_run("-lvs") reprec.assertoutcome(passed=3) @@ -3286,7 +3284,7 @@ def myscoped(request): assert request.config def test_func(): pass - """ + """ # noqa: UP031 (python syntax issues) % (scope, ok.split(), error.split()) ) reprec = pytester.inline_run("-l") @@ -3307,7 +3305,7 @@ def arg(request): assert request.config def test_func(arg): pass - """ + """ # noqa: UP031 (python syntax issues) % (scope, ok.split(), error.split()) ) reprec = pytester.inline_run() diff --git a/testing/python/integration.py b/testing/python/integration.py index 51f231849f2..c90e21356c5 100644 --- a/testing/python/integration.py +++ b/testing/python/integration.py @@ -1,8 +1,8 @@ -import pytest from _pytest._code import getfslineno from _pytest.fixtures import getfixturemarker from _pytest.pytester import Pytester from _pytest.python import Function +import pytest def test_wrapped_getfslineno() -> None: diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 9393c972746..9a7adf52d50 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -13,7 +13,6 @@ from typing import Tuple from typing import Union -import pytest from _pytest import fixtures from _pytest import python from _pytest.compat import getfuncargnames @@ -23,6 +22,8 @@ from _pytest.python import Function from _pytest.python import IdMaker from _pytest.scope import Scope +import pytest + # import hypothesis # from hypothesis import strategies @@ -1940,7 +1941,7 @@ def test_increment(n, expected): @pytest.mark.parametrize("strict", [True, False]) def test_xfail_passing_is_xpass(self, pytester: Pytester, strict: bool) -> None: - s = """ + s = f""" import pytest m = pytest.mark.xfail("sys.version_info > (0, 0, 0)", reason="some bug", strict={strict}) @@ -1952,9 +1953,7 @@ def test_xfail_passing_is_xpass(self, pytester: Pytester, strict: bool) -> None: ]) def test_increment(n, expected): assert n + 1 == expected - """.format( - strict=strict - ) + """ pytester.makepyfile(s) reprec = pytester.inline_run() passed, failed = (2, 1) if strict else (3, 0) @@ -2005,7 +2004,7 @@ def test_limit(limit, myfixture): @pytest.mark.parametrize("strict", [True, False]) def test_parametrize_marked_value(self, pytester: Pytester, strict: bool) -> None: - s = """ + s = f""" import pytest @pytest.mark.parametrize(("n", "expected"), [ @@ -2020,9 +2019,7 @@ def test_parametrize_marked_value(self, pytester: Pytester, strict: bool) -> Non ]) def test_increment(n, expected): assert n + 1 == expected - """.format( - strict=strict - ) + """ pytester.makepyfile(s) reprec = pytester.inline_run() passed, failed = (0, 2) if strict else (2, 0) diff --git a/testing/python/raises.py b/testing/python/raises.py index f1e8fb1fb30..99a3c766a0e 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -1,9 +1,9 @@ import re import sys -import pytest from _pytest.outcomes import Failed from _pytest.pytester import Pytester +import pytest class TestRaises: diff --git a/testing/test_argcomplete.py b/testing/test_argcomplete.py index 8c10e230b0c..592b1f30374 100644 --- a/testing/test_argcomplete.py +++ b/testing/test_argcomplete.py @@ -1,9 +1,10 @@ +from pathlib import Path import subprocess import sys -from pathlib import Path -import pytest from _pytest.monkeypatch import MonkeyPatch +import pytest + # Test for _argcomplete but not specific for any application. diff --git a/testing/test_assertion.py b/testing/test_assertion.py index e55ec38e145..de0d3ed1bcb 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -8,14 +8,14 @@ import attr -import _pytest.assertion as plugin -import pytest from _pytest import outcomes +import _pytest.assertion as plugin from _pytest.assertion import truncate from _pytest.assertion import util from _pytest.config import Config as _Config from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest def mock_config(verbose: int = 0, assertion_override: Optional[int] = None): @@ -181,11 +181,9 @@ def test_pytest_plugins_rewrite_module_names( """ plugins = '"ham"' if mode == "str" else '["ham"]' contents = { - "conftest.py": """ + "conftest.py": f""" pytest_plugins = {plugins} - """.format( - plugins=plugins - ), + """, "ham.py": """ import pytest """, @@ -853,9 +851,7 @@ def __repr__(self): assert "raised in repr" in expl[0] assert expl[2:] == [ "(pytest_assertion plugin: representation of details failed:" - " {}:{}: ValueError: 42.".format( - __file__, A.__repr__.__code__.co_firstlineno + 1 - ), + f" {__file__}:{A.__repr__.__code__.co_firstlineno + 1}: ValueError: 42.", " Probably an object has a faulty __repr__.)", ] @@ -1398,7 +1394,6 @@ def test_truncates_at_1_line_when_first_line_is_GT_max_chars(self) -> None: def test_full_output_truncated(self, monkeypatch, pytester: Pytester) -> None: """Test against full runpytest() output.""" - line_count = 7 line_len = 100 expected_truncated_lines = 2 diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index f29c4448e64..1fb3401bab6 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1,16 +1,15 @@ import ast import errno +from functools import partial import glob import importlib import marshal import os +from pathlib import Path import py_compile import stat import sys import textwrap -import zipfile -from functools import partial -from pathlib import Path from typing import cast from typing import Dict from typing import Generator @@ -19,9 +18,9 @@ from typing import Optional from typing import Set from unittest import mock +import zipfile import _pytest._code -import pytest from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest.assertion import util from _pytest.assertion.rewrite import _get_assertion_exprs @@ -35,6 +34,7 @@ from _pytest.config import ExitCode from _pytest.pathlib import make_numbered_dir from _pytest.pytester import Pytester +import pytest def rewrite(src: str) -> ast.Module: @@ -780,11 +780,10 @@ def test_zipfile(self, pytester: Pytester) -> None: f.close() z.chmod(256) pytester.makepyfile( - """ + f""" import sys - sys.path.append(%r) + sys.path.append({z_fn!r}) import test_gum.test_lizard""" - % (z_fn,) ) assert pytester.runpytest().ret == ExitCode.NO_TESTS_COLLECTED @@ -1856,10 +1855,10 @@ def test_simple(): result.assert_outcomes(passed=1) +# fmt: off @pytest.mark.parametrize( ("src", "expected"), ( - # fmt: off pytest.param(b"", {}, id="trivial"), pytest.param( b"def x(): assert 1\n", @@ -1936,9 +1935,9 @@ def test_simple(): {1: "5"}, id="no newline at end of file", ), - # fmt: on ), ) +# fmt: on def test_get_assertion_exprs(src, expected) -> None: assert _get_assertion_exprs(src) == expected @@ -2034,9 +2033,7 @@ def test_foo(): assert test_foo_pyc.is_file() # normal file: not touched by pytest, normal cache tag - bar_init_pyc = get_cache_dir(bar_init) / "__init__.{cache_tag}.pyc".format( - cache_tag=sys.implementation.cache_tag - ) + bar_init_pyc = get_cache_dir(bar_init) / f"__init__.{sys.implementation.cache_tag}.pyc" assert bar_init_pyc.is_file() diff --git a/testing/test_cacheprovider.py b/testing/test_cacheprovider.py index 21c1957cfeb..ab3209a0faf 100644 --- a/testing/test_cacheprovider.py +++ b/testing/test_cacheprovider.py @@ -1,14 +1,15 @@ import os -import shutil from pathlib import Path +import shutil from typing import Generator from typing import List -import pytest from _pytest.config import ExitCode from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester from _pytest.tmpdir import TempPathFactory +import pytest + pytest_plugins = ("pytester",) @@ -133,12 +134,10 @@ def test_cachefuncarg(cache): def test_custom_rel_cache_dir(self, pytester: Pytester) -> None: rel_cache_dir = os.path.join("custom_cache_dir", "subdir") pytester.makeini( - """ + f""" [pytest] - cache_dir = {cache_dir} - """.format( - cache_dir=rel_cache_dir - ) + cache_dir = {rel_cache_dir} + """ ) pytester.makepyfile(test_errored="def test_error():\n assert False") pytester.runpytest() @@ -150,12 +149,10 @@ def test_custom_abs_cache_dir( tmp = tmp_path_factory.mktemp("tmp") abs_cache_dir = tmp / "custom_cache_dir" pytester.makeini( - """ + f""" [pytest] - cache_dir = {cache_dir} - """.format( - cache_dir=abs_cache_dir - ) + cache_dir = {abs_cache_dir} + """ ) pytester.makepyfile(test_errored="def test_error():\n assert False") pytester.runpytest() @@ -169,9 +166,7 @@ def test_custom_cache_dir_with_env_var( """ [pytest] cache_dir = {cache_dir} - """.format( - cache_dir="$env_var" - ) + """.format(cache_dir="$env_var") ) pytester.makepyfile(test_errored="def test_error():\n assert False") pytester.runpytest() @@ -200,12 +195,10 @@ def test_cache_reportheader_external_abspath( pytester.makepyfile("def test_hello(): pass") pytester.makeini( - """ + f""" [pytest] - cache_dir = {abscache} - """.format( - abscache=external_cache - ) + cache_dir = {external_cache} + """ ) result = pytester.runpytest("-v") result.stdout.fnmatch_lines([f"cachedir: {external_cache}"]) @@ -645,13 +638,11 @@ def test(): assert 0 assert result.ret == 1 pytester.makepyfile( - """ + f""" import pytest @pytest.{mark} def test(): assert 0 - """.format( - mark=mark - ) + """ ) result = pytester.runpytest() assert result.ret == 0 diff --git a/testing/test_capture.py b/testing/test_capture.py index b6ea8161356..bc918ed30f0 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,16 +1,15 @@ import contextlib import io +from io import UnsupportedOperation import os import subprocess import sys import textwrap -from io import UnsupportedOperation from typing import BinaryIO from typing import cast from typing import Generator from typing import TextIO -import pytest from _pytest import capture from _pytest.capture import _get_multicapture from _pytest.capture import CaptureFixture @@ -20,6 +19,8 @@ from _pytest.config import ExitCode from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest + # note: py.io capture tests where copied from # pylib 1.4.20.dev2 (rev 13d9af95547e) @@ -502,13 +503,11 @@ def test_capture_is_represented_on_failure_issue128( self, pytester: Pytester, method ) -> None: p = pytester.makepyfile( - """\ - def test_hello(cap{}): + f"""\ + def test_hello(cap{method}): print("xxx42xxx") assert 0 - """.format( - method - ) + """ ) result = pytester.runpytest(p) result.stdout.fnmatch_lines(["xxx42xxx"]) @@ -623,7 +622,7 @@ def test_disabled_capture_fixture( self, pytester: Pytester, fixture: str, no_capture: bool ) -> None: pytester.makepyfile( - """\ + f"""\ def test_disabled({fixture}): print('captured before') with {fixture}.disabled(): @@ -633,9 +632,7 @@ def test_disabled({fixture}): def test_normal(): print('test_normal executed') - """.format( - fixture=fixture - ) + """ ) args = ("-s",) if no_capture else () result = pytester.runpytest_subprocess(*args) @@ -680,7 +677,7 @@ def test_fixture_use_by_other_fixtures(self, pytester: Pytester, fixture) -> Non """Ensure that capsys and capfd can be used by other fixtures during setup and teardown.""" pytester.makepyfile( - """\ + f"""\ import sys import pytest @@ -702,9 +699,7 @@ def test_captured_print(captured_print): out, err = captured_print assert out == 'stdout contents begin\\n' assert err == 'stderr contents begin\\n' - """.format( - fixture=fixture - ) + """ ) result = pytester.runpytest_subprocess() result.stdout.fnmatch_lines(["*1 passed*"]) @@ -717,7 +712,7 @@ def test_fixture_use_by_other_fixtures_teardown( ) -> None: """Ensure we can access setup and teardown buffers from teardown when using capsys/capfd (##3033)""" pytester.makepyfile( - """\ + f"""\ import sys import pytest import os @@ -734,9 +729,7 @@ def fix({cap}): def test_a(fix): print("call out") sys.stderr.write("call err\\n") - """.format( - cap=cap - ) + """ ) reprec = pytester.inline_run() reprec.assertoutcome(passed=1) @@ -1048,16 +1041,12 @@ def test_simple_resume_suspend(self) -> None: pytest.raises(AssertionError, cap.suspend) assert repr(cap) == ( - "".format( - cap.targetfd_save, cap.tmpfile - ) + f"" ) # Should not crash with missing "_old". assert isinstance(cap.syscapture, capture.SysCapture) assert repr(cap.syscapture) == ( - " _state='done' tmpfile={!r}>".format( - cap.syscapture.tmpfile - ) + f" _state='done' tmpfile={cap.syscapture.tmpfile!r}>" ) def test_capfd_sys_stdout_mode(self, capfd) -> None: @@ -1198,7 +1187,6 @@ class TestTeeStdCapture(TestStdCapture): def test_capturing_error_recursive(self) -> None: r"""For TeeStdCapture since we passthrough stderr/stdout, cap1 should get all output, while cap2 should only get "cap2\n".""" - with self.getcapture() as cap1: print("cap1") with self.getcapture() as cap2: @@ -1393,28 +1381,27 @@ def test_capture_again(): def test_capturing_and_logging_fundamentals(pytester: Pytester, method: str) -> None: # here we check a fundamental feature p = pytester.makepyfile( - """ + f""" import sys, os, logging from _pytest import capture cap = capture.MultiCapture( in_=None, out=None, - err=capture.%s, + err=capture.{method}, ) cap.start_capturing() logging.warning("hello1") outerr = cap.readouterr() - print("suspend, captured %%s" %%(outerr,)) + print("suspend, captured %s" %(outerr,)) logging.warning("hello2") cap.pop_outerr_to_orig() logging.warning("hello3") outerr = cap.readouterr() - print("suspend2, captured %%s" %% (outerr,)) + print("suspend2, captured %s" % (outerr,)) """ - % (method,) ) result = pytester.runpython(p) result.stdout.fnmatch_lines( @@ -1580,16 +1567,16 @@ def test_capture_with_live_logging( # capture should work with live cli logging pytester.makepyfile( - """ + f""" import logging import sys logger = logging.getLogger(__name__) - def test_capture({0}): + def test_capture({capture_fixture}): print("hello") sys.stderr.write("world\\n") - captured = {0}.readouterr() + captured = {capture_fixture}.readouterr() assert captured.out == "hello\\n" assert captured.err == "world\\n" @@ -1597,11 +1584,9 @@ def test_capture({0}): print("next") logging.info("something") - captured = {0}.readouterr() + captured = {capture_fixture}.readouterr() assert captured.out == "next\\n" - """.format( - capture_fixture - ) + """ ) result = pytester.runpytest_subprocess("--log-cli-level=INFO") diff --git a/testing/test_collection.py b/testing/test_collection.py index be65169f75c..1cb553e5066 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -1,12 +1,11 @@ import os +from pathlib import Path import pprint import shutil import sys import textwrap -from pathlib import Path from typing import List -import pytest from _pytest.config import ExitCode from _pytest.fixtures import FixtureRequest from _pytest.main import _in_venv @@ -16,6 +15,7 @@ from _pytest.pathlib import symlink_or_skip from _pytest.pytester import HookRecorder from _pytest.pytester import Pytester +import pytest def ensure_file(file_path: Path) -> Path: @@ -1281,21 +1281,19 @@ def test_collect_with_chdir_during_import(pytester: Pytester) -> None: subdir = pytester.mkdir("sub") pytester.path.joinpath("conftest.py").write_text( textwrap.dedent( - """ + f""" import os - os.chdir(%r) + os.chdir({str(subdir)!r}) """ - % (str(subdir),) ), encoding="utf-8", ) pytester.makepyfile( - """ + f""" def test_1(): import os - assert os.getcwd() == %r + assert os.getcwd() == {str(subdir)!r} """ - % (str(subdir),) ) result = pytester.runpytest() result.stdout.fnmatch_lines(["*1 passed in*"]) @@ -1638,13 +1636,11 @@ def test_conftest(self, pytester: Pytester) -> None: pytester.makepyfile( **{ "tests/conftest.py": "", - "tests/test_foo.py": """ + "tests/test_foo.py": f""" import sys def test_check(): assert r"{tests_dir}" not in sys.path - """.format( - tests_dir=tests_dir - ), + """, } ) result = pytester.runpytest("-v", "--import-mode=importlib") diff --git a/testing/test_compat.py b/testing/test_compat.py index 27c6db95bbf..bc63ebc8fed 100644 --- a/testing/test_compat.py +++ b/testing/test_compat.py @@ -1,12 +1,11 @@ import enum -import sys from functools import cached_property from functools import partial from functools import wraps +import sys from typing import TYPE_CHECKING from typing import Union -import pytest from _pytest.compat import _PytestWrapper from _pytest.compat import assert_never from _pytest.compat import get_real_func @@ -15,6 +14,8 @@ from _pytest.compat import safe_isclass from _pytest.outcomes import OutcomeException from _pytest.pytester import Pytester +import pytest + if TYPE_CHECKING: from typing_extensions import Literal diff --git a/testing/test_config.py b/testing/test_config.py index a1cbfc35e70..4f7fd79a854 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1,10 +1,10 @@ import dataclasses import importlib.metadata import os +from pathlib import Path import re import sys import textwrap -from pathlib import Path from typing import Any from typing import Dict from typing import List @@ -14,7 +14,6 @@ from typing import Union import _pytest._code -import pytest from _pytest.config import _get_plugin_specs_as_list from _pytest.config import _iter_rewritable_modules from _pytest.config import _strtobool @@ -31,6 +30,7 @@ from _pytest.monkeypatch import MonkeyPatch from _pytest.pathlib import absolutepath from _pytest.pytester import Pytester +import pytest class TestParseIni: @@ -50,12 +50,10 @@ def test_getcfg_and_config( monkeypatch.chdir(sub) (tmp_path / filename).write_text( textwrap.dedent( - """\ + f"""\ [{section}] name = value - """.format( - section=section - ) + """ ), encoding="utf-8", ) @@ -125,12 +123,10 @@ def test_tox_ini_wrong_version(self, pytester: Pytester) -> None: def test_ini_names(self, pytester: Pytester, name, section) -> None: pytester.path.joinpath(name).write_text( textwrap.dedent( - """ + f""" [{section}] minversion = 3.36 - """.format( - section=section - ) + """ ), encoding="utf-8", ) @@ -864,7 +860,6 @@ def test_addini_default_values(self, pytester: Pytester) -> None: """Tests the default values for configuration based on config type """ - pytester.makeconftest( """ def pytest_addoption(parser): @@ -1621,11 +1616,9 @@ def test_override_ini_names(self, pytester: Pytester, name: str) -> None: section = "[pytest]" if name != "setup.cfg" else "[tool:pytest]" pytester.path.joinpath(name).write_text( textwrap.dedent( - """ + f""" {section} - custom = 1.0""".format( - section=section - ) + custom = 1.0""" ), encoding="utf-8", ) @@ -2039,7 +2032,6 @@ def test_pytest_plugins_in_non_top_level_conftest_unsupported_pyargs( self, pytester: Pytester, use_pyargs: bool ) -> None: """When using --pyargs, do not emit the warning about non-top-level conftest warnings (#4039, #4044)""" - files = { "src/pkg/__init__.py": "", "src/pkg/conftest.py": "", @@ -2054,9 +2046,9 @@ def test_pytest_plugins_in_non_top_level_conftest_unsupported_pyargs( 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_conftest.py b/testing/test_conftest.py index cfc2d577b53..6a0d567ac41 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -1,6 +1,6 @@ import os -import textwrap from pathlib import Path +import textwrap from typing import cast from typing import Dict from typing import Generator @@ -9,13 +9,13 @@ from typing import Sequence from typing import Union -import pytest from _pytest.config import ExitCode from _pytest.config import PytestPluginManager from _pytest.monkeypatch import MonkeyPatch from _pytest.pathlib import symlink_or_skip from _pytest.pytester import Pytester from _pytest.tmpdir import TempPathFactory +import pytest def ConftestWithSetinitial(path) -> PytestPluginManager: diff --git a/testing/test_debugging.py b/testing/test_debugging.py index e20375ea87b..dced97dd4d8 100644 --- a/testing/test_debugging.py +++ b/testing/test_debugging.py @@ -3,10 +3,11 @@ from typing import List import _pytest._code -import pytest from _pytest.debugging import _validate_usepdb_cls from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest + _ENVIRON_PYTHONBREAKPOINT = os.environ.get("PYTHONBREAKPOINT", "") @@ -1185,7 +1186,7 @@ def test_2(): def test_pdb_suspends_fixture_capturing(pytester: Pytester, fixture: str) -> None: """Using "-s" with pytest should suspend/resume fixture capturing.""" p1 = pytester.makepyfile( - """ + f""" def test_inner({fixture}): import sys @@ -1200,9 +1201,7 @@ def test_inner({fixture}): out, err = {fixture}.readouterr() assert out =="out_inner_before\\nout_inner_after\\n" assert err =="err_inner_before\\nerr_inner_after\\n" - """.format( - fixture=fixture - ) + """ ) child = pytester.spawn_pytest(str(p1) + " -s") @@ -1275,7 +1274,6 @@ def runcall(self, *args, **kwds): def test_raises_bdbquit_with_eoferror(pytester: Pytester) -> None: """It is not guaranteed that DontReadFromInput's read is called.""" - p1 = pytester.makepyfile( """ def input_without_read(*args, **kwargs): diff --git a/testing/test_doctest.py b/testing/test_doctest.py index f4d3155c435..abe407eb8d2 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -1,11 +1,10 @@ import inspect +from pathlib import Path import sys import textwrap -from pathlib import Path from typing import Callable from typing import Optional -import pytest from _pytest.doctest import _get_checker from _pytest.doctest import _is_main_py from _pytest.doctest import _is_mocked @@ -15,6 +14,7 @@ from _pytest.doctest import DoctestModule from _pytest.doctest import DoctestTextfile from _pytest.pytester import Pytester +import pytest class TestDoctests: @@ -182,19 +182,15 @@ def test_multiple_patterns(self, pytester: Pytester): def test_encoding(self, pytester, test_string, encoding): """Test support for doctest_encoding ini option.""" pytester.makeini( - """ + f""" [pytest] - doctest_encoding={} - """.format( - encoding - ) - ) - doctest = """ - >>> "{}" - {} - """.format( - test_string, repr(test_string) + doctest_encoding={encoding} + """ ) + doctest = f""" + >>> "{test_string}" + {repr(test_string)} + """ fn = pytester.path / "test_encoding.txt" fn.write_text(doctest, encoding=encoding) @@ -901,23 +897,19 @@ def test_allow_unicode(self, pytester, config_mode): comment = "#doctest: +ALLOW_UNICODE" pytester.maketxtfile( - test_doc=""" + test_doc=f""" >>> b'12'.decode('ascii') {comment} '12' - """.format( - comment=comment - ) + """ ) pytester.makepyfile( - foo=""" + foo=f""" def foo(): ''' >>> b'12'.decode('ascii') {comment} '12' ''' - """.format( - comment=comment - ) + """ ) reprec = pytester.inline_run("--doctest-modules") reprec.assertoutcome(passed=2) @@ -940,23 +932,19 @@ def test_allow_bytes(self, pytester, config_mode): comment = "#doctest: +ALLOW_BYTES" pytester.maketxtfile( - test_doc=""" + test_doc=f""" >>> b'foo' {comment} 'foo' - """.format( - comment=comment - ) + """ ) pytester.makepyfile( - foo=""" + foo=f""" def foo(): ''' >>> b'foo' {comment} 'foo' ''' - """.format( - comment=comment - ) + """ ) reprec = pytester.inline_run("--doctest-modules") reprec.assertoutcome(passed=2) @@ -1033,7 +1021,7 @@ def test_number_precision(self, pytester, config_mode): comment = "#doctest: +NUMBER" pytester.maketxtfile( - test_doc=""" + test_doc=f""" Scalars: @@ -1085,9 +1073,7 @@ def test_number_precision(self, pytester, config_mode): >>> 'abc' {comment} 'abc' >>> None {comment} - """.format( - comment=comment - ) + """ ) reprec = pytester.inline_run() reprec.assertoutcome(passed=1) @@ -1115,12 +1101,10 @@ def test_number_precision(self, pytester, config_mode): ) def test_number_non_matches(self, pytester, expression, output): pytester.maketxtfile( - test_doc=""" + test_doc=f""" >>> {expression} #doctest: +NUMBER {output} - """.format( - expression=expression, output=output - ) + """ ) reprec = pytester.inline_run() reprec.assertoutcome(passed=0, failed=1) @@ -1301,15 +1285,13 @@ def test_fixture_scopes(self, pytester, scope, enable_doctest): See #1057 and #1100. """ pytester.makeconftest( - """ + f""" import pytest @pytest.fixture(autouse=True, scope="{scope}") def auto(request): return 99 - """.format( - scope=scope - ) + """ ) pytester.makepyfile( test_1=''' @@ -1337,15 +1319,13 @@ def test_fixture_module_doctest_scopes( See #1057 and #1100. """ pytester.makeconftest( - """ + f""" import pytest @pytest.fixture(autouse={autouse}, scope="{scope}") def auto(request): return 99 - """.format( - scope=scope, autouse=autouse - ) + """ ) if use_fixture_in_doctest: pytester.maketxtfile( @@ -1371,7 +1351,7 @@ def test_auto_use_request_attributes(self, pytester, scope): behave as expected when requested for a doctest item. """ pytester.makeconftest( - """ + f""" import pytest @pytest.fixture(autouse=True, scope="{scope}") @@ -1383,9 +1363,7 @@ def auto(request): if "{scope}" == 'function': assert request.function is None return 99 - """.format( - scope=scope - ) + """ ) pytester.maketxtfile( test_doc=""" @@ -1408,16 +1386,14 @@ def test_namespace_doctestfile(self, pytester, scope): simple text file doctest """ pytester.makeconftest( - """ + f""" import pytest import contextlib @pytest.fixture(autouse=True, scope="{scope}") def add_contextlib(doctest_namespace): doctest_namespace['cl'] = contextlib - """.format( - scope=scope - ) + """ ) p = pytester.maketxtfile( """ @@ -1435,16 +1411,14 @@ def test_namespace_pyfile(self, pytester, scope): simple Python file docstring doctest """ pytester.makeconftest( - """ + f""" import pytest import contextlib @pytest.fixture(autouse=True, scope="{scope}") def add_contextlib(doctest_namespace): doctest_namespace['cl'] = contextlib - """.format( - scope=scope - ) + """ ) p = pytester.makepyfile( """ @@ -1547,16 +1521,14 @@ def test_doctest_report_invalid(self, pytester: Pytester): def test_doctest_mock_objects_dont_recurse_missbehaved(mock_module, pytester: Pytester): pytest.importorskip(mock_module) pytester.makepyfile( - """ + f""" from {mock_module} import call class Example(object): ''' >>> 1 + 1 2 ''' - """.format( - mock_module=mock_module - ) + """ ) result = pytester.runpytest("--doctest-modules") result.stdout.fnmatch_lines(["* 1 passed *"]) @@ -1571,7 +1543,7 @@ def __getattr__(self, _): "stop", [None, _is_mocked, lambda f: None, lambda f: False, lambda f: True] ) def test_warning_on_unwrap_of_broken_object( - stop: Optional[Callable[[object], object]] + stop: Optional[Callable[[object], object]], ) -> None: bad_instance = Broken() assert inspect.unwrap.__module__ == "inspect" @@ -1605,7 +1577,7 @@ def test_is_setup_py_different_encoding(tmp_path: Path, mod: str) -> None: setup_py = tmp_path.joinpath("setup.py") contents = ( "# -*- coding: cp1252 -*-\n" - 'from {} import setup; setup(name="foo", description="€")\n'.format(mod) + f'from {mod} import setup; setup(name="foo", description="€")\n' ) setup_py.write_bytes(contents.encode("cp1252")) assert _is_setup_py(setup_py) diff --git a/testing/test_error_diffs.py b/testing/test_error_diffs.py index 6494a44fb12..f290eb1679f 100644 --- a/testing/test_error_diffs.py +++ b/testing/test_error_diffs.py @@ -5,8 +5,9 @@ """ -import pytest from _pytest.pytester import Pytester +import pytest + TESTCASES = [ pytest.param( diff --git a/testing/test_faulthandler.py b/testing/test_faulthandler.py index 0446241b064..ae7ff093f19 100644 --- a/testing/test_faulthandler.py +++ b/testing/test_faulthandler.py @@ -1,8 +1,8 @@ import io import sys -import pytest from _pytest.pytester import Pytester +import pytest def test_enabled(pytester: Pytester) -> None: diff --git a/testing/test_findpaths.py b/testing/test_findpaths.py index 8287de603ed..554ffd324d6 100644 --- a/testing/test_findpaths.py +++ b/testing/test_findpaths.py @@ -2,12 +2,12 @@ from pathlib import Path from textwrap import dedent -import pytest from _pytest.config import UsageError from _pytest.config.findpaths import get_common_ancestor from _pytest.config.findpaths import get_dirs_from_args from _pytest.config.findpaths import is_fs_root from _pytest.config.findpaths import load_config_dict_from_file +import pytest class TestLoadConfigDictFromFile: diff --git a/testing/test_helpconfig.py b/testing/test_helpconfig.py index ba89d0c4acf..2bb10615af6 100644 --- a/testing/test_helpconfig.py +++ b/testing/test_helpconfig.py @@ -1,6 +1,6 @@ -import pytest from _pytest.config import ExitCode from _pytest.pytester import Pytester +import pytest def test_version_verbose(pytester: Pytester, pytestconfig, monkeypatch) -> None: diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index b0c2d1c6d4e..de84dfec04f 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -1,7 +1,7 @@ -import os -import platform from datetime import datetime +import os from pathlib import Path +import platform from typing import cast from typing import List from typing import Optional @@ -12,7 +12,6 @@ import xmlschema -import pytest from _pytest.config import Config from _pytest.junitxml import bin_xml_escape from _pytest.junitxml import LogXML @@ -22,6 +21,7 @@ from _pytest.reports import BaseReport from _pytest.reports import TestReport from _pytest.stash import Stash +import pytest @pytest.fixture(scope="session") @@ -1282,12 +1282,10 @@ def test_record_fixtures_without_junitxml( pytester: Pytester, fixture_name: str ) -> None: pytester.makepyfile( - """ + f""" def test_record({fixture_name}): {fixture_name}("foo", "bar") - """.format( - fixture_name=fixture_name - ) + """ ) result = pytester.runpytest() assert result.ret == 0 @@ -1335,7 +1333,7 @@ def test_record_fixtures_xunit2( """ ) pytester.makepyfile( - """ + f""" import pytest @pytest.fixture @@ -1343,9 +1341,7 @@ def other({fixture_name}): {fixture_name}("bar", 1) def test_record({fixture_name}, other): {fixture_name}("foo", "<1"); - """.format( - fixture_name=fixture_name - ) + """ ) result, dom = run_and_parse(family=None) @@ -1355,10 +1351,8 @@ def test_record({fixture_name}, other): "*test_record_fixtures_xunit2.py:6:*record_xml_attribute is an experimental feature" ) expected_lines = [ - "*test_record_fixtures_xunit2.py:6:*{fixture_name} is incompatible " - "with junit_family 'xunit2' (use 'legacy' or 'xunit1')".format( - fixture_name=fixture_name - ) + f"*test_record_fixtures_xunit2.py:6:*{fixture_name} is incompatible " + "with junit_family 'xunit2' (use 'legacy' or 'xunit1')" ] result.stdout.fnmatch_lines(expected_lines) @@ -1610,13 +1604,11 @@ def test_set_suite_name( ) -> None: if suite_name: pytester.makeini( - """ + f""" [pytest] junit_suite_name={suite_name} - junit_family={family} - """.format( - suite_name=suite_name, family=xunit_family - ) + junit_family={xunit_family} + """ ) expected = suite_name else: @@ -1697,14 +1689,12 @@ def test_logging_passing_tests_disabled_does_not_log_test_output( pytester: Pytester, run_and_parse: RunAndParse, xunit_family: str ) -> None: pytester.makeini( - """ + f""" [pytest] junit_log_passing_tests=False junit_logging=system-out - junit_family={family} - """.format( - family=xunit_family - ) + junit_family={xunit_family} + """ ) pytester.makepyfile( """ @@ -1734,13 +1724,11 @@ def test_logging_passing_tests_disabled_logs_output_for_failing_test_issue5430( xunit_family: str, ) -> None: pytester.makeini( - """ + f""" [pytest] junit_log_passing_tests=False - junit_family={family} - """.format( - family=xunit_family - ) + junit_family={xunit_family} + """ ) pytester.makepyfile( """ diff --git a/testing/test_legacypath.py b/testing/test_legacypath.py index b4fd1bf2c22..a0c6d754186 100644 --- a/testing/test_legacypath.py +++ b/testing/test_legacypath.py @@ -1,10 +1,10 @@ from pathlib import Path -import pytest from _pytest.compat import LEGACY_PATH from _pytest.fixtures import TopRequest from _pytest.legacypath import TempdirFactory from _pytest.legacypath import Testdir +import pytest def test_item_fspath(pytester: pytest.Pytester) -> None: diff --git a/testing/test_link_resolve.py b/testing/test_link_resolve.py index 1ac3afd09e8..a35d1b7ad6b 100644 --- a/testing/test_link_resolve.py +++ b/testing/test_link_resolve.py @@ -1,10 +1,10 @@ +from contextlib import contextmanager import os.path +from pathlib import Path +from string import ascii_lowercase import subprocess import sys import textwrap -from contextlib import contextmanager -from pathlib import Path -from string import ascii_lowercase from _pytest.pytester import Pytester diff --git a/testing/test_main.py b/testing/test_main.py index 3c8998c1a35..b887bd32475 100644 --- a/testing/test_main.py +++ b/testing/test_main.py @@ -1,16 +1,16 @@ import argparse import os +from pathlib import Path import re import sys -from pathlib import Path from typing import Optional -import pytest from _pytest.config import ExitCode from _pytest.config import UsageError from _pytest.main import resolve_collection_argument from _pytest.main import validate_basetemp from _pytest.pytester import Pytester +import pytest @pytest.mark.parametrize( @@ -24,19 +24,17 @@ def test_wrap_session_notify_exception(ret_exc, pytester: Pytester) -> None: returncode, exc = ret_exc c1 = pytester.makeconftest( - """ + f""" import pytest def pytest_sessionstart(): - raise {exc}("boom") + raise {exc.__name__}("boom") def pytest_internalerror(excrepr, excinfo): returncode = {returncode!r} if returncode is not False: pytest.exit("exiting after %s..." % excinfo.typename, returncode={returncode!r}) - """.format( - returncode=returncode, exc=exc.__name__ - ) + """ ) result = pytester.runpytest() if returncode: @@ -84,13 +82,11 @@ def test_wrap_session_exit_sessionfinish( returncode: Optional[int], pytester: Pytester ) -> None: pytester.makeconftest( - """ + f""" import pytest def pytest_sessionfinish(): pytest.exit(reason="exit_pytest_sessionfinish", returncode={returncode}) - """.format( - returncode=returncode - ) + """ ) result = pytester.runpytest() if returncode: diff --git a/testing/test_mark.py b/testing/test_mark.py index 6f86afa194d..6237d6566e6 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -4,13 +4,13 @@ from typing import Optional from unittest import mock -import pytest from _pytest.config import ExitCode from _pytest.mark import MarkGenerator from _pytest.mark.structures import EMPTY_PARAMETERSET_OPTION from _pytest.nodes import Collector from _pytest.nodes import Node from _pytest.pytester import Pytester +import pytest class TestMark: @@ -933,12 +933,10 @@ def test_parameterset_for_parametrize_marks( ) -> None: if mark is not None: pytester.makeini( - """ + f""" [pytest] - {}={} - """.format( - EMPTY_PARAMETERSET_OPTION, mark - ) + {EMPTY_PARAMETERSET_OPTION}={mark} + """ ) config = pytester.parseconfig() @@ -958,12 +956,10 @@ def test_parameterset_for_parametrize_marks( def test_parameterset_for_fail_at_collect(pytester: Pytester) -> None: pytester.makeini( - """ + f""" [pytest] - {}=fail_at_collect - """.format( - EMPTY_PARAMETERSET_OPTION - ) + {EMPTY_PARAMETERSET_OPTION}=fail_at_collect + """ ) config = pytester.parseconfig() diff --git a/testing/test_mark_expression.py b/testing/test_mark_expression.py index f3643e7b409..a7a9cf3044a 100644 --- a/testing/test_mark_expression.py +++ b/testing/test_mark_expression.py @@ -1,8 +1,8 @@ from typing import Callable -import pytest from _pytest.mark.expression import Expression from _pytest.mark.expression import ParseError +import pytest def evaluate(input: str, matcher: Callable[[str], bool]) -> bool: diff --git a/testing/test_monkeypatch.py b/testing/test_monkeypatch.py index 8175b5f0fad..a49f874a682 100644 --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -1,15 +1,15 @@ import os +from pathlib import Path import re import sys import textwrap -from pathlib import Path from typing import Dict from typing import Generator from typing import Type -import pytest from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest @pytest.fixture diff --git a/testing/test_nodes.py b/testing/test_nodes.py index 84c377cf990..9151a5403c0 100644 --- a/testing/test_nodes.py +++ b/testing/test_nodes.py @@ -1,16 +1,16 @@ -import re -import warnings from pathlib import Path +import re from typing import cast from typing import List from typing import Type +import warnings -import pytest from _pytest import nodes from _pytest.compat import legacy_path from _pytest.outcomes import OutcomeException from _pytest.pytester import Pytester from _pytest.warning_types import PytestWarning +import pytest @pytest.mark.parametrize( @@ -63,7 +63,6 @@ def test_subclassing_both_item_and_collector_deprecated( Verifies we warn on diamond inheritance as well as correctly managing legacy inheritance constructors with missing args as found in plugins. """ - # We do not expect any warnings messages to issued during class definition. with warnings.catch_warnings(): warnings.simplefilter("error") diff --git a/testing/test_nose.py b/testing/test_nose.py index 7ec4026f249..07644b66d49 100644 --- a/testing/test_nose.py +++ b/testing/test_nose.py @@ -1,5 +1,5 @@ -import pytest from _pytest.pytester import Pytester +import pytest def setup_module(mod): diff --git a/testing/test_parseopt.py b/testing/test_parseopt.py index 1b80883ee0f..4f93c43804f 100644 --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -1,16 +1,16 @@ import argparse import locale import os +from pathlib import Path import shlex import subprocess import sys -from pathlib import Path -import pytest from _pytest.config import argparsing as parseopt from _pytest.config.exceptions import UsageError from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest @pytest.fixture @@ -317,9 +317,7 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None: # http://stackoverflow.com/q/12589419/1307905 # so we use bash fp.write( - 'COMP_WORDBREAKS="$COMP_WORDBREAKS" {} -m pytest 8>&1 9>&2'.format( - shlex.quote(sys.executable) - ) + f'COMP_WORDBREAKS="$COMP_WORDBREAKS" {shlex.quote(sys.executable)} -m pytest 8>&1 9>&2' ) # alternative would be extended Pytester.{run(),_run(),popen()} to be able # to handle a keyword argument env that replaces os.environ in popen or @@ -337,9 +335,7 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None: pytest.skip("argcomplete not available") elif not result.stdout.str(): pytest.skip( - "bash provided no output on stdout, argcomplete not available? (stderr={!r})".format( - result.stderr.str() - ) + f"bash provided no output on stdout, argcomplete not available? (stderr={result.stderr.str()!r})" ) else: result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) diff --git a/testing/test_pastebin.py b/testing/test_pastebin.py index 86b231f8b5e..44958498af5 100644 --- a/testing/test_pastebin.py +++ b/testing/test_pastebin.py @@ -3,9 +3,9 @@ from typing import List from typing import Union -import pytest from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest class TestPasteCapture: diff --git a/testing/test_pathlib.py b/testing/test_pathlib.py index 3e1d2265bb7..921b926e8ad 100644 --- a/testing/test_pathlib.py +++ b/testing/test_pathlib.py @@ -1,16 +1,15 @@ import errno import os.path +from pathlib import Path import pickle import sys -import unittest.mock -from pathlib import Path from textwrap import dedent from types import ModuleType from typing import Any from typing import Generator from typing import Iterator +import unittest.mock -import pytest from _pytest.monkeypatch import MonkeyPatch from _pytest.pathlib import bestrelpath from _pytest.pathlib import commonpath @@ -30,6 +29,7 @@ from _pytest.pathlib import visit from _pytest.pytester import Pytester from _pytest.tmpdir import TempPathFactory +import pytest class TestFNMatcherPort: diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 8bafde33846..1adf3185028 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -4,7 +4,6 @@ import types from typing import List -import pytest from _pytest.config import Config from _pytest.config import ExitCode from _pytest.config import PytestPluginManager @@ -13,6 +12,7 @@ from _pytest.monkeypatch import MonkeyPatch from _pytest.pathlib import import_path from _pytest.pytester import Pytester +import pytest @pytest.fixture diff --git a/testing/test_pytester.py b/testing/test_pytester.py index 6fc6bd24519..340015f6eaf 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -5,16 +5,16 @@ from types import ModuleType from typing import List -import _pytest.pytester as pytester_mod -import pytest from _pytest.config import ExitCode from _pytest.config import PytestPluginManager from _pytest.monkeypatch import MonkeyPatch +import _pytest.pytester as pytester_mod from _pytest.pytester import HookRecorder from _pytest.pytester import LineMatcher from _pytest.pytester import Pytester from _pytest.pytester import SysModulesSnapshot from _pytest.pytester import SysPathsSnapshot +import pytest def test_make_hook_recorder(pytester: Pytester) -> None: @@ -704,15 +704,13 @@ def test_spawn_uses_tmphome(pytester: Pytester) -> None: pytester._monkeypatch.setenv("CUSTOMENV", "42") p1 = pytester.makepyfile( - """ + f""" import os def test(): assert os.environ["HOME"] == {tmphome!r} assert os.environ["CUSTOMENV"] == "42" - """.format( - tmphome=tmphome - ) + """ ) child = pytester.spawn_pytest(str(p1)) out = child.read() diff --git a/testing/test_python_path.py b/testing/test_python_path.py index dfef0f3fecf..d5ca954dd20 100644 --- a/testing/test_python_path.py +++ b/testing/test_python_path.py @@ -4,8 +4,8 @@ from typing import List from typing import Optional -import pytest from _pytest.pytester import Pytester +import pytest @pytest.fixture() diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 19a1cd534f1..3e9e8e9fdba 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -1,11 +1,11 @@ -import warnings from typing import List from typing import Optional from typing import Type +import warnings -import pytest from _pytest.pytester import Pytester from _pytest.recwarn import WarningsRecorder +import pytest def test_recwarn_stacklevel(recwarn: WarningsRecorder) -> None: diff --git a/testing/test_reports.py b/testing/test_reports.py index a101eb4578b..8f32932d896 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -1,7 +1,6 @@ from typing import Sequence from typing import Union -import pytest from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionRepr from _pytest.config import Config @@ -9,6 +8,7 @@ from _pytest.python_api import approx from _pytest.reports import CollectReport from _pytest.reports import TestReport +import pytest class TestReportSerialization: @@ -278,7 +278,7 @@ def test_chained_exceptions( ) -> None: """Check serialization/deserialization of report objects containing chained exceptions (#5786)""" pytester.makepyfile( - """ + f""" def foo(): raise ValueError('value error') def test_a(): @@ -286,18 +286,16 @@ def test_a(): foo() except ValueError as e: raise RuntimeError('runtime error') from e - if {error_during_import}: + if {report_class is CollectReport}: test_a() - """.format( - error_during_import=report_class is CollectReport - ) + """ ) 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/testing/test_runner.py b/testing/test_runner.py index 26f5b9a0bc2..769ce149234 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -1,15 +1,14 @@ +from functools import partial import inspect import os +from pathlib import Path import sys import types -from functools import partial -from pathlib import Path from typing import Dict from typing import List from typing import Tuple from typing import Type -import pytest from _pytest import outcomes from _pytest import reports from _pytest import runner @@ -19,6 +18,8 @@ from _pytest.monkeypatch import MonkeyPatch from _pytest.outcomes import OutcomeException from _pytest.pytester import Pytester +import pytest + if sys.version_info[:2] < (3, 11): from exceptiongroup import ExceptionGroup diff --git a/testing/test_runner_xunit.py b/testing/test_runner_xunit.py index 901703ed727..058841b0804 100644 --- a/testing/test_runner_xunit.py +++ b/testing/test_runner_xunit.py @@ -2,8 +2,8 @@ from typing import List -import pytest from _pytest.pytester import Pytester +import pytest def test_module_and_function_setup(pytester: Pytester) -> None: @@ -255,7 +255,7 @@ def test_setup_teardown_function_level_with_optional_argument( sys, "trace_setups_teardowns", trace_setups_teardowns, raising=False ) p = pytester.makepyfile( - """ + f""" import pytest import sys @@ -276,9 +276,7 @@ def teardown_method(self, {arg}): trace('teardown_method') def test_method_1(self): pass def test_method_2(self): pass - """.format( - arg=arg - ) + """ ) result = pytester.inline_run(p) result.assertoutcome(passed=4) diff --git a/testing/test_scope.py b/testing/test_scope.py index 09ee1343a80..1727c2ee1bb 100644 --- a/testing/test_scope.py +++ b/testing/test_scope.py @@ -1,7 +1,7 @@ import re -import pytest from _pytest.scope import Scope +import pytest def test_ordering() -> None: diff --git a/testing/test_session.py b/testing/test_session.py index 803bbed5434..297190bda2f 100644 --- a/testing/test_session.py +++ b/testing/test_session.py @@ -1,7 +1,7 @@ -import pytest from _pytest.config import ExitCode from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest class SessionTests: diff --git a/testing/test_setuponly.py b/testing/test_setuponly.py index fe4bdc514eb..78922ea580d 100644 --- a/testing/test_setuponly.py +++ b/testing/test_setuponly.py @@ -1,8 +1,8 @@ import sys -import pytest from _pytest.config import ExitCode from _pytest.pytester import Pytester +import pytest @pytest.fixture(params=["--setup-only", "--setup-plan", "--setup-show"], scope="module") diff --git a/testing/test_skipping.py b/testing/test_skipping.py index b2ad4b0cf6d..e1cf4c2b008 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -1,12 +1,12 @@ import sys import textwrap -import pytest from _pytest.pytester import Pytester from _pytest.runner import runtestprotocol from _pytest.skipping import evaluate_skip_marks from _pytest.skipping import evaluate_xfail_marks from _pytest.skipping import pytest_runtest_setup +import pytest class TestEvaluation: @@ -75,14 +75,13 @@ def test_marked_one_arg_twice(self, pytester: Pytester) -> None: ] for i in range(0, 2): item = pytester.getitem( - """ + f""" import pytest - %s - %s + {lines[i]} + {lines[(i + 1) % 2]} def test_func(): pass """ - % (lines[i], lines[(i + 1) % 2]) ) skipped = evaluate_skip_marks(item) assert skipped @@ -606,7 +605,7 @@ def test_xfail_raises( @pytest.mark.xfail(raises=%s) def test_raises(): raise %s() - """ + """ # noqa: UP031 (python syntax issues) % (expected, actual) ) result = pytester.runpytest(p) @@ -908,7 +907,7 @@ def test_skipif_reporting(self, pytester: Pytester, params) -> None: @pytest.mark.skipif(%(params)s) def test_that(): assert 0 - """ + """ # noqa: UP031 (python syntax issues) % dict(params=params) ) result = pytester.runpytest(p, "-s", "-rs") @@ -934,15 +933,13 @@ def test_skipif_reporting_multiple( self, pytester: Pytester, marker, msg1, msg2 ) -> None: pytester.makepyfile( - test_foo=""" + test_foo=f""" import pytest @pytest.mark.{marker}(False, reason='first_condition') @pytest.mark.{marker}(True, reason='second_condition') def test_foobar(): assert 1 - """.format( - marker=marker - ) + """ ) result = pytester.runpytest("-s", "-rsxX") result.stdout.fnmatch_lines( diff --git a/testing/test_stash.py b/testing/test_stash.py index 2c9df4832e4..e523c4e6f2b 100644 --- a/testing/test_stash.py +++ b/testing/test_stash.py @@ -1,6 +1,6 @@ -import pytest from _pytest.stash import Stash from _pytest.stash import StashKey +import pytest def test_stash() -> None: diff --git a/testing/test_stepwise.py b/testing/test_stepwise.py index 85e38c7d568..156121b1246 100644 --- a/testing/test_stepwise.py +++ b/testing/test_stepwise.py @@ -1,10 +1,10 @@ from pathlib import Path -import pytest from _pytest.cacheprovider import Cache from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester from _pytest.stepwise import STEPWISE_CACHE_DIR +import pytest @pytest.fixture diff --git a/testing/test_terminal.py b/testing/test_terminal.py index b42eb9f4c88..a326dc21f9a 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -1,11 +1,11 @@ """Terminal reporting of the full testing process.""" import collections +from io import StringIO import os +from pathlib import Path import sys import textwrap -from io import StringIO -from pathlib import Path from types import SimpleNamespace from typing import cast from typing import Dict @@ -14,10 +14,8 @@ import pluggy -import _pytest.config -import _pytest.terminal -import pytest from _pytest._io.wcwidth import wcswidth +import _pytest.config from _pytest.config import Config from _pytest.config import ExitCode from _pytest.monkeypatch import MonkeyPatch @@ -25,6 +23,7 @@ from _pytest.reports import BaseReport from _pytest.reports import CollectReport from _pytest.reports import TestReport +import _pytest.terminal from _pytest.terminal import _folded_skips from _pytest.terminal import _format_trimmed from _pytest.terminal import _get_line_with_reprcrash_message @@ -32,6 +31,8 @@ from _pytest.terminal import _plugin_nameversions from _pytest.terminal import getreportopt from _pytest.terminal import TerminalReporter +import pytest + DistInfo = collections.namedtuple("DistInfo", ["project_name", "version"]) @@ -156,7 +157,6 @@ def test_report_collect_after_half_a_second( self, pytester: Pytester, monkeypatch: MonkeyPatch ) -> None: """Test for "collecting" being updated after 0.5s""" - pytester.makepyfile( **{ "test1.py": """ @@ -869,13 +869,7 @@ def test_passes(): result.stdout.fnmatch_lines( [ "*===== test session starts ====*", - "platform %s -- Python %s*pytest-%s**pluggy-%s" - % ( - sys.platform, - verinfo, - pytest.__version__, - pluggy.__version__, - ), + f"platform {sys.platform} -- Python {verinfo}*pytest-{pytest.__version__}**pluggy-{pluggy.__version__}", "*test_header_trailer_info.py .*", "=* 1 passed*in *.[0-9][0-9]s *=", ] @@ -896,13 +890,7 @@ def test_passes(): result = pytester.runpytest("--no-header") verinfo = ".".join(map(str, sys.version_info[:3])) result.stdout.no_fnmatch_line( - "platform %s -- Python %s*pytest-%s**pluggy-%s" - % ( - sys.platform, - verinfo, - pytest.__version__, - pluggy.__version__, - ) + f"platform {sys.platform} -- Python {verinfo}*pytest-{pytest.__version__}**pluggy-{pluggy.__version__}" ) if request.config.pluginmanager.list_plugin_distinfo(): result.stdout.no_fnmatch_line("plugins: *") @@ -943,12 +931,10 @@ def test_header_absolute_testpath( tests = pytester.path.joinpath("tests") tests.mkdir() pytester.makepyprojecttoml( - """ + f""" [tool.pytest.ini_options] - testpaths = ['{}'] - """.format( - tests - ) + testpaths = ['{tests}'] + """ ) result = pytester.runpytest() result.stdout.fnmatch_lines( @@ -2413,7 +2399,12 @@ def markup(self, word: str, **markup: str): __tracebackhide__ = True if msg: rep.longrepr.reprcrash.message = msg # type: ignore - actual = _get_line_with_reprcrash_message(config, rep(), DummyTerminalWriter(), {}) # type: ignore + actual = _get_line_with_reprcrash_message( + config, # type: ignore[arg-type] + rep(), # type: ignore[arg-type] + DummyTerminalWriter(), # type: ignore[arg-type] + {}, + ) assert actual == expected if actual != f"{mocked_verbose_word} {mocked_pos}": diff --git a/testing/test_threadexception.py b/testing/test_threadexception.py index fd9a091ccc9..99837b94e8a 100644 --- a/testing/test_threadexception.py +++ b/testing/test_threadexception.py @@ -1,5 +1,5 @@ -import pytest from _pytest.pytester import Pytester +import pytest @pytest.mark.filterwarnings("default::pytest.PytestUnhandledThreadExceptionWarning") diff --git a/testing/test_tmpdir.py b/testing/test_tmpdir.py index 1e1446af127..7c046db46c9 100644 --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -1,15 +1,14 @@ import dataclasses import os +from pathlib import Path import stat import sys -import warnings -from pathlib import Path from typing import Callable from typing import cast from typing import List from typing import Union +import warnings -import pytest from _pytest import pathlib from _pytest.config import Config from _pytest.monkeypatch import MonkeyPatch @@ -23,6 +22,7 @@ from _pytest.pytester import Pytester from _pytest.tmpdir import get_user from _pytest.tmpdir import TempPathFactory +import pytest def test_tmp_path_fixture(pytester: Pytester) -> None: @@ -241,12 +241,10 @@ def test_fixt(fixt): def test_mktemp(pytester: Pytester, basename: str, is_ok: bool) -> None: mytemp = pytester.mkdir("mytemp") p = pytester.makepyfile( - """ + f""" def test_abs_path(tmp_path_factory): - tmp_path_factory.mktemp('{}', numbered=False) - """.format( - basename - ) + tmp_path_factory.mktemp('{basename}', numbered=False) + """ ) result = pytester.runpytest(p, "--basetemp=%s" % mytemp) @@ -337,7 +335,6 @@ def test_tmp_path_fallback_uid_not_found(pytester: Pytester) -> None: """Test that tmp_path works even if the current process's user id does not correspond to a valid user. """ - pytester.makepyfile( """ def test_some(tmp_path): diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 24f954051d6..60772127431 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -2,10 +2,10 @@ import sys from typing import List -import pytest from _pytest.config import ExitCode from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +import pytest def test_simple_unittest(pytester: Pytester) -> None: @@ -352,22 +352,21 @@ def test_teareddown(): @pytest.mark.parametrize("type", ["Error", "Failure"]) def test_testcase_adderrorandfailure_defers(pytester: Pytester, type: str) -> None: pytester.makepyfile( - """ + f""" from unittest import TestCase import pytest class MyTestCase(TestCase): def run(self, result): excinfo = pytest.raises(ZeroDivisionError, lambda: 0/0) try: - result.add%s(self, excinfo._excinfo) + result.add{type}(self, excinfo._excinfo) except KeyboardInterrupt: raise except: - pytest.fail("add%s should not raise") + pytest.fail("add{type} should not raise") def test_hello(self): pass """ - % (type, type) ) result = pytester.runpytest() result.stdout.no_fnmatch_line("*should not raise*") @@ -399,14 +398,13 @@ def from_exc_info(cls, *args, **kwargs): mp.setattr(_pytest._code, 'ExceptionInfo', FakeExceptionInfo) try: excinfo = excinfo._excinfo - result.add%(type)s(self, excinfo) + result.add{type}(self, excinfo) finally: mp.undo() def test_hello(self): pass - """ - % locals() + """.format(**locals()) ) result = pytester.runpytest() result.stdout.fnmatch_lines( @@ -833,7 +831,7 @@ def test_passing_test_is_fail(self): @pytest.mark.parametrize("stmt", ["return", "yield"]) def test_unittest_setup_interaction(pytester: Pytester, stmt: str) -> None: pytester.makepyfile( - """ + f""" import unittest import pytest class MyTestCase(unittest.TestCase): @@ -855,9 +853,7 @@ def test_method2(self): def test_classattr(self): assert self.__class__.hello == "world" - """.format( - stmt=stmt - ) + """ ) result = pytester.runpytest() result.stdout.fnmatch_lines(["*3 passed*"]) @@ -1062,7 +1058,7 @@ def pytest_collection_modifyitems(items): ) pytester.makepyfile( - """ + f""" import pytest import {module} @@ -1081,9 +1077,7 @@ def test_two(self): assert self.fixture2 - """.format( - module=module, base=base - ) + """ ) result = pytester.runpytest("-s") @@ -1252,7 +1246,7 @@ def test_pdb_teardown_skipped_for_functions( monkeypatch.setattr(pytest, "track_pdb_teardown_skipped", tracked, raising=False) pytester.makepyfile( - """ + f""" import unittest import pytest @@ -1268,9 +1262,7 @@ def tearDown(self): def test_1(self): pass - """.format( - mark=mark - ) + """ ) result = pytester.runpytest_inprocess("--pdb") result.stdout.fnmatch_lines("* 1 skipped in *") @@ -1289,7 +1281,7 @@ def test_pdb_teardown_skipped_for_classes( monkeypatch.setattr(pytest, "track_pdb_teardown_skipped", tracked, raising=False) pytester.makepyfile( - """ + f""" import unittest import pytest @@ -1305,9 +1297,7 @@ def tearDown(self): def test_1(self): pass - """.format( - mark=mark - ) + """ ) result = pytester.runpytest_inprocess("--pdb") result.stdout.fnmatch_lines("* 1 skipped in *") diff --git a/testing/test_unraisableexception.py b/testing/test_unraisableexception.py index d255adb2b91..1657cfe4a84 100644 --- a/testing/test_unraisableexception.py +++ b/testing/test_unraisableexception.py @@ -1,7 +1,8 @@ import sys -import pytest from _pytest.pytester import Pytester +import pytest + PYPY = hasattr(sys, "pypy_version_info") diff --git a/testing/test_warning_types.py b/testing/test_warning_types.py index 5f69439ef3e..cab50d8baa4 100644 --- a/testing/test_warning_types.py +++ b/testing/test_warning_types.py @@ -1,8 +1,8 @@ import inspect -import pytest from _pytest import warning_types from _pytest.pytester import Pytester +import pytest @pytest.mark.parametrize( @@ -42,5 +42,6 @@ def test(): def test_warn_explicit_for_annotates_errors_with_location(): with pytest.raises(Warning, match="(?m)test\n at .*python_api.py:\\d+"): warning_types.warn_explicit_for( - pytest.raises, warning_types.PytestWarning("test") # type: ignore + pytest.raises, # type: ignore[arg-type] + warning_types.PytestWarning("test"), ) diff --git a/testing/test_warnings.py b/testing/test_warnings.py index 96ecad6f647..86c81ed0ac6 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -1,13 +1,14 @@ import os import sys -import warnings from typing import List from typing import Optional from typing import Tuple +import warnings -import pytest from _pytest.fixtures import FixtureRequest from _pytest.pytester import Pytester +import pytest + WARNINGS_SUMMARY_HEADER = "warnings summary" @@ -19,13 +20,11 @@ def pyfile_with_warnings(pytester: Pytester, request: FixtureRequest) -> str: test_name = request.function.__name__ module_name = test_name.lstrip("test_") + "_module" test_file = pytester.makepyfile( - """ + f""" import {module_name} def test_func(): assert {module_name}.foo() == 1 - """.format( - module_name=module_name - ), + """, **{ module_name: """ import warnings @@ -436,7 +435,7 @@ class TestDeprecationWarningsByDefault: def create_file(self, pytester: Pytester, mark="") -> None: pytester.makepyfile( - """ + f""" import pytest, warnings warnings.warn(DeprecationWarning("collection")) @@ -444,9 +443,7 @@ def create_file(self, pytester: Pytester, mark="") -> None: {mark} def test_foo(): warnings.warn(PendingDeprecationWarning("test run")) - """.format( - mark=mark - ) + """ ) @pytest.mark.parametrize("customize_filters", [True, False]) diff --git a/tox.ini b/tox.ini index ec73d21165d..f291ee25801 100644 --- a/tox.ini +++ b/tox.ini @@ -184,27 +184,3 @@ usedevelop = True deps = pypandoc commands = python scripts/generate-gh-release-notes.py {posargs} - -[flake8] -max-line-length = 120 -extend-ignore = - ; whitespace before ':' - E203 - ; Missing Docstrings - D100,D101,D102,D103,D104,D105,D106,D107 - ; Whitespace Issues - D202,D203,D204,D205,D209,D213 - ; Quotes Issues - 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] -; This config mimics what reorder-python-imports does. -force_single_line = 1 -known_localfolder = pytest,_pytest -known_third_party = test_source,test_excinfo -force_alphabetical_sort_within_sections = 1