Merge pull request #11901 from Pierre-Sassoulas/migrate-from-isort-to-ruff

Migrate from ``autoflake``, ``black``, ``isort``, ``pyupgrade``, ``flake8`` and ``pydocstyle``, to ``ruff``
This commit is contained in:
Pierre Sassoulas 2024-02-02 09:42:07 +01:00 committed by GitHub
commit bdfc5c80d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
150 changed files with 803 additions and 973 deletions

View File

@ -23,9 +23,11 @@ afc607cfd81458d4e4f3b1f3cf8cc931b933907e
5f95dce95602921a70bfbc7d8de2f7712c5e4505 5f95dce95602921a70bfbc7d8de2f7712c5e4505
# ran pyupgrade-docs again # ran pyupgrade-docs again
75d0b899bbb56d6849e9d69d83a9426ed3f43f8b 75d0b899bbb56d6849e9d69d83a9426ed3f43f8b
# move argument parser to own file # move argument parser to own file
c9df77cbd6a365dcb73c39618e4842711817e871 c9df77cbd6a365dcb73c39618e4842711817e871
# Replace reorder-python-imports by isort due to black incompatibility (#11896) # Replace reorder-python-imports by isort due to black incompatibility (#11896)
8b54596639f41dfac070030ef20394b9001fe63c 8b54596639f41dfac070030ef20394b9001fe63c
# Run blacken-docs with black's 2024's style
4546d5445aaefe6a03957db028c263521dfb5c4b
# Migration to ruff / ruff format
4588653b2497ed25976b7aaff225b889fb476756

View File

@ -1,14 +1,10 @@
repos: repos:
- repo: https://github.com/psf/black - repo: https://github.com/astral-sh/ruff-pre-commit
rev: 24.1.1 rev: "v0.1.15"
hooks: hooks:
- id: black - id: ruff
args: [--safe, --quiet] args: ["--fix"]
- repo: https://github.com/asottile/blacken-docs - id: ruff-format
rev: 1.16.0
hooks:
- id: blacken-docs
additional_dependencies: [black==24.1.1]
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0 rev: v4.5.0
hooks: hooks:
@ -20,33 +16,11 @@ repos:
- id: debug-statements - id: debug-statements
exclude: _pytest/(debugging|hookspec).py exclude: _pytest/(debugging|hookspec).py
language_version: python3 language_version: python3
- repo: https://github.com/PyCQA/autoflake - repo: https://github.com/adamchainz/blacken-docs
rev: v2.2.1 rev: 1.16.0
hooks: hooks:
- id: autoflake - id: blacken-docs
name: autoflake additional_dependencies: [black==24.1.1]
args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"]
language: python
files: \.py$
- repo: https://github.com/PyCQA/flake8
rev: 7.0.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
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/asottile/setup-cfg-fmt - repo: https://github.com/asottile/setup-cfg-fmt
rev: v2.5.0 rev: v2.5.0
hooks: hooks:

View File

@ -27,9 +27,6 @@
:target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main
:alt: pre-commit.ci status :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 .. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg
:target: https://www.codetriage.com/pytest-dev/pytest :target: https://www.codetriage.com/pytest-dev/pytest

View File

@ -1,5 +1,6 @@
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
import cProfile import cProfile
import pstats import pstats

View File

@ -4,6 +4,7 @@
# FastFilesCompleter 0.7383 1.0760 # FastFilesCompleter 0.7383 1.0760
import timeit import timeit
imports = [ imports = [
"from argcomplete.completers import FilesCompleter as completer", "from argcomplete.completers import FilesCompleter as completer",
"from _pytest._argcomplete import FastFilesCompleter as completer", "from _pytest._argcomplete import FastFilesCompleter as completer",

View File

@ -1,5 +1,6 @@
import pytest import pytest
SKIP = True SKIP = True

View File

@ -1,5 +1,6 @@
from unittest import TestCase # noqa: F401 from unittest import TestCase # noqa: F401
for i in range(15000): for i in range(15000):
exec( exec(
f""" f"""

View File

@ -23,6 +23,7 @@ from typing import TYPE_CHECKING
from _pytest import __version__ as version from _pytest import __version__ as version
if TYPE_CHECKING: if TYPE_CHECKING:
import sphinx.application import sphinx.application

View File

@ -2,6 +2,7 @@ import os.path
import pytest import pytest
mydir = os.path.dirname(__file__) mydir = os.path.dirname(__file__)

View File

@ -1,6 +1,7 @@
import os.path import os.path
import shutil import shutil
failure_demo = os.path.join(os.path.dirname(__file__), "failure_demo.py") failure_demo = os.path.join(os.path.dirname(__file__), "failure_demo.py")
pytest_plugins = ("pytester",) pytest_plugins = ("pytester",)

View File

@ -7,6 +7,7 @@ import textwrap
import pytest import pytest
pythonlist = ["python3.9", "python3.10", "python3.11"] pythonlist = ["python3.9", "python3.10", "python3.11"]
@ -32,14 +33,12 @@ class Python:
dumpfile = self.picklefile.with_name("dump.py") dumpfile = self.picklefile.with_name("dump.py")
dumpfile.write_text( dumpfile.write_text(
textwrap.dedent( textwrap.dedent(
r""" rf"""
import pickle import pickle
f = open({!r}, 'wb') f = open({str(self.picklefile)!r}, 'wb')
s = pickle.dump({!r}, f, protocol=2) s = pickle.dump({obj!r}, f, protocol=2)
f.close() f.close()
""".format( """
str(self.picklefile), obj
)
) )
) )
subprocess.run((self.pythonpath, str(dumpfile)), check=True) subprocess.run((self.pythonpath, str(dumpfile)), check=True)
@ -48,17 +47,15 @@ class Python:
loadfile = self.picklefile.with_name("load.py") loadfile = self.picklefile.with_name("load.py")
loadfile.write_text( loadfile.write_text(
textwrap.dedent( textwrap.dedent(
r""" rf"""
import pickle import pickle
f = open({!r}, 'rb') f = open({str(self.picklefile)!r}, 'rb')
obj = pickle.load(f) obj = pickle.load(f)
f.close() f.close()
res = eval({!r}) res = eval({expression!r})
if not res: if not res:
raise SystemExit(1) raise SystemExit(1)
""".format( """
str(self.picklefile), expression
)
) )
) )
print(loadfile) print(loadfile)

View File

@ -1,5 +1,6 @@
import pytest import pytest
xfail = pytest.mark.xfail xfail = pytest.mark.xfail

View File

@ -3,6 +3,7 @@ from pathlib import Path
import requests import requests
issues_url = "https://api.github.com/repos/pytest-dev/pytest/issues" issues_url = "https://api.github.com/repos/pytest-dev/pytest/issues"

View File

@ -123,3 +123,55 @@ target-version = ['py38']
[tool.check-wheel-contents] [tool.check-wheel-contents]
# W009: Wheel contains multiple toplevel library entries # W009: Wheel contains multiple toplevel library entries
ignore = "W009" 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
]
[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

View File

@ -8,9 +8,9 @@ our CHANGELOG) into Markdown (which is required by GitHub Releases).
Requires Python3.6+. Requires Python3.6+.
""" """
from pathlib import Path
import re import re
import sys import sys
from pathlib import Path
from typing import Sequence from typing import Sequence
import pypandoc import pypandoc

View File

@ -14,8 +14,8 @@ After that, it will create a release using the `release` tox environment, and pu
`pytest bot <pytestbot@gmail.com>` commit author. `pytest bot <pytestbot@gmail.com>` commit author.
""" """
import argparse import argparse
import re
from pathlib import Path from pathlib import Path
import re
from subprocess import check_call from subprocess import check_call
from subprocess import check_output from subprocess import check_output
from subprocess import run from subprocess import run

View File

@ -1,6 +1,6 @@
# mypy: disallow-untyped-defs # mypy: disallow-untyped-defs
import sys
from subprocess import call from subprocess import call
import sys
def main() -> int: def main() -> int:

View File

@ -11,13 +11,14 @@ from typing import TypedDict
import packaging.version import packaging.version
import platformdirs import platformdirs
import tabulate
import wcwidth
from requests_cache import CachedResponse from requests_cache import CachedResponse
from requests_cache import CachedSession from requests_cache import CachedSession
from requests_cache import OriginalResponse from requests_cache import OriginalResponse
from requests_cache import SQLiteCache from requests_cache import SQLiteCache
import tabulate
from tqdm import tqdm from tqdm import tqdm
import wcwidth
FILE_HEAD = r""" FILE_HEAD = r"""
.. Note this file is autogenerated by scripts/update-plugin-list.py - usually weekly via github action .. 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 force refresh in case of last serial mismatch
""" """
response = session.get(f"https://pypi.org/pypi/{name}/json") response = session.get(f"https://pypi.org/pypi/{name}/json")
if int(response.headers.get("X-PyPI-Last-Serial", -1)) != last_serial: if int(response.headers.get("X-PyPI-Last-Serial", -1)) != last_serial:
response = session.get(f"https://pypi.org/pypi/{name}/json", refresh=True) response = session.get(f"https://pypi.org/pypi/{name}/json", refresh=True)
@ -184,7 +184,6 @@ def iter_plugins() -> Iterator[PluginInfo]:
def plugin_definitions(plugins: Iterable[PluginInfo]) -> Iterator[str]: def plugin_definitions(plugins: Iterable[PluginInfo]) -> Iterator[str]:
"""Return RST for the plugin list that fits better on a vertical page.""" """Return RST for the plugin list that fits better on a vertical page."""
for plugin in plugins: for plugin in plugins:
yield dedent( yield dedent(
f""" f"""

View File

@ -63,9 +63,9 @@ If things do not work right away:
""" """
import argparse import argparse
from glob import glob
import os import os
import sys import sys
from glob import glob
from typing import Any from typing import Any
from typing import List from typing import List
from typing import Optional from typing import Optional

View File

@ -10,6 +10,7 @@ from .code import TracebackEntry
from .source import getrawcode from .source import getrawcode
from .source import Source from .source import Source
__all__ = [ __all__ = [
"Code", "Code",
"ExceptionInfo", "ExceptionInfo",

View File

@ -2,14 +2,14 @@
import ast import ast
import dataclasses import dataclasses
import inspect import inspect
import os
import re
import sys
import traceback
from inspect import CO_VARARGS from inspect import CO_VARARGS
from inspect import CO_VARKEYWORDS from inspect import CO_VARKEYWORDS
from io import StringIO from io import StringIO
import os
from pathlib import Path from pathlib import Path
import re
import sys
import traceback
from traceback import format_exception_only from traceback import format_exception_only
from types import CodeType from types import CodeType
from types import FrameType from types import FrameType
@ -51,6 +51,7 @@ from _pytest.deprecated import check_ispytest
from _pytest.pathlib import absolutepath from _pytest.pathlib import absolutepath
from _pytest.pathlib import bestrelpath from _pytest.pathlib import bestrelpath
if sys.version_info[:2] < (3, 11): if sys.version_info[:2] < (3, 11):
from exceptiongroup import BaseExceptionGroup from exceptiongroup import BaseExceptionGroup
@ -278,9 +279,9 @@ class TracebackEntry:
Mostly for internal use. Mostly for internal use.
""" """
tbh: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]] = ( tbh: Union[
False bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]
) ] = False
for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals): for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals):
# in normal cases, f_locals and f_globals are dictionaries # in normal cases, f_locals and f_globals are dictionaries
# however via `exec(...)` / `eval(...)` they can be other types # however via `exec(...)` / `eval(...)` they can be other types
@ -377,10 +378,12 @@ class Traceback(List[TracebackEntry]):
return self return self
@overload @overload
def __getitem__(self, key: "SupportsIndex") -> TracebackEntry: ... def __getitem__(self, key: "SupportsIndex") -> TracebackEntry:
...
@overload @overload
def __getitem__(self, key: slice) -> "Traceback": ... def __getitem__(self, key: slice) -> "Traceback":
...
def __getitem__( def __getitem__(
self, key: Union["SupportsIndex", slice] self, key: Union["SupportsIndex", slice]
@ -485,9 +488,10 @@ class ExceptionInfo(Generic[E]):
.. versionadded:: 7.4 .. versionadded:: 7.4
""" """
assert ( assert exception.__traceback__, (
exception.__traceback__ "Exceptions passed to ExcInfo.from_exception(...)"
), "Exceptions passed to ExcInfo.from_exception(...) must have a non-None __traceback__." " must have a non-None __traceback__."
)
exc_info = (type(exception), exception, exception.__traceback__) exc_info = (type(exception), exception, exception.__traceback__)
return cls.from_exc_info(exc_info, exprinfo) return cls.from_exc_info(exc_info, exprinfo)
@ -586,9 +590,7 @@ class ExceptionInfo(Generic[E]):
def __repr__(self) -> str: def __repr__(self) -> str:
if self._excinfo is None: if self._excinfo is None:
return "<ExceptionInfo for raises contextmanager>" return "<ExceptionInfo for raises contextmanager>"
return "<{} {} tblen={}>".format( return f"<{self.__class__.__name__} {saferepr(self._excinfo[1])} tblen={len(self.traceback)}>"
self.__class__.__name__, saferepr(self._excinfo[1]), len(self.traceback)
)
def exconly(self, tryshort: bool = False) -> str: def exconly(self, tryshort: bool = False) -> str:
"""Return the exception as a string. """Return the exception as a string.
@ -1016,13 +1018,8 @@ class FormattedExcinfo:
extraline: Optional[str] = ( extraline: Optional[str] = (
"!!! Recursion error detected, but an error occurred locating the origin of recursion.\n" "!!! 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" " The following exception happened when comparing locals in the stack frame:\n"
" {exc_type}: {exc_msg}\n" f" {type(e).__name__}: {str(e)}\n"
" Displaying first and last {max_frames} stack frames out of {total}." f" Displaying first and last {max_frames} stack frames out of {len(traceback)}."
).format(
exc_type=type(e).__name__,
exc_msg=str(e),
max_frames=max_frames,
total=len(traceback),
) )
# Type ignored because adding two instances of a List subtype # Type ignored because adding two instances of a List subtype
# currently incorrectly has type List instead of the subtype. # currently incorrectly has type List instead of the subtype.
@ -1054,13 +1051,13 @@ class FormattedExcinfo:
# full support for exception groups added to ExceptionInfo. # full support for exception groups added to ExceptionInfo.
# See https://github.com/pytest-dev/pytest/issues/9159 # See https://github.com/pytest-dev/pytest/issues/9159
if isinstance(e, BaseExceptionGroup): if isinstance(e, BaseExceptionGroup):
reprtraceback: Union[ReprTracebackNative, ReprTraceback] = ( reprtraceback: Union[
ReprTracebackNative( ReprTracebackNative, ReprTraceback
traceback.format_exception( ] = ReprTracebackNative(
type(excinfo_.value), traceback.format_exception(
excinfo_.value, type(excinfo_.value),
excinfo_.traceback[0]._rawentry, excinfo_.value,
) excinfo_.traceback[0]._rawentry,
) )
) )
else: else:
@ -1229,7 +1226,6 @@ class ReprEntry(TerminalRepr):
the "E" prefix) using syntax highlighting, taking care to not highlighting the ">" the "E" prefix) using syntax highlighting, taking care to not highlighting the ">"
character, as doing so might break line continuations. character, as doing so might break line continuations.
""" """
if not self.lines: if not self.lines:
return return

View File

@ -1,11 +1,10 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import ast import ast
from bisect import bisect_right
import inspect import inspect
import textwrap import textwrap
import tokenize import tokenize
import types import types
import warnings
from bisect import bisect_right
from typing import Iterable from typing import Iterable
from typing import Iterator from typing import Iterator
from typing import List from typing import List
@ -13,6 +12,7 @@ from typing import Optional
from typing import overload from typing import overload
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
import warnings
class Source: class Source:
@ -47,10 +47,12 @@ class Source:
__hash__ = None # type: ignore __hash__ = None # type: ignore
@overload @overload
def __getitem__(self, key: int) -> str: ... def __getitem__(self, key: int) -> str:
...
@overload @overload
def __getitem__(self, key: slice) -> "Source": ... def __getitem__(self, key: slice) -> "Source":
...
def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]: def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]:
if isinstance(key, int): if isinstance(key, int):

View File

@ -1,6 +1,7 @@
from .terminalwriter import get_terminal_width from .terminalwriter import get_terminal_width
from .terminalwriter import TerminalWriter from .terminalwriter import TerminalWriter
__all__ = [ __all__ = [
"TerminalWriter", "TerminalWriter",
"get_terminal_width", "get_terminal_width",

View File

@ -15,9 +15,9 @@
# useful, thank small children who sleep at night. # useful, thank small children who sleep at night.
import collections as _collections import collections as _collections
import dataclasses as _dataclasses import dataclasses as _dataclasses
from io import StringIO as _StringIO
import re import re
import types as _types import types as _types
from io import StringIO as _StringIO
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict

View File

@ -19,8 +19,8 @@ def _format_repr_exception(exc: BaseException, obj: object) -> str:
raise raise
except BaseException as exc: except BaseException as exc:
exc_info = f"unpresentable exception ({_try_repr_or_str(exc)})" exc_info = f"unpresentable exception ({_try_repr_or_str(exc)})"
return "<[{} raised in repr()] {} object at 0x{:x}>".format( return (
exc_info, type(obj).__name__, id(obj) 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 This function is a wrapper around the Repr/reprlib functionality of the
stdlib. stdlib.
""" """
return SafeRepr(maxsize, use_ascii).repr(obj) return SafeRepr(maxsize, use_ascii).repr(obj)

View File

@ -11,6 +11,7 @@ from typing import TextIO
from .wcwidth import wcswidth from .wcwidth import wcswidth
# This code was initially copied from py 1.8.1, file _io/terminalwriter.py. # This code was initially copied from py 1.8.1, file _io/terminalwriter.py.
@ -183,9 +184,7 @@ class TerminalWriter:
""" """
if indents and len(indents) != len(lines): if indents and len(indents) != len(lines):
raise ValueError( raise ValueError(
"indents size ({}) should have same size as lines ({})".format( f"indents size ({len(indents)}) should have same size as lines ({len(lines)})"
len(indents), len(lines)
)
) )
if not indents: if not indents:
indents = [""] * len(lines) indents = [""] * len(lines)
@ -210,8 +209,8 @@ class TerminalWriter:
from pygments.lexers.python import PythonLexer as Lexer from pygments.lexers.python import PythonLexer as Lexer
elif lexer == "diff": elif lexer == "diff":
from pygments.lexers.diff import DiffLexer as Lexer from pygments.lexers.diff import DiffLexer as Lexer
import pygments.util
from pygments import highlight from pygments import highlight
import pygments.util
except ImportError: except ImportError:
return source return source
else: else:

View File

@ -1,5 +1,5 @@
import unicodedata
from functools import lru_cache from functools import lru_cache
import unicodedata
@lru_cache(100) @lru_cache(100)

View File

@ -9,6 +9,7 @@ from typing import Callable
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import TypeVar from typing import TypeVar
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import ParamSpec from typing_extensions import ParamSpec

View File

@ -3,15 +3,11 @@
from __future__ import annotations from __future__ import annotations
import atexit import atexit
from contextlib import contextmanager
import fnmatch import fnmatch
import importlib.util import importlib.util
import io import io
import os import os
import posixpath
import sys
import uuid
import warnings
from contextlib import contextmanager
from os.path import abspath from os.path import abspath
from os.path import dirname from os.path import dirname
from os.path import exists from os.path import exists
@ -20,18 +16,23 @@ from os.path import isdir
from os.path import isfile from os.path import isfile
from os.path import islink from os.path import islink
from os.path import normpath from os.path import normpath
import posixpath
from stat import S_ISDIR from stat import S_ISDIR
from stat import S_ISLNK from stat import S_ISLNK
from stat import S_ISREG from stat import S_ISREG
import sys
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import cast from typing import cast
from typing import Literal from typing import Literal
from typing import overload from typing import overload
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import uuid
import warnings
from . import error from . import error
# Moved from local.py. # Moved from local.py.
iswin32 = sys.platform == "win32" or (getattr(os, "_name", False) == "nt") iswin32 = sys.platform == "win32" or (getattr(os, "_name", False) == "nt")
@ -204,10 +205,12 @@ class Stat:
if TYPE_CHECKING: if TYPE_CHECKING:
@property @property
def size(self) -> int: ... def size(self) -> int:
...
@property @property
def mtime(self) -> float: ... def mtime(self) -> float:
...
def __getattr__(self, name: str) -> Any: def __getattr__(self, name: str) -> Any:
return getattr(self._osstatresult, "st_" + name) return getattr(self._osstatresult, "st_" + name)
@ -674,7 +677,7 @@ class LocalPath:
else: else:
kw.setdefault("dirname", dirname) kw.setdefault("dirname", dirname)
kw.setdefault("sep", self.sep) 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 return obj
def _getbyspec(self, spec: str) -> list[str]: def _getbyspec(self, spec: str) -> list[str]:
@ -759,7 +762,10 @@ class LocalPath:
# expected "Callable[[str, Any, Any], TextIOWrapper]" [arg-type] # expected "Callable[[str, Any, Any], TextIOWrapper]" [arg-type]
# Which seems incorrect, given io.open supports the given argument types. # Which seems incorrect, given io.open supports the given argument types.
return error.checked_call( 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) return error.checked_call(open, self.strpath, mode)
@ -778,11 +784,11 @@ class LocalPath:
valid checkers:: valid checkers::
file=1 # is a file file = 1 # is a file
file=0 # is not a file (may not even exist) file = 0 # is not a file (may not even exist)
dir=1 # is a dir dir = 1 # is a dir
link=1 # is a link link = 1 # is a link
exists=1 # exists exists = 1 # exists
You can specify multiple checker definitions, for example:: You can specify multiple checker definitions, for example::
@ -960,10 +966,12 @@ class LocalPath:
return p return p
@overload @overload
def stat(self, raising: Literal[True] = ...) -> Stat: ... def stat(self, raising: Literal[True] = ...) -> Stat:
...
@overload @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: def stat(self, raising: bool = True) -> Stat | None:
"""Return an os.stat() tuple.""" """Return an os.stat() tuple."""
@ -1275,7 +1283,8 @@ class LocalPath:
# error: Argument 1 has incompatible type overloaded function; expected "Callable[[str], str]" [arg-type] # 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. # Which seems incorrect, given tempfile.mkdtemp supports the given argument types.
path = error.checked_call( 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) return cls(path)

View File

@ -16,6 +16,7 @@ from _pytest.config import hookimpl
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.nodes import Item from _pytest.nodes import Item
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.main import Session 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 reporting via the pytest_assertrepr_compare hook. This sets up this custom
comparison for the test. comparison for the test.
""" """
ihook = item.ihook ihook = item.ihook
def callbinrepr(op, left: object, right: object) -> Optional[str]: def callbinrepr(op, left: object, right: object) -> Optional[str]:

View File

@ -1,6 +1,7 @@
"""Rewrite assertion AST to produce nice error messages.""" """Rewrite assertion AST to produce nice error messages."""
import ast import ast
from collections import defaultdict
import errno import errno
import functools import functools
import importlib.abc import importlib.abc
@ -10,13 +11,12 @@ import io
import itertools import itertools
import marshal import marshal
import os import os
from pathlib import Path
from pathlib import PurePath
import struct import struct
import sys import sys
import tokenize import tokenize
import types import types
from collections import defaultdict
from pathlib import Path
from pathlib import PurePath
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
from typing import IO from typing import IO
@ -40,6 +40,7 @@ from _pytest.pathlib import absolutepath
from _pytest.pathlib import fnmatch_ex from _pytest.pathlib import fnmatch_ex
from _pytest.stash import StashKey from _pytest.stash import StashKey
# fmt: off # fmt: off
from _pytest.assertion.util import format_explanation as _format_explanation # noqa:F401, isort:skip from _pytest.assertion.util import format_explanation as _format_explanation # noqa:F401, isort:skip
# fmt:on # fmt:on
@ -671,9 +672,9 @@ class AssertionRewriter(ast.NodeVisitor):
self.enable_assertion_pass_hook = False self.enable_assertion_pass_hook = False
self.source = source self.source = source
self.scope: tuple[ast.AST, ...] = () self.scope: tuple[ast.AST, ...] = ()
self.variables_overwrite: defaultdict[tuple[ast.AST, ...], Dict[str, str]] = ( self.variables_overwrite: defaultdict[
defaultdict(dict) tuple[ast.AST, ...], Dict[str, str]
) ] = defaultdict(dict)
def run(self, mod: ast.Module) -> None: def run(self, mod: ast.Module) -> None:
"""Find all assert statements in *mod* and rewrite them.""" """Find all assert statements in *mod* and rewrite them."""
@ -1019,9 +1020,7 @@ class AssertionRewriter(ast.NodeVisitor):
] ]
): ):
pytest_temp = self.variable() pytest_temp = self.variable()
self.variables_overwrite[self.scope][ self.variables_overwrite[self.scope][v.left.target.id] = v.left # type:ignore[assignment]
v.left.target.id
] = v.left # type:ignore[assignment]
v.left.target.id = pytest_temp v.left.target.id = pytest_temp
self.push_format_context() self.push_format_context()
res, expl = self.visit(v) res, expl = self.visit(v)
@ -1065,9 +1064,7 @@ class AssertionRewriter(ast.NodeVisitor):
if isinstance(arg, ast.Name) and arg.id in self.variables_overwrite.get( if isinstance(arg, ast.Name) and arg.id in self.variables_overwrite.get(
self.scope, {} self.scope, {}
): ):
arg = self.variables_overwrite[self.scope][ arg = self.variables_overwrite[self.scope][arg.id] # type:ignore[assignment]
arg.id
] # type:ignore[assignment]
res, expl = self.visit(arg) res, expl = self.visit(arg)
arg_expls.append(expl) arg_expls.append(expl)
new_args.append(res) new_args.append(res)
@ -1075,9 +1072,7 @@ class AssertionRewriter(ast.NodeVisitor):
if isinstance( if isinstance(
keyword.value, ast.Name keyword.value, ast.Name
) and keyword.value.id in self.variables_overwrite.get(self.scope, {}): ) and keyword.value.id in self.variables_overwrite.get(self.scope, {}):
keyword.value = self.variables_overwrite[self.scope][ keyword.value = self.variables_overwrite[self.scope][keyword.value.id] # type:ignore[assignment]
keyword.value.id
] # type:ignore[assignment]
res, expl = self.visit(keyword.value) res, expl = self.visit(keyword.value)
new_kwargs.append(ast.keyword(keyword.arg, res)) new_kwargs.append(ast.keyword(keyword.arg, res))
if keyword.arg: if keyword.arg:
@ -1114,13 +1109,9 @@ class AssertionRewriter(ast.NodeVisitor):
if isinstance( if isinstance(
comp.left, ast.Name comp.left, ast.Name
) and comp.left.id in self.variables_overwrite.get(self.scope, {}): ) and comp.left.id in self.variables_overwrite.get(self.scope, {}):
comp.left = self.variables_overwrite[self.scope][ comp.left = self.variables_overwrite[self.scope][comp.left.id] # type:ignore[assignment]
comp.left.id
] # type:ignore[assignment]
if isinstance(comp.left, ast.NamedExpr): if isinstance(comp.left, ast.NamedExpr):
self.variables_overwrite[self.scope][ self.variables_overwrite[self.scope][comp.left.target.id] = comp.left # type:ignore[assignment]
comp.left.target.id
] = comp.left # type:ignore[assignment]
left_res, left_expl = self.visit(comp.left) left_res, left_expl = self.visit(comp.left)
if isinstance(comp.left, (ast.Compare, ast.BoolOp)): if isinstance(comp.left, (ast.Compare, ast.BoolOp)):
left_expl = f"({left_expl})" left_expl = f"({left_expl})"
@ -1138,9 +1129,7 @@ class AssertionRewriter(ast.NodeVisitor):
and next_operand.target.id == left_res.id and next_operand.target.id == left_res.id
): ):
next_operand.target.id = self.variable() next_operand.target.id = self.variable()
self.variables_overwrite[self.scope][ self.variables_overwrite[self.scope][left_res.id] = next_operand # type:ignore[assignment]
left_res.id
] = next_operand # type:ignore[assignment]
next_res, next_expl = self.visit(next_operand) next_res, next_expl = self.visit(next_operand)
if isinstance(next_operand, (ast.Compare, ast.BoolOp)): if isinstance(next_operand, (ast.Compare, ast.BoolOp)):
next_expl = f"({next_expl})" next_expl = f"({next_expl})"

View File

@ -11,6 +11,7 @@ from _pytest.assertion import util
from _pytest.config import Config from _pytest.config import Config
from _pytest.nodes import Item from _pytest.nodes import Item
DEFAULT_MAX_LINES = 8 DEFAULT_MAX_LINES = 8
DEFAULT_MAX_CHARS = 8 * 80 DEFAULT_MAX_CHARS = 8 * 80
USAGE_MSG = "use '-vv' to show" USAGE_MSG = "use '-vv' to show"

View File

@ -15,13 +15,14 @@ from typing import Protocol
from typing import Sequence from typing import Sequence
from unicodedata import normalize from unicodedata import normalize
import _pytest._code
from _pytest import outcomes from _pytest import outcomes
import _pytest._code
from _pytest._io.pprint import PrettyPrinter from _pytest._io.pprint import PrettyPrinter
from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr
from _pytest._io.saferepr import saferepr_unlimited from _pytest._io.saferepr import saferepr_unlimited
from _pytest.config import Config from _pytest.config import Config
# The _reprcompare attribute on the util module is used by the new assertion # The _reprcompare attribute on the util module is used by the new assertion
# interpretation code and assertion rewriter to detect this plugin was # interpretation code and assertion rewriter to detect this plugin was
# loaded and in turn call the hooks defined here as part of the # 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: if i > 42:
i -= 10 # Provide some context i -= 10 # Provide some context
explanation += [ explanation += [
"Skipping {} identical trailing " f"Skipping {i} identical trailing "
"characters in diff, use -v to show".format(i) "characters in diff, use -v to show"
] ]
left = left[:-i] left = left[:-i]
right = right[:-i] right = right[:-i]

View File

@ -32,6 +32,7 @@ from _pytest.nodes import Directory
from _pytest.nodes import File from _pytest.nodes import File
from _pytest.reports import TestReport from _pytest.reports import TestReport
README_CONTENT = """\ README_CONTENT = """\
# pytest cache directory # # pytest cache directory #
@ -368,15 +369,13 @@ class LFPlugin:
noun = "failure" if self._previously_failed_count == 1 else "failures" noun = "failure" if self._previously_failed_count == 1 else "failures"
suffix = " first" if self.config.getoption("failedfirst") else "" suffix = " first" if self.config.getoption("failedfirst") else ""
self._report_status = "rerun previous {count} {noun}{suffix}".format( self._report_status = (
count=self._previously_failed_count, suffix=suffix, noun=noun f"rerun previous {self._previously_failed_count} {noun}{suffix}"
) )
if self._skipped_files > 0: if self._skipped_files > 0:
files_noun = "file" if self._skipped_files == 1 else "files" files_noun = "file" if self._skipped_files == 1 else "files"
self._report_status += " (skipped {files} {files_noun})".format( self._report_status += f" (skipped {self._skipped_files} {files_noun})"
files=self._skipped_files, files_noun=files_noun
)
else: else:
self._report_status = "no previously failed tests, " self._report_status = "no previously failed tests, "
if self.config.getoption("last_failed_no_failures") == "none": if self.config.getoption("last_failed_no_failures") == "none":

View File

@ -4,9 +4,9 @@ import abc
import collections import collections
import contextlib import contextlib
import io import io
from io import UnsupportedOperation
import os import os
import sys import sys
from io import UnsupportedOperation
from tempfile import TemporaryFile from tempfile import TemporaryFile
from types import TracebackType from types import TracebackType
from typing import Any from typing import Any
@ -39,6 +39,7 @@ from _pytest.nodes import File
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.reports import CollectReport from _pytest.reports import CollectReport
_CaptureMethod = Literal["fd", "sys", "no", "tee-sys"] _CaptureMethod = Literal["fd", "sys", "no", "tee-sys"]
@ -790,9 +791,7 @@ class CaptureManager:
current_fixture = self._capture_fixture.request.fixturename current_fixture = self._capture_fixture.request.fixturename
requested_fixture = capture_fixture.request.fixturename requested_fixture = capture_fixture.request.fixturename
capture_fixture.request.raiseerror( capture_fixture.request.raiseerror(
"cannot use {} and {} at the same time".format( f"cannot use {requested_fixture} and {current_fixture} at the same time"
requested_fixture, current_fixture
)
) )
self._capture_fixture = capture_fixture 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] <pytest.CaptureFixture>`. Returns an instance of :class:`CaptureFixture[str] <pytest.CaptureFixture>`.
Example: Example:
.. code-block:: python .. code-block:: python
def test_output(capsys): def test_output(capsys):
@ -1016,7 +1014,6 @@ def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None,
Returns an instance of :class:`CaptureFixture[bytes] <pytest.CaptureFixture>`. Returns an instance of :class:`CaptureFixture[bytes] <pytest.CaptureFixture>`.
Example: Example:
.. code-block:: python .. code-block:: python
def test_output(capsysbinary): def test_output(capsysbinary):
@ -1044,7 +1041,6 @@ def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]:
Returns an instance of :class:`CaptureFixture[str] <pytest.CaptureFixture>`. Returns an instance of :class:`CaptureFixture[str] <pytest.CaptureFixture>`.
Example: Example:
.. code-block:: python .. code-block:: python
def test_system_echo(capfd): 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] <pytest.CaptureFixture>`. Returns an instance of :class:`CaptureFixture[bytes] <pytest.CaptureFixture>`.
Example: Example:
.. code-block:: python .. code-block:: python
def test_system_echo(capfdbinary): def test_system_echo(capfdbinary):

View File

@ -6,17 +6,18 @@ import dataclasses
import enum import enum
import functools import functools
import inspect import inspect
import os
import sys
from inspect import Parameter from inspect import Parameter
from inspect import signature from inspect import signature
import os
from pathlib import Path from pathlib import Path
import sys
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Final from typing import Final
from typing import NoReturn from typing import NoReturn
from typing import TypeVar from typing import TypeVar
_T = TypeVar("_T") _T = TypeVar("_T")
_S = TypeVar("_S") _S = TypeVar("_S")
@ -243,9 +244,7 @@ def get_real_func(obj):
from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr
raise ValueError( raise ValueError(
("could not find real function of {start}\nstopped at {current}").format( f"could not find real function of {saferepr(start_obj)}\nstopped at {saferepr(obj)}"
start=saferepr(start_obj), current=saferepr(obj)
)
) )
if isinstance(obj, functools.partial): if isinstance(obj, functools.partial):
obj = obj.func obj = obj.func

View File

@ -5,18 +5,17 @@ import collections.abc
import copy import copy
import dataclasses import dataclasses
import enum import enum
from functools import lru_cache
import glob import glob
import importlib.metadata import importlib.metadata
import inspect import inspect
import os import os
from pathlib import Path
import re import re
import shlex import shlex
import sys import sys
import types
import warnings
from functools import lru_cache
from pathlib import Path
from textwrap import dedent from textwrap import dedent
import types
from types import FunctionType from types import FunctionType
from typing import Any from typing import Any
from typing import Callable from typing import Callable
@ -37,6 +36,7 @@ from typing import Tuple
from typing import Type from typing import Type
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Union from typing import Union
import warnings
from pluggy import HookimplMarker from pluggy import HookimplMarker
from pluggy import HookimplOpts from pluggy import HookimplOpts
@ -44,15 +44,15 @@ from pluggy import HookspecMarker
from pluggy import HookspecOpts from pluggy import HookspecOpts
from pluggy import PluginManager from pluggy import PluginManager
import _pytest._code
import _pytest.deprecated
import _pytest.hookspec
from .exceptions import PrintHelp as PrintHelp from .exceptions import PrintHelp as PrintHelp
from .exceptions import UsageError as UsageError from .exceptions import UsageError as UsageError
from .findpaths import determine_setup from .findpaths import determine_setup
import _pytest._code
from _pytest._code import ExceptionInfo from _pytest._code import ExceptionInfo
from _pytest._code import filter_traceback from _pytest._code import filter_traceback
from _pytest._io import TerminalWriter from _pytest._io import TerminalWriter
import _pytest.deprecated
import _pytest.hookspec
from _pytest.outcomes import fail from _pytest.outcomes import fail
from _pytest.outcomes import Skipped from _pytest.outcomes import Skipped
from _pytest.pathlib import absolutepath from _pytest.pathlib import absolutepath
@ -65,6 +65,7 @@ from _pytest.stash import Stash
from _pytest.warning_types import PytestConfigWarning from _pytest.warning_types import PytestConfigWarning
from _pytest.warning_types import warn_explicit_for from _pytest.warning_types import warn_explicit_for
if TYPE_CHECKING: if TYPE_CHECKING:
from .argparsing import Argument from .argparsing import Argument
from .argparsing import Parser from .argparsing import Parser
@ -813,7 +814,7 @@ class PytestPluginManager(PluginManager):
def _get_plugin_specs_as_list( def _get_plugin_specs_as_list(
specs: Union[None, types.ModuleType, str, Sequence[str]] specs: Union[None, types.ModuleType, str, Sequence[str]],
) -> List[str]: ) -> List[str]:
"""Parse a plugins specification into a list of plugin names.""" """Parse a plugins specification into a list of plugin names."""
# None means empty. # None means empty.
@ -1374,12 +1375,7 @@ class Config:
if Version(minver) > Version(pytest.__version__): if Version(minver) > Version(pytest.__version__):
raise pytest.UsageError( raise pytest.UsageError(
"%s: 'minversion' requires pytest-%s, actual pytest-%s'" f"{self.inipath}: 'minversion' requires pytest-{minver}, actual pytest-{pytest.__version__}'"
% (
self.inipath,
minver,
pytest.__version__,
)
) )
def _validate_config_options(self) -> None: def _validate_config_options(self) -> None:
@ -1614,9 +1610,7 @@ class Config:
key, user_ini_value = ini_config.split("=", 1) key, user_ini_value = ini_config.split("=", 1)
except ValueError as e: except ValueError as e:
raise UsageError( raise UsageError(
"-o/--override-ini expects option=value style (got: {!r}).".format( f"-o/--override-ini expects option=value style (got: {ini_config!r})."
ini_config
)
) from e ) from e
else: else:
if key == name: if key == name:
@ -1674,7 +1668,6 @@ class Config:
can be used to explicitly use the global verbosity level. can be used to explicitly use the global verbosity level.
Example: Example:
.. code-block:: ini .. code-block:: ini
# content of pytest.ini # content of pytest.ini

View File

@ -1,8 +1,8 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import argparse import argparse
from gettext import gettext
import os import os
import sys import sys
from gettext import gettext
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import cast from typing import cast
@ -21,6 +21,7 @@ import _pytest._io
from _pytest.config.exceptions import UsageError from _pytest.config.exceptions import UsageError
from _pytest.deprecated import check_ispytest from _pytest.deprecated import check_ispytest
FILE_OR_DIR = "file_or_dir" FILE_OR_DIR = "file_or_dir"
@ -216,7 +217,7 @@ class Parser:
def get_ini_default_for_type( 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: ) -> Any:
""" """
Used by addini to get the default value for a given ini-option type, when Used by addini to get the default value for a given ini-option type, when
@ -448,7 +449,7 @@ class MyOptionParser(argparse.ArgumentParser):
) -> Optional[Tuple[Optional[argparse.Action], str, Optional[str]]]: ) -> Optional[Tuple[Optional[argparse.Action], str, Optional[str]]]:
if not arg_string: if not arg_string:
return None return None
if not arg_string[0] in self.prefix_chars: if arg_string[0] not in self.prefix_chars:
return None return None
if arg_string in self._option_string_actions: if arg_string in self._option_string_actions:
action = self._option_string_actions[arg_string] action = self._option_string_actions[arg_string]

View File

@ -1,6 +1,6 @@
import os import os
import sys
from pathlib import Path from pathlib import Path
import sys
from typing import Dict from typing import Dict
from typing import Iterable from typing import Iterable
from typing import List 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. Return None if the file does not contain valid pytest configuration.
""" """
# Configuration from ini files are obtained from the [pytest] section, if present. # Configuration from ini files are obtained from the [pytest] section, if present.
if filepath.suffix == ".ini": if filepath.suffix == ".ini":
iniconfig = _parse_ini_config(filepath) iniconfig = _parse_ini_config(filepath)
@ -213,9 +212,7 @@ def determine_setup(
rootdir = absolutepath(os.path.expandvars(rootdir_cmd_arg)) rootdir = absolutepath(os.path.expandvars(rootdir_cmd_arg))
if not rootdir.is_dir(): if not rootdir.is_dir():
raise UsageError( raise UsageError(
"Directory '{}' not found. Check your '--rootdir' option.".format( f"Directory '{rootdir}' not found. Check your '--rootdir' option."
rootdir
)
) )
assert rootdir is not None assert rootdir is not None
return rootdir, inipath, inicfg or {} return rootdir, inipath, inicfg or {}

View File

@ -4,7 +4,6 @@ import argparse
import functools import functools
import sys import sys
import types import types
import unittest
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Generator from typing import Generator
@ -14,6 +13,7 @@ from typing import Tuple
from typing import Type from typing import Type
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Union from typing import Union
import unittest
from _pytest import outcomes from _pytest import outcomes
from _pytest._code import ExceptionInfo from _pytest._code import ExceptionInfo
@ -26,6 +26,7 @@ from _pytest.config.exceptions import UsageError
from _pytest.nodes import Node from _pytest.nodes import Node
from _pytest.reports import BaseReport from _pytest.reports import BaseReport
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.capture import CaptureManager from _pytest.capture import CaptureManager
from _pytest.runner import CallInfo from _pytest.runner import CallInfo
@ -264,8 +265,7 @@ class pytestPDB:
elif capturing: elif capturing:
tw.sep( tw.sep(
">", ">",
"PDB %s (IO-capturing turned off for %s)" f"PDB {method} (IO-capturing turned off for {capturing})",
% (method, capturing),
) )
else: else:
tw.sep(">", f"PDB {method}") tw.sep(">", f"PDB {method}")

View File

@ -15,6 +15,7 @@ from _pytest.warning_types import PytestDeprecationWarning
from _pytest.warning_types import PytestRemovedIn9Warning from _pytest.warning_types import PytestRemovedIn9Warning
from _pytest.warning_types import UnformattedWarning from _pytest.warning_types import UnformattedWarning
# set of plugins which have been integrated into the core; we use this list to ignore # set of plugins which have been integrated into the core; we use this list to ignore
# them during registration to avoid conflicts # them during registration to avoid conflicts
DEPRECATED_EXTERNAL_PLUGINS = { DEPRECATED_EXTERNAL_PLUGINS = {

View File

@ -1,16 +1,15 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Discover and run doctests in modules and test files.""" """Discover and run doctests in modules and test files."""
import bdb import bdb
from contextlib import contextmanager
import functools import functools
import inspect import inspect
import os import os
from pathlib import Path
import platform import platform
import sys import sys
import traceback import traceback
import types import types
import warnings
from contextlib import contextmanager
from pathlib import Path
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
@ -24,6 +23,7 @@ from typing import Tuple
from typing import Type from typing import Type
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Union from typing import Union
import warnings
from _pytest import outcomes from _pytest import outcomes
from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionInfo
@ -45,6 +45,7 @@ from _pytest.python import Module
from _pytest.python_api import approx from _pytest.python_api import approx
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
if TYPE_CHECKING: if TYPE_CHECKING:
import doctest import doctest
@ -486,9 +487,9 @@ def _patch_unwrap_mock_aware() -> Generator[None, None, None]:
return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func)) return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func))
except Exception as e: except Exception as e:
warnings.warn( 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. " "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, PytestWarning,
) )
raise raise

View File

@ -2,11 +2,12 @@ import os
import sys import sys
from typing import Generator from typing import Generator
import pytest
from _pytest.config import Config from _pytest.config import Config
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.stash import StashKey from _pytest.stash import StashKey
import pytest
fault_handler_original_stderr_fd_key = StashKey[int]() fault_handler_original_stderr_fd_key = StashKey[int]()
fault_handler_stderr_fd_key = StashKey[int]() fault_handler_stderr_fd_key = StashKey[int]()

View File

@ -1,13 +1,12 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import abc import abc
from collections import defaultdict
from collections import deque
from contextlib import suppress
import dataclasses import dataclasses
import functools import functools
import inspect import inspect
import os import os
import warnings
from collections import defaultdict
from collections import deque
from contextlib import suppress
from pathlib import Path from pathlib import Path
from typing import AbstractSet from typing import AbstractSet
from typing import Any from typing import Any
@ -31,6 +30,7 @@ from typing import Tuple
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import warnings
import _pytest import _pytest
from _pytest import nodes from _pytest import nodes
@ -67,6 +67,7 @@ from _pytest.scope import _ScopeName
from _pytest.scope import HIGH_SCOPES from _pytest.scope import HIGH_SCOPES
from _pytest.scope import Scope from _pytest.scope import Scope
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Deque from typing import Deque
@ -601,13 +602,9 @@ class FixtureRequest(abc.ABC):
fixtures_not_supported = getattr(funcitem, "nofuncargs", False) fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
if has_params and fixtures_not_supported: if has_params and fixtures_not_supported:
msg = ( msg = (
"{name} does not support fixtures, maybe unittest.TestCase subclass?\n" f"{funcitem.name} does not support fixtures, maybe unittest.TestCase subclass?\n"
"Node id: {nodeid}\n" f"Node id: {funcitem.nodeid}\n"
"Function type: {typename}" f"Function type: {type(funcitem).__name__}"
).format(
name=funcitem.name,
nodeid=funcitem.nodeid,
typename=type(funcitem).__name__,
) )
fail(msg, pytrace=False) fail(msg, pytrace=False)
if has_params: if has_params:
@ -740,9 +737,7 @@ class SubRequest(FixtureRequest):
if node is None and scope is Scope.Class: if node is None and scope is Scope.Class:
# Fallback to function item itself. # Fallback to function item itself.
node = self._pyfuncitem node = self._pyfuncitem
assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format( assert node, f'Could not obtain a node for scope "{scope}" for function {self._pyfuncitem!r}'
scope, self._pyfuncitem
)
return node return node
def _check_scope( def _check_scope(
@ -845,8 +840,8 @@ class FixtureLookupError(LookupError):
if faclist: if faclist:
available.add(name) available.add(name)
if self.argname in available: if self.argname in available:
msg = " recursive dependency involving fixture '{}' detected".format( msg = (
self.argname f" recursive dependency involving fixture '{self.argname}' detected"
) )
else: else:
msg = f"fixture '{self.argname}' not found" msg = f"fixture '{self.argname}' not found"
@ -940,15 +935,13 @@ def _eval_scope_callable(
result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg] result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg]
except Exception as e: except Exception as e:
raise TypeError( raise TypeError(
"Error evaluating {} while defining fixture '{}'.\n" f"Error evaluating {scope_callable} while defining fixture '{fixture_name}'.\n"
"Expected a function with the signature (*, fixture_name, config)".format( "Expected a function with the signature (*, fixture_name, config)"
scope_callable, fixture_name
)
) from e ) from e
if not isinstance(result, str): if not isinstance(result, str):
fail( fail(
"Expected {} to return a 'str' while defining fixture '{}', but it returned:\n" f"Expected {scope_callable} to return a 'str' while defining fixture '{fixture_name}', but it returned:\n"
"{!r}".format(scope_callable, fixture_name, result), f"{result!r}",
pytrace=False, pytrace=False,
) )
return result return result
@ -1090,9 +1083,7 @@ class FixtureDef(Generic[FixtureValue]):
return request.param_index if not hasattr(request, "param") else request.param return request.param_index if not hasattr(request, "param") else request.param
def __repr__(self) -> str: def __repr__(self) -> str:
return "<FixtureDef argname={!r} scope={!r} baseid={!r}>".format( return f"<FixtureDef argname={self.argname!r} scope={self.scope!r} baseid={self.baseid!r}>"
self.argname, self.scope, self.baseid
)
def resolve_fixture_function( def resolve_fixture_function(
@ -1113,7 +1104,8 @@ def resolve_fixture_function(
# Handle the case where fixture is defined not in a test class, but some other class # 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. # (for example a plugin class with a fixture), see #2270.
if hasattr(fixturefunc, "__self__") and not isinstance( 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 return fixturefunc
fixturefunc = getimfunc(fixturedef.func) fixturefunc = getimfunc(fixturedef.func)
@ -1208,9 +1200,7 @@ class FixtureFunctionMarker:
if name == "request": if name == "request":
location = getlocation(function) location = getlocation(function)
fail( fail(
"'request' is a reserved word for fixtures, use another name:\n {}".format( f"'request' is a reserved word for fixtures, use another name:\n {location}",
location
),
pytrace=False, pytrace=False,
) )
@ -1230,7 +1220,8 @@ def fixture(
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
] = ..., ] = ...,
name: Optional[str] = ..., name: Optional[str] = ...,
) -> FixtureFunction: ... ) -> FixtureFunction:
...
@overload @overload
@ -1244,7 +1235,8 @@ def fixture( # noqa: F811
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
] = ..., ] = ...,
name: Optional[str] = None, name: Optional[str] = None,
) -> FixtureFunctionMarker: ... ) -> FixtureFunctionMarker:
...
def fixture( # noqa: F811 def fixture( # noqa: F811

View File

@ -1,19 +1,19 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Version info, help messages, tracing configuration.""" """Version info, help messages, tracing configuration."""
from argparse import Action
import os import os
import sys import sys
from argparse import Action
from typing import Generator from typing import Generator
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Union from typing import Union
import pytest
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.config import PrintHelp from _pytest.config import PrintHelp
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
import pytest
class HelpAction(Action): class HelpAction(Action):
@ -109,9 +109,8 @@ def pytest_cmdline_parse() -> Generator[None, Config, Config]:
path = config.option.debug path = config.option.debug
debugfile = open(path, "w", encoding="utf-8") debugfile = open(path, "w", encoding="utf-8")
debugfile.write( debugfile.write(
"versions pytest-%s, " "versions pytest-{}, "
"python-%s\ninvocation_dir=%s\ncwd=%s\nargs=%s\n\n" "python-{}\ninvocation_dir={}\ncwd={}\nargs={}\n\n".format(
% (
pytest.__version__, pytest.__version__,
".".join(map(str, sys.version_info)), ".".join(map(str, sys.version_info)),
config.invocation_params.dir, config.invocation_params.dir,
@ -137,9 +136,7 @@ def pytest_cmdline_parse() -> Generator[None, Config, Config]:
def showversion(config: Config) -> None: def showversion(config: Config) -> None:
if config.option.version > 1: if config.option.version > 1:
sys.stdout.write( sys.stdout.write(
"This is pytest version {}, imported from {}\n".format( f"This is pytest version {pytest.__version__}, imported from {pytest.__file__}\n"
pytest.__version__, pytest.__file__
)
) )
plugininfo = getpluginversioninfo(config) plugininfo = getpluginversioninfo(config)
if plugininfo: if plugininfo:

View File

@ -14,10 +14,11 @@ from typing import Union
from pluggy import HookspecMarker from pluggy import HookspecMarker
if TYPE_CHECKING: if TYPE_CHECKING:
import pdb import pdb
import warnings
from typing import Literal from typing import Literal
import warnings
from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ExceptionRepr from _pytest._code.code import ExceptionRepr

View File

@ -7,12 +7,11 @@ Based on initial code from Ross Lawley.
Output conforms to Output conforms to
https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd 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 functools
import os import os
import platform import platform
import re import re
import xml.etree.ElementTree as ET
from datetime import datetime
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
from typing import List from typing import List
@ -20,8 +19,8 @@ from typing import Match
from typing import Optional from typing import Optional
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
import xml.etree.ElementTree as ET
import pytest
from _pytest import nodes from _pytest import nodes
from _pytest import timing from _pytest import timing
from _pytest._code.code import ExceptionRepr from _pytest._code.code import ExceptionRepr
@ -33,6 +32,8 @@ from _pytest.fixtures import FixtureRequest
from _pytest.reports import TestReport from _pytest.reports import TestReport
from _pytest.stash import StashKey from _pytest.stash import StashKey
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
import pytest
xml_key = StashKey["LogXML"]() 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"): if xml is not None and xml.family not in ("xunit1", "legacy"):
request.node.warn( request.node.warn(
PytestWarning( PytestWarning(
"{fixture_name} is incompatible with junit_family '{family}' (use 'legacy' or 'xunit1')".format( f"{fixture_name} is incompatible with junit_family '{xml.family}' (use 'legacy' or 'xunit1')"
fixture_name=fixture_name, family=xml.family
)
) )
) )
@ -367,7 +366,6 @@ def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object]
`pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See `pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See
:issue:`7767` for details. :issue:`7767` for details.
""" """
__tracebackhide__ = True __tracebackhide__ = True
def record_func(name: str, value: object) -> None: def record_func(name: str, value: object) -> None:

View File

@ -2,9 +2,9 @@
"""Add backward compatibility support for the legacy py path type.""" """Add backward compatibility support for the legacy py path type."""
import dataclasses import dataclasses
import os import os
from pathlib import Path
import shlex import shlex
import subprocess import subprocess
from pathlib import Path
from typing import Final from typing import Final
from typing import final from typing import final
from typing import List from typing import List
@ -34,6 +34,7 @@ from _pytest.pytester import RunResult
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
from _pytest.tmpdir import TempPathFactory from _pytest.tmpdir import TempPathFactory
if TYPE_CHECKING: if TYPE_CHECKING:
import pexpect import pexpect

View File

@ -1,17 +1,17 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Access and control log capturing.""" """Access and control log capturing."""
import io
import logging
import os
import re
from contextlib import contextmanager from contextlib import contextmanager
from contextlib import nullcontext from contextlib import nullcontext
from datetime import datetime from datetime import datetime
from datetime import timedelta from datetime import timedelta
from datetime import timezone from datetime import timezone
import io
from io import StringIO from io import StringIO
import logging
from logging import LogRecord from logging import LogRecord
import os
from pathlib import Path from pathlib import Path
import re
from types import TracebackType from types import TracebackType
from typing import AbstractSet from typing import AbstractSet
from typing import Dict from typing import Dict
@ -44,6 +44,7 @@ from _pytest.main import Session
from _pytest.stash import StashKey from _pytest.stash import StashKey
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
if TYPE_CHECKING: if TYPE_CHECKING:
logging_StreamHandler = logging.StreamHandler[StringIO] logging_StreamHandler = logging.StreamHandler[StringIO]
else: else:
@ -116,7 +117,6 @@ class ColoredLevelFormatter(DatetimeFormatter):
.. warning:: .. warning::
This is an experimental API. This is an experimental API.
""" """
assert self._fmt is not None assert self._fmt is not None
levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt) levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt)
if not levelname_fmt_match: if not levelname_fmt_match:
@ -183,7 +183,6 @@ class PercentStyleMultiline(logging.PercentStyle):
0 (auto-indent turned off) or 0 (auto-indent turned off) or
>0 (explicitly set indentation position). >0 (explicitly set indentation position).
""" """
if auto_indent_option is None: if auto_indent_option is None:
return 0 return 0
elif isinstance(auto_indent_option, bool): 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: except ValueError as e:
# Python logging does not recognise this as a logging level # Python logging does not recognise this as a logging level
raise UsageError( raise UsageError(
"'{}' is not recognized as a logging level name for " f"'{log_level}' is not recognized as a logging level name for "
"'{}'. Please consider passing the " f"'{setting_name}'. Please consider passing the "
"logging level num instead.".format(log_level, setting_name) "logging level num instead."
) from e ) from e

View File

@ -6,9 +6,8 @@ import fnmatch
import functools import functools
import importlib import importlib
import os import os
import sys
import warnings
from pathlib import Path from pathlib import Path
import sys
from typing import AbstractSet from typing import AbstractSet
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
@ -23,11 +22,12 @@ from typing import overload
from typing import Sequence from typing import Sequence
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
import warnings
import pluggy import pluggy
import _pytest._code
from _pytest import nodes from _pytest import nodes
import _pytest._code
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import directory_arg from _pytest.config import directory_arg
from _pytest.config import ExitCode from _pytest.config import ExitCode
@ -722,12 +722,14 @@ class Session(nodes.Collector):
@overload @overload
def perform_collect( def perform_collect(
self, args: Optional[Sequence[str]] = ..., genitems: "Literal[True]" = ... self, args: Optional[Sequence[str]] = ..., genitems: "Literal[True]" = ...
) -> Sequence[nodes.Item]: ... ) -> Sequence[nodes.Item]:
...
@overload @overload
def perform_collect( # noqa: F811 def perform_collect( # noqa: F811
self, args: Optional[Sequence[str]] = ..., genitems: bool = ... self, args: Optional[Sequence[str]] = ..., genitems: bool = ...
) -> Sequence[Union[nodes.Item, nodes.Collector]]: ... ) -> Sequence[Union[nodes.Item, nodes.Collector]]:
...
def perform_collect( # noqa: F811 def perform_collect( # noqa: F811
self, args: Optional[Sequence[str]] = None, genitems: bool = True self, args: Optional[Sequence[str]] = None, genitems: bool = True

View File

@ -24,6 +24,7 @@ from _pytest.config import UsageError
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.stash import StashKey from _pytest.stash import StashKey
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.nodes import Item 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, ""): if empty_parameterset not in ("skip", "xfail", "fail_at_collect", None, ""):
raise UsageError( raise UsageError(
"{!s} must be one of skip, xfail or fail_at_collect" f"{EMPTY_PARAMETERSET_OPTION!s} must be one of skip, xfail or fail_at_collect"
" but it is {!r}".format(EMPTY_PARAMETERSET_OPTION, empty_parameterset) f" but it is {empty_parameterset!r}"
) )

View File

@ -27,6 +27,7 @@ from typing import NoReturn
from typing import Optional from typing import Optional
from typing import Sequence from typing import Sequence
__all__ = [ __all__ = [
"Expression", "Expression",
"ParseError", "ParseError",

View File

@ -2,7 +2,6 @@
import collections.abc import collections.abc
import dataclasses import dataclasses
import inspect import inspect
import warnings
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Collection from typing import Collection
@ -22,6 +21,7 @@ from typing import Type
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import warnings
from .._code import getfslineno from .._code import getfslineno
from ..compat import ascii_escaped from ..compat import ascii_escaped
@ -33,6 +33,7 @@ from _pytest.deprecated import MARKED_FIXTURE
from _pytest.outcomes import fail from _pytest.outcomes import fail
from _pytest.warning_types import PytestUnknownMarkWarning from _pytest.warning_types import PytestUnknownMarkWarning
if TYPE_CHECKING: if TYPE_CHECKING:
from ..nodes import Node from ..nodes import Node
@ -112,7 +113,6 @@ class ParameterSet(NamedTuple):
Enforce tuple wrapping so single argument tuple values Enforce tuple wrapping so single argument tuple values
don't get decomposed and break tests. don't get decomposed and break tests.
""" """
if isinstance(parameterset, cls): if isinstance(parameterset, cls):
return parameterset return parameterset
if force_tuple: if force_tuple:
@ -272,8 +272,8 @@ class MarkDecorator:
``MarkDecorators`` are created with ``pytest.mark``:: ``MarkDecorators`` are created with ``pytest.mark``::
mark1 = pytest.mark.NAME # Simple MarkDecorator mark1 = pytest.mark.NAME # Simple MarkDecorator
mark2 = pytest.mark.NAME(name1=value) # Parametrized MarkDecorator mark2 = pytest.mark.NAME(name1=value) # Parametrized MarkDecorator
and can then be applied as decorators to test functions:: and can then be applied as decorators to test functions::
@ -394,7 +394,7 @@ def get_unpacked_marks(
def normalize_mark_list( def normalize_mark_list(
mark_list: Iterable[Union[Mark, MarkDecorator]] mark_list: Iterable[Union[Mark, MarkDecorator]],
) -> Iterable[Mark]: ) -> Iterable[Mark]:
""" """
Normalize an iterable of Mark or MarkDecorator objects into a list of marks Normalize an iterable of Mark or MarkDecorator objects into a list of marks
@ -434,10 +434,12 @@ if TYPE_CHECKING:
class _SkipMarkDecorator(MarkDecorator): class _SkipMarkDecorator(MarkDecorator):
@overload # type: ignore[override,misc,no-overload-impl] @overload # type: ignore[override,misc,no-overload-impl]
def __call__(self, arg: Markable) -> Markable: ... def __call__(self, arg: Markable) -> Markable:
...
@overload @overload
def __call__(self, reason: str = ...) -> "MarkDecorator": ... def __call__(self, reason: str = ...) -> "MarkDecorator":
...
class _SkipifMarkDecorator(MarkDecorator): class _SkipifMarkDecorator(MarkDecorator):
def __call__( # type: ignore[override] def __call__( # type: ignore[override]
@ -445,11 +447,13 @@ if TYPE_CHECKING:
condition: Union[str, bool] = ..., condition: Union[str, bool] = ...,
*conditions: Union[str, bool], *conditions: Union[str, bool],
reason: str = ..., reason: str = ...,
) -> MarkDecorator: ... ) -> MarkDecorator:
...
class _XfailMarkDecorator(MarkDecorator): class _XfailMarkDecorator(MarkDecorator):
@overload # type: ignore[override,misc,no-overload-impl] @overload # type: ignore[override,misc,no-overload-impl]
def __call__(self, arg: Markable) -> Markable: ... def __call__(self, arg: Markable) -> Markable:
...
@overload @overload
def __call__( def __call__(
@ -462,7 +466,8 @@ if TYPE_CHECKING:
None, Type[BaseException], Tuple[Type[BaseException], ...] None, Type[BaseException], Tuple[Type[BaseException], ...]
] = ..., ] = ...,
strict: bool = ..., strict: bool = ...,
) -> MarkDecorator: ... ) -> MarkDecorator:
...
class _ParametrizeMarkDecorator(MarkDecorator): class _ParametrizeMarkDecorator(MarkDecorator):
def __call__( # type: ignore[override] def __call__( # type: ignore[override]
@ -478,7 +483,8 @@ if TYPE_CHECKING:
] ]
] = ..., ] = ...,
scope: Optional[_ScopeName] = ..., scope: Optional[_ScopeName] = ...,
) -> MarkDecorator: ... ) -> MarkDecorator:
...
class _UsefixturesMarkDecorator(MarkDecorator): class _UsefixturesMarkDecorator(MarkDecorator):
def __call__(self, *fixtures: str) -> MarkDecorator: # type: ignore[override] def __call__(self, *fixtures: str) -> MarkDecorator: # type: ignore[override]
@ -498,9 +504,10 @@ class MarkGenerator:
import pytest import pytest
@pytest.mark.slowtest @pytest.mark.slowtest
def test_function(): def test_function():
pass pass
applies a 'slowtest' :class:`Mark` on ``test_function``. applies a 'slowtest' :class:`Mark` on ``test_function``.
""" """

View File

@ -1,10 +1,9 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Monkeypatching and mocking functionality.""" """Monkeypatching and mocking functionality."""
from contextlib import contextmanager
import os import os
import re import re
import sys import sys
import warnings
from contextlib import contextmanager
from typing import Any from typing import Any
from typing import final from typing import final
from typing import Generator from typing import Generator
@ -16,10 +15,12 @@ from typing import overload
from typing import Tuple from typing import Tuple
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import warnings
from _pytest.fixtures import fixture from _pytest.fixtures import fixture
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$") 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) obj = getattr(obj, name)
except AttributeError as e: except AttributeError as e:
raise AttributeError( raise AttributeError(
"{!r} object at {} has no attribute {!r}".format( f"{type(obj).__name__!r} object at {ann} has no attribute {name!r}"
type(obj).__name__, ann, name
)
) from e ) from e
return obj return obj
@ -142,7 +141,6 @@ class MonkeyPatch:
which undoes any patching done inside the ``with`` block upon exit. which undoes any patching done inside the ``with`` block upon exit.
Example: Example:
.. code-block:: python .. code-block:: python
import functools import functools
@ -169,7 +167,8 @@ class MonkeyPatch:
name: object, name: object,
value: Notset = ..., value: Notset = ...,
raising: bool = ..., raising: bool = ...,
) -> None: ... ) -> None:
...
@overload @overload
def setattr( def setattr(
@ -178,7 +177,8 @@ class MonkeyPatch:
name: str, name: str,
value: object, value: object,
raising: bool = ..., raising: bool = ...,
) -> None: ... ) -> None:
...
def setattr( def setattr(
self, self,
@ -320,10 +320,8 @@ class MonkeyPatch:
if not isinstance(value, str): if not isinstance(value, str):
warnings.warn( # type: ignore[unreachable] warnings.warn( # type: ignore[unreachable]
PytestWarning( PytestWarning(
"Value of environment variable {name} type should be str, but got " f"Value of environment variable {name} type should be str, but got "
"{value!r} (type: {type}); converted to str implicitly".format( f"{value!r} (type: {type(value).__name__}); converted to str implicitly"
name=name, value=value, type=type(value).__name__
)
), ),
stacklevel=2, stacklevel=2,
) )
@ -343,7 +341,6 @@ class MonkeyPatch:
def syspath_prepend(self, path) -> None: def syspath_prepend(self, path) -> None:
"""Prepend ``path`` to ``sys.path`` list of import locations.""" """Prepend ``path`` to ``sys.path`` list of import locations."""
if self._savesyspath is None: if self._savesyspath is None:
self._savesyspath = sys.path[:] self._savesyspath = sys.path[:]
sys.path.insert(0, str(path)) sys.path.insert(0, str(path))

View File

@ -1,9 +1,8 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import abc import abc
import os
import warnings
from functools import cached_property from functools import cached_property
from inspect import signature from inspect import signature
import os
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
from typing import Callable from typing import Callable
@ -20,6 +19,7 @@ from typing import Type
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import warnings
import pluggy import pluggy
@ -39,6 +39,7 @@ from _pytest.pathlib import commonpath
from _pytest.stash import Stash from _pytest.stash import Stash
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
if TYPE_CHECKING: if TYPE_CHECKING:
# Imported here due to circular import. # Imported here due to circular import.
from _pytest._code.code import _TracebackStyle from _pytest._code.code import _TracebackStyle
@ -229,9 +230,7 @@ class Node(abc.ABC, metaclass=NodeMeta):
# enforce type checks here to avoid getting a generic type error later otherwise. # enforce type checks here to avoid getting a generic type error later otherwise.
if not isinstance(warning, Warning): if not isinstance(warning, Warning):
raise ValueError( raise ValueError(
"warning must be an instance of Warning or subclass, got {!r}".format( f"warning must be an instance of Warning or subclass, got {warning!r}"
warning
)
) )
path, lineno = get_fslocation_from_item(self) path, lineno = get_fslocation_from_item(self)
assert lineno is not None assert lineno is not None
@ -326,10 +325,12 @@ class Node(abc.ABC, metaclass=NodeMeta):
yield node, mark yield node, mark
@overload @overload
def get_closest_marker(self, name: str) -> Optional[Mark]: ... def get_closest_marker(self, name: str) -> Optional[Mark]:
...
@overload @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( def get_closest_marker(
self, name: str, default: Optional[Mark] = None self, name: str, default: Optional[Mark] = None

View File

@ -239,8 +239,7 @@ def importorskip(
if verattr is None or Version(verattr) < Version(minversion): if verattr is None or Version(verattr) < Version(minversion):
raise Skipped( raise Skipped(
"module %r has __version__ %r, required is: %r" f"module {modname!r} has __version__ {verattr!r}, required is: {minversion!r}",
% (modname, verattr, minversion),
allow_module_level=True, allow_module_level=True,
) )
return mod return mod

View File

@ -1,16 +1,17 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Submit failure or test session information to a pastebin service.""" """Submit failure or test session information to a pastebin service."""
import tempfile
from io import StringIO from io import StringIO
import tempfile
from typing import IO from typing import IO
from typing import Union from typing import Union
import pytest
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import create_terminal_writer from _pytest.config import create_terminal_writer
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.stash import StashKey from _pytest.stash import StashKey
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
import pytest
pastebinfile_key = StashKey[IO[bytes]]() pastebinfile_key = StashKey[IO[bytes]]()

View File

@ -1,21 +1,16 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import atexit import atexit
import contextlib 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 enum import Enum
from errno import EBADF from errno import EBADF
from errno import ELOOP from errno import ELOOP
from errno import ENOENT from errno import ENOENT
from errno import ENOTDIR from errno import ENOTDIR
import fnmatch
from functools import partial from functools import partial
import importlib.util
import itertools
import os
from os.path import expanduser from os.path import expanduser
from os.path import expandvars from os.path import expandvars
from os.path import isabs from os.path import isabs
@ -23,6 +18,9 @@ from os.path import sep
from pathlib import Path from pathlib import Path
from pathlib import PurePath from pathlib import PurePath
from posixpath import sep as posix_sep from posixpath import sep as posix_sep
import shutil
import sys
import types
from types import ModuleType from types import ModuleType
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
@ -35,11 +33,14 @@ from typing import Tuple
from typing import Type from typing import Type
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import uuid
import warnings
from _pytest.compat import assert_never from _pytest.compat import assert_never
from _pytest.outcomes import skip from _pytest.outcomes import skip
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
LOCK_TIMEOUT = 60 * 60 * 24 * 3 LOCK_TIMEOUT = 60 * 60 * 24 * 3
@ -102,9 +103,7 @@ def on_rm_rf_error(
if func not in (os.open,): if func not in (os.open,):
warnings.warn( warnings.warn(
PytestWarning( PytestWarning(
"(rm_rf) unknown function {} when removing {}:\n{}: {}".format( f"(rm_rf) unknown function {func} when removing {path}:\n{type(exc)}: {exc}"
func, path, type(exc), exc
)
) )
) )
return False return False
@ -243,7 +242,7 @@ def make_numbered_dir(root: Path, prefix: str, mode: int = 0o700) -> Path:
else: else:
raise OSError( raise OSError(
"could not create numbered dir with prefix " "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"
) )

View File

@ -5,19 +5,19 @@ PYTEST_DONT_REWRITE
""" """
import collections.abc import collections.abc
import contextlib import contextlib
from fnmatch import fnmatch
import gc import gc
import importlib import importlib
from io import StringIO
import locale import locale
import os import os
from pathlib import Path
import platform import platform
import re import re
import shutil import shutil
import subprocess import subprocess
import sys import sys
import traceback import traceback
from fnmatch import fnmatch
from io import StringIO
from pathlib import Path
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
@ -70,6 +70,7 @@ from _pytest.reports import TestReport
from _pytest.tmpdir import TempPathFactory from _pytest.tmpdir import TempPathFactory
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
if TYPE_CHECKING: if TYPE_CHECKING:
import pexpect import pexpect
@ -187,7 +188,7 @@ class LsofFdLeakChecker:
"*** After:", "*** After:",
*(str(f) for f in lines2), *(str(f) for f in lines2),
"***** %s FD leakage detected" % len(leaked_files), "***** %s FD leakage detected" % len(leaked_files),
"*** function %s:%s: %s " % item.location, "*** function {}:{}: {} ".format(*item.location),
"See issue #2366", "See issue #2366",
] ]
item.warn(PytestWarning("\n".join(error))) item.warn(PytestWarning("\n".join(error)))
@ -244,7 +245,8 @@ class RecordedHookCall:
if TYPE_CHECKING: if TYPE_CHECKING:
# The class has undetermined attributes, this tells mypy about it. # The class has undetermined attributes, this tells mypy about it.
def __getattr__(self, key: str): ... def __getattr__(self, key: str):
...
@final @final
@ -325,13 +327,15 @@ class HookRecorder:
def getreports( def getreports(
self, self,
names: "Literal['pytest_collectreport']", names: "Literal['pytest_collectreport']",
) -> Sequence[CollectReport]: ... ) -> Sequence[CollectReport]:
...
@overload @overload
def getreports( def getreports(
self, self,
names: "Literal['pytest_runtest_logreport']", names: "Literal['pytest_runtest_logreport']",
) -> Sequence[TestReport]: ... ) -> Sequence[TestReport]:
...
@overload @overload
def getreports( def getreports(
@ -340,7 +344,8 @@ class HookRecorder:
"pytest_collectreport", "pytest_collectreport",
"pytest_runtest_logreport", "pytest_runtest_logreport",
), ),
) -> Sequence[Union[CollectReport, TestReport]]: ... ) -> Sequence[Union[CollectReport, TestReport]]:
...
def getreports( def getreports(
self, self,
@ -372,14 +377,12 @@ class HookRecorder:
values.append(rep) values.append(rep)
if not values: if not values:
raise ValueError( raise ValueError(
"could not find test report matching %r: " f"could not find test report matching {inamepart!r}: "
"no test reports at all!" % (inamepart,) "no test reports at all!"
) )
if len(values) > 1: if len(values) > 1:
raise ValueError( raise ValueError(
"found 2 or more testreports matching {!r}: {}".format( f"found 2 or more testreports matching {inamepart!r}: {values}"
inamepart, values
)
) )
return values[0] return values[0]
@ -387,13 +390,15 @@ class HookRecorder:
def getfailures( def getfailures(
self, self,
names: "Literal['pytest_collectreport']", names: "Literal['pytest_collectreport']",
) -> Sequence[CollectReport]: ... ) -> Sequence[CollectReport]:
...
@overload @overload
def getfailures( def getfailures(
self, self,
names: "Literal['pytest_runtest_logreport']", names: "Literal['pytest_runtest_logreport']",
) -> Sequence[TestReport]: ... ) -> Sequence[TestReport]:
...
@overload @overload
def getfailures( def getfailures(
@ -402,7 +407,8 @@ class HookRecorder:
"pytest_collectreport", "pytest_collectreport",
"pytest_runtest_logreport", "pytest_runtest_logreport",
), ),
) -> Sequence[Union[CollectReport, TestReport]]: ... ) -> Sequence[Union[CollectReport, TestReport]]:
...
def getfailures( def getfailures(
self, self,
@ -801,7 +807,6 @@ class Pytester:
The first created file. The first created file.
Examples: Examples:
.. code-block:: python .. code-block:: python
pytester.makefile(".txt", "line1", "line2") pytester.makefile(".txt", "line1", "line2")
@ -855,7 +860,6 @@ class Pytester:
existing files. existing files.
Examples: Examples:
.. code-block:: python .. code-block:: python
def test_something(pytester): def test_something(pytester):
@ -875,7 +879,6 @@ class Pytester:
existing files. existing files.
Examples: Examples:
.. code-block:: python .. code-block:: python
def test_something(pytester): def test_something(pytester):
@ -1265,9 +1268,7 @@ class Pytester:
for item in items: for item in items:
if item.name == funcname: if item.name == funcname:
return item return item
assert 0, "{!r} item not found in module:\n{}\nitems: {}".format( assert 0, f"{funcname!r} item not found in module:\n{source}\nitems: {items}"
funcname, source, items
)
def getitems(self, source: Union[str, "os.PathLike[str]"]) -> List[Item]: def getitems(self, source: Union[str, "os.PathLike[str]"]) -> List[Item]:
"""Return all test items collected from the module. """Return all test items collected from the module.
@ -1426,10 +1427,7 @@ class Pytester:
def handle_timeout() -> None: def handle_timeout() -> None:
__tracebackhide__ = True __tracebackhide__ = True
timeout_message = ( timeout_message = f"{timeout} second timeout expired running: {cmdargs}"
"{seconds} second timeout expired running:"
" {command}".format(seconds=timeout, command=cmdargs)
)
popen.kill() popen.kill()
popen.wait() popen.wait()

View File

@ -1,18 +1,17 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Python test discovery, setup and run of test functions.""" """Python test discovery, setup and run of test functions."""
import abc import abc
from collections import Counter
from collections import defaultdict
import dataclasses import dataclasses
import enum import enum
import fnmatch import fnmatch
from functools import partial
import inspect import inspect
import itertools import itertools
import os import os
import types
import warnings
from collections import Counter
from collections import defaultdict
from functools import partial
from pathlib import Path from pathlib import Path
import types
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
@ -29,6 +28,7 @@ from typing import Sequence
from typing import Set from typing import Set
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
import warnings
import _pytest import _pytest
from _pytest import fixtures from _pytest import fixtures
@ -81,6 +81,7 @@ from _pytest.warning_types import PytestCollectionWarning
from _pytest.warning_types import PytestReturnNotNoneWarning from _pytest.warning_types import PytestReturnNotNoneWarning
from _pytest.warning_types import PytestUnhandledCoroutineWarning from _pytest.warning_types import PytestUnhandledCoroutineWarning
_PYTEST_DIR = Path(_pytest.__file__).parent _PYTEST_DIR = Path(_pytest.__file__).parent
@ -263,8 +264,8 @@ def pytest_pycollect_makeitem(
elif getattr(obj, "__test__", True): elif getattr(obj, "__test__", True):
if is_generator(obj): if is_generator(obj):
res: Function = Function.from_parent(collector, name=name) res: Function = Function.from_parent(collector, name=name)
reason = "yield tests were removed in pytest 4.0 - {name} will be ignored".format( reason = (
name=name f"yield tests were removed in pytest 4.0 - {name} will be ignored"
) )
res.add_marker(MARK_GEN.xfail(run=False, reason=reason)) res.add_marker(MARK_GEN.xfail(run=False, reason=reason))
res.warn(PytestCollectionWarning(reason)) res.warn(PytestCollectionWarning(reason))
@ -524,12 +525,12 @@ def importtestmodule(
except ImportPathMismatchError as e: except ImportPathMismatchError as e:
raise nodes.Collector.CollectError( raise nodes.Collector.CollectError(
"import file mismatch:\n" "import file mismatch:\n"
"imported module %r has this __file__ attribute:\n" "imported module {!r} has this __file__ attribute:\n"
" %s\n" " {}\n"
"which is not the same as the test file we want to collect:\n" "which is not the same as the test file we want to collect:\n"
" %s\n" " {}\n"
"HINT: remove __pycache__ / .pyc files and/or use a " "HINT: remove __pycache__ / .pyc files and/or use a "
"unique basename for your test file modules" % e.args "unique basename for your test file modules".format(*e.args)
) from e ) from e
except ImportError as e: except ImportError as e:
exc_info = ExceptionInfo.from_current() exc_info = ExceptionInfo.from_current()
@ -542,10 +543,10 @@ def importtestmodule(
) )
formatted_tb = str(exc_repr) formatted_tb = str(exc_repr)
raise nodes.Collector.CollectError( 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" "Hint: make sure your test modules/packages have valid Python names.\n"
"Traceback:\n" "Traceback:\n"
"{traceback}".format(path=path, traceback=formatted_tb) f"{formatted_tb}"
) from e ) from e
except skip.Exception as e: except skip.Exception as e:
if e.allow_module_level: if e.allow_module_level:
@ -765,9 +766,8 @@ class Class(PyCollector):
assert self.parent is not None assert self.parent is not None
self.warn( self.warn(
PytestCollectionWarning( PytestCollectionWarning(
"cannot collect test class %r because it has a " f"cannot collect test class {self.obj.__name__!r} because it has a "
"__init__ constructor (from: %s)" f"__init__ constructor (from: {self.parent.nodeid})"
% (self.obj.__name__, self.parent.nodeid)
) )
) )
return [] return []
@ -775,9 +775,8 @@ class Class(PyCollector):
assert self.parent is not None assert self.parent is not None
self.warn( self.warn(
PytestCollectionWarning( PytestCollectionWarning(
"cannot collect test class %r because it has a " f"cannot collect test class {self.obj.__name__!r} because it has a "
"__new__ constructor (from: %s)" f"__new__ constructor (from: {self.parent.nodeid})"
% (self.obj.__name__, self.parent.nodeid)
) )
) )
return [] return []
@ -1432,17 +1431,14 @@ class Metafunc:
for arg in indirect: for arg in indirect:
if arg not in argnames: if arg not in argnames:
fail( fail(
"In {}: indirect fixture '{}' doesn't exist".format( f"In {self.function.__name__}: indirect fixture '{arg}' doesn't exist",
self.function.__name__, arg
),
pytrace=False, pytrace=False,
) )
arg_directness[arg] = "indirect" arg_directness[arg] = "indirect"
else: else:
fail( fail(
"In {func}: expected Sequence or boolean for indirect, got {type}".format( f"In {self.function.__name__}: expected Sequence or boolean"
type=type(indirect).__name__, func=self.function.__name__ f" for indirect, got {type(indirect).__name__}",
),
pytrace=False, pytrace=False,
) )
return arg_directness return arg_directness
@ -1464,9 +1460,7 @@ class Metafunc:
if arg not in self.fixturenames: if arg not in self.fixturenames:
if arg in default_arg_names: if arg in default_arg_names:
fail( fail(
"In {}: function already takes an argument '{}' with a default value".format( f"In {func_name}: function already takes an argument '{arg}' with a default value",
func_name, arg
),
pytrace=False, pytrace=False,
) )
else: else:

View File

@ -1,10 +1,10 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import math
import pprint
from collections.abc import Collection from collections.abc import Collection
from collections.abc import Sized from collections.abc import Sized
from decimal import Decimal from decimal import Decimal
import math
from numbers import Complex from numbers import Complex
import pprint
from types import TracebackType from types import TracebackType
from typing import Any from typing import Any
from typing import Callable from typing import Callable
@ -27,6 +27,7 @@ import _pytest._code
from _pytest.compat import STRING_TYPES from _pytest.compat import STRING_TYPES
from _pytest.outcomes import fail from _pytest.outcomes import fail
if TYPE_CHECKING: if TYPE_CHECKING:
from numpy import ndarray from numpy import ndarray
@ -238,9 +239,7 @@ class ApproxMapping(ApproxBase):
with numeric values (the keys can be anything).""" with numeric values (the keys can be anything)."""
def __repr__(self) -> str: def __repr__(self) -> str:
return "approx({!r})".format( return f"approx({({k: self._approx_scalar(v) for k, v in self.expected.items()})!r})"
{k: self._approx_scalar(v) for k, v in self.expected.items()}
)
def _repr_compare(self, other_side: Mapping[object, float]) -> List[str]: def _repr_compare(self, other_side: Mapping[object, float]) -> List[str]:
import math import math
@ -315,9 +314,7 @@ class ApproxSequenceLike(ApproxBase):
seq_type = type(self.expected) seq_type = type(self.expected)
if seq_type not in (tuple, list): if seq_type not in (tuple, list):
seq_type = list seq_type = list
return "approx({!r})".format( return f"approx({seq_type(self._approx_scalar(x) for x in self.expected)!r})"
seq_type(self._approx_scalar(x) for x in self.expected)
)
def _repr_compare(self, other_side: Sequence[float]) -> List[str]: def _repr_compare(self, other_side: Sequence[float]) -> List[str]:
import math import math
@ -697,7 +694,6 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
``approx`` falls back to strict equality for nonnumeric types instead ``approx`` falls back to strict equality for nonnumeric types instead
of raising ``TypeError``. of raising ``TypeError``.
""" """
# Delegate the comparison to a class that knows how to deal with the type # 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). # of the expected value (e.g. int, float, list, dict, numpy.array, etc).
# #
@ -779,7 +775,8 @@ def raises(
expected_exception: Union[Type[E], Tuple[Type[E], ...]], expected_exception: Union[Type[E], Tuple[Type[E], ...]],
*, *,
match: Optional[Union[str, Pattern[str]]] = ..., match: Optional[Union[str, Pattern[str]]] = ...,
) -> "RaisesContext[E]": ... ) -> "RaisesContext[E]":
...
@overload @overload
@ -788,7 +785,8 @@ def raises( # noqa: F811
func: Callable[..., Any], func: Callable[..., Any],
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Any,
) -> _pytest._code.ExceptionInfo[E]: ... ) -> _pytest._code.ExceptionInfo[E]:
...
def raises( # noqa: F811 def raises( # noqa: F811
@ -837,10 +835,10 @@ def raises( # noqa: F811
The ``match`` argument searches the formatted exception string, which includes any The ``match`` argument searches the formatted exception string, which includes any
`PEP-678 <https://peps.python.org/pep-0678/>`__ ``__notes__``: `PEP-678 <https://peps.python.org/pep-0678/>`__ ``__notes__``:
>>> with pytest.raises(ValueError, match=r'had a note added'): # doctest: +SKIP >>> with pytest.raises(ValueError, match=r"had a note added"): # doctest: +SKIP
... e = ValueError("value must be 42") ... e = ValueError("value must be 42")
... e.add_note("had a note added") ... e.add_note("had a note added")
... raise e ... raise e
The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the
details of the captured exception:: details of the captured exception::
@ -855,7 +853,7 @@ def raises( # noqa: F811
Given that ``pytest.raises`` matches subclasses, be wary of using it to match :class:`Exception` like this:: 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. 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 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 real bugs, where the user wrote this expecting a specific exception, but some other exception is being

View File

@ -1,8 +1,7 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Record warnings during test function execution.""" """Record warnings during test function execution."""
import re
import warnings
from pprint import pformat from pprint import pformat
import re
from types import TracebackType from types import TracebackType
from typing import Any from typing import Any
from typing import Callable from typing import Callable
@ -17,11 +16,13 @@ from typing import Tuple
from typing import Type from typing import Type
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
import warnings
from _pytest.deprecated import check_ispytest from _pytest.deprecated import check_ispytest
from _pytest.fixtures import fixture from _pytest.fixtures import fixture
from _pytest.outcomes import fail from _pytest.outcomes import fail
T = TypeVar("T") T = TypeVar("T")
@ -41,13 +42,15 @@ def recwarn() -> Generator["WarningsRecorder", None, None]:
@overload @overload
def deprecated_call( def deprecated_call(
*, match: Optional[Union[str, Pattern[str]]] = ... *, match: Optional[Union[str, Pattern[str]]] = ...
) -> "WarningsRecorder": ... ) -> "WarningsRecorder":
...
@overload @overload
def deprecated_call( # noqa: F811 def deprecated_call( # noqa: F811
func: Callable[..., T], *args: Any, **kwargs: Any func: Callable[..., T], *args: Any, **kwargs: Any
) -> T: ... ) -> T:
...
def deprecated_call( # noqa: F811 def deprecated_call( # noqa: F811
@ -89,7 +92,8 @@ def warns(
expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = ..., expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = ...,
*, *,
match: Optional[Union[str, Pattern[str]]] = ..., match: Optional[Union[str, Pattern[str]]] = ...,
) -> "WarningsChecker": ... ) -> "WarningsChecker":
...
@overload @overload
@ -98,7 +102,8 @@ def warns( # noqa: F811
func: Callable[..., T], func: Callable[..., T],
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Any,
) -> T: ... ) -> T:
...
def warns( # noqa: F811 def warns( # noqa: F811

View File

@ -1,7 +1,7 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import dataclasses import dataclasses
import os
from io import StringIO from io import StringIO
import os
from pprint import pprint from pprint import pprint
from typing import Any from typing import Any
from typing import cast from typing import cast
@ -37,6 +37,7 @@ from _pytest.nodes import Collector
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.outcomes import skip from _pytest.outcomes import skip
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.runner import CallInfo from _pytest.runner import CallInfo
@ -46,7 +47,7 @@ def getworkerinfoline(node):
return node._workerinfocache return node._workerinfocache
except AttributeError: except AttributeError:
d = node.workerinfo d = node.workerinfo
ver = "%s.%s.%s" % d["version_info"][:3] ver = "{}.{}.{}".format(*d["version_info"][:3])
node._workerinfocache = s = "[{}] {} -- Python {} {}".format( node._workerinfocache = s = "[{}] {} -- Python {} {}".format(
d["id"], d["sysplatform"], ver, d["executable"] d["id"], d["sysplatform"], ver, d["executable"]
) )
@ -71,7 +72,8 @@ class BaseReport:
if TYPE_CHECKING: if TYPE_CHECKING:
# Can have arbitrary fields given to __init__(). # 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: def toterminal(self, out: TerminalWriter) -> None:
if hasattr(self, "node"): if hasattr(self, "node"):
@ -313,9 +315,7 @@ class TestReport(BaseReport):
self.__dict__.update(extra) self.__dict__.update(extra)
def __repr__(self) -> str: def __repr__(self) -> str:
return "<{} {!r} when={!r} outcome={!r}>".format( return f"<{self.__class__.__name__} {self.nodeid!r} when={self.when!r} outcome={self.outcome!r}>"
self.__class__.__name__, self.nodeid, self.when, self.outcome
)
@classmethod @classmethod
def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport": def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport":
@ -430,9 +430,7 @@ class CollectReport(BaseReport):
return (self.fspath, None, self.fspath) return (self.fspath, None, self.fspath)
def __repr__(self) -> str: def __repr__(self) -> str:
return "<CollectReport {!r} lenresult={} outcome={!r}>".format( return f"<CollectReport {self.nodeid!r} lenresult={len(self.result)} outcome={self.outcome!r}>"
self.nodeid, len(self.result), self.outcome
)
class CollectErrorRepr(TerminalRepr): class CollectErrorRepr(TerminalRepr):
@ -444,7 +442,7 @@ class CollectErrorRepr(TerminalRepr):
def pytest_report_to_serializable( def pytest_report_to_serializable(
report: Union[CollectReport, TestReport] report: Union[CollectReport, TestReport],
) -> Optional[Dict[str, Any]]: ) -> Optional[Dict[str, Any]]:
if isinstance(report, (TestReport, CollectReport)): if isinstance(report, (TestReport, CollectReport)):
data = report._to_json() data = report._to_json()
@ -476,7 +474,7 @@ def _report_to_json(report: BaseReport) -> Dict[str, Any]:
""" """
def serialize_repr_entry( def serialize_repr_entry(
entry: Union[ReprEntry, ReprEntryNative] entry: Union[ReprEntry, ReprEntryNative],
) -> Dict[str, Any]: ) -> Dict[str, Any]:
data = dataclasses.asdict(entry) data = dataclasses.asdict(entry)
for key, value in data.items(): for key, value in data.items():
@ -608,9 +606,9 @@ def _report_kwargs_from_json(reportdict: Dict[str, Any]) -> Dict[str, Any]:
description, description,
) )
) )
exception_info: Union[ExceptionChainRepr, ReprExceptionInfo] = ( exception_info: Union[
ExceptionChainRepr(chain) ExceptionChainRepr, ReprExceptionInfo
) ] = ExceptionChainRepr(chain)
else: else:
exception_info = ReprExceptionInfo( exception_info = ReprExceptionInfo(
reprtraceback=reprtraceback, reprtraceback=reprtraceback,

View File

@ -37,6 +37,7 @@ from _pytest.outcomes import OutcomeException
from _pytest.outcomes import Skipped from _pytest.outcomes import Skipped
from _pytest.outcomes import TEST_OUTCOME from _pytest.outcomes import TEST_OUTCOME
if sys.version_info[:2] < (3, 11): if sys.version_info[:2] < (3, 11):
from exceptiongroup import BaseExceptionGroup from exceptiongroup import BaseExceptionGroup
@ -94,8 +95,7 @@ def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None:
if verbose < 2 and rep.duration < durations_min: if verbose < 2 and rep.duration < durations_min:
tr.write_line("") tr.write_line("")
tr.write_line( tr.write_line(
"(%s durations < %gs hidden. Use -vv to show these durations.)" f"({len(dlist) - i} durations < {durations_min:g}s hidden. Use -vv to show these durations.)"
% (len(dlist) - i, durations_min)
) )
break break
tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}") tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}")

View File

@ -13,6 +13,7 @@ from functools import total_ordering
from typing import Literal from typing import Literal
from typing import Optional from typing import Optional
_ScopeName = Literal["session", "package", "module", "class", "function"] _ScopeName = Literal["session", "package", "module", "class", "function"]

View File

@ -2,7 +2,6 @@ from typing import Generator
from typing import Optional from typing import Optional
from typing import Union from typing import Union
import pytest
from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import ExitCode from _pytest.config import ExitCode
@ -10,6 +9,7 @@ from _pytest.config.argparsing import Parser
from _pytest.fixtures import FixtureDef from _pytest.fixtures import FixtureDef
from _pytest.fixtures import SubRequest from _pytest.fixtures import SubRequest
from _pytest.scope import Scope from _pytest.scope import Scope
import pytest
def pytest_addoption(parser: Parser) -> None: def pytest_addoption(parser: Parser) -> None:
@ -74,7 +74,7 @@ def _show_fixture_action(
scope_indent = list(reversed(Scope)).index(fixturedef._scope) scope_indent = list(reversed(Scope)).index(fixturedef._scope)
tw.write(" " * 2 * scope_indent) tw.write(" " * 2 * scope_indent)
tw.write( tw.write(
"{step} {scope} {fixture}".format( "{step} {scope} {fixture}".format( # noqa: UP032 (Readability)
step=msg.ljust(8), # align the output to TEARDOWN step=msg.ljust(8), # align the output to TEARDOWN
scope=fixturedef.scope[0].upper(), scope=fixturedef.scope[0].upper(),
fixture=fixturedef.argname, fixture=fixturedef.argname,

View File

@ -1,12 +1,12 @@
from typing import Optional from typing import Optional
from typing import Union from typing import Union
import pytest
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.fixtures import FixtureDef from _pytest.fixtures import FixtureDef
from _pytest.fixtures import SubRequest from _pytest.fixtures import SubRequest
import pytest
def pytest_addoption(parser: Parser) -> None: def pytest_addoption(parser: Parser) -> None:

View File

@ -1,11 +1,11 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
"""Support for skip/xfail functions and markers.""" """Support for skip/xfail functions and markers."""
from collections.abc import Mapping
import dataclasses import dataclasses
import os import os
import platform import platform
import sys import sys
import traceback import traceback
from collections.abc import Mapping
from typing import Generator from typing import Generator
from typing import Optional from typing import Optional
from typing import Tuple from typing import Tuple
@ -105,9 +105,7 @@ def evaluate_condition(item: Item, mark: Mark, condition: object) -> Tuple[bool,
): ):
if not isinstance(dictionary, Mapping): if not isinstance(dictionary, Mapping):
raise ValueError( raise ValueError(
"pytest_markeval_namespace() needs to return a dict, got {!r}".format( f"pytest_markeval_namespace() needs to return a dict, got {dictionary!r}"
dictionary
)
) )
globals_.update(dictionary) globals_.update(dictionary)
if hasattr(item, "obj"): if hasattr(item, "obj"):

View File

@ -5,6 +5,7 @@ from typing import Generic
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
__all__ = ["Stash", "StashKey"] __all__ = ["Stash", "StashKey"]

View File

@ -2,12 +2,13 @@ from typing import List
from typing import Optional from typing import Optional
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import pytest
from _pytest import nodes from _pytest import nodes
from _pytest.config import Config from _pytest.config import Config
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.main import Session from _pytest.main import Session
from _pytest.reports import TestReport from _pytest.reports import TestReport
import pytest
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.cacheprovider import Cache from _pytest.cacheprovider import Cache

View File

@ -4,16 +4,15 @@
This is a good source for looking at the various reporting hooks. This is a good source for looking at the various reporting hooks.
""" """
import argparse import argparse
from collections import Counter
import dataclasses import dataclasses
import datetime import datetime
from functools import partial
import inspect import inspect
from pathlib import Path
import platform import platform
import sys import sys
import textwrap import textwrap
import warnings
from collections import Counter
from functools import partial
from pathlib import Path
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import ClassVar from typing import ClassVar
@ -31,16 +30,17 @@ from typing import TextIO
from typing import Tuple from typing import Tuple
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Union from typing import Union
import warnings
import pluggy import pluggy
import _pytest._version
from _pytest import nodes from _pytest import nodes
from _pytest import timing from _pytest import timing
from _pytest._code import ExceptionInfo from _pytest._code import ExceptionInfo
from _pytest._code.code import ExceptionRepr from _pytest._code.code import ExceptionRepr
from _pytest._io import TerminalWriter from _pytest._io import TerminalWriter
from _pytest._io.wcwidth import wcswidth from _pytest._io.wcwidth import wcswidth
import _pytest._version
from _pytest.assertion.util import running_on_ci from _pytest.assertion.util import running_on_ci
from _pytest.config import _PluggyPlugin from _pytest.config import _PluggyPlugin
from _pytest.config import Config from _pytest.config import Config
@ -55,6 +55,7 @@ from _pytest.reports import BaseReport
from _pytest.reports import CollectReport from _pytest.reports import CollectReport
from _pytest.reports import TestReport from _pytest.reports import TestReport
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.main import Session from _pytest.main import Session
@ -671,8 +672,8 @@ class TerminalReporter:
return f" [ {collected} / {collected} ]" return f" [ {collected} / {collected} ]"
else: else:
if collected: if collected:
return " [{:3d}%]".format( return (
len(self._progress_nodeids_reported) * 100 // collected f" [{len(self._progress_nodeids_reported) * 100 // collected:3d}%]"
) )
return " [100%]" return " [100%]"
@ -757,9 +758,7 @@ class TerminalReporter:
if pypy_version_info: if pypy_version_info:
verinfo = ".".join(map(str, pypy_version_info[:3])) verinfo = ".".join(map(str, pypy_version_info[:3]))
msg += f"[pypy-{verinfo}-{pypy_version_info[3]}]" msg += f"[pypy-{verinfo}-{pypy_version_info[3]}]"
msg += ", pytest-{}, pluggy-{}".format( msg += f", pytest-{_pytest._version.version}, pluggy-{pluggy.__version__}"
_pytest._version.version, pluggy.__version__
)
if ( if (
self.verbosity > 0 self.verbosity > 0
or self.config.option.debug or self.config.option.debug
@ -1464,7 +1463,7 @@ def _plugin_nameversions(plugininfo) -> List[str]:
values: List[str] = [] values: List[str] = []
for plugin, dist in plugininfo: for plugin, dist in plugininfo:
# Gets us name and version! # 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. # Questionable convenience, but it keeps things short.
if name.startswith("pytest-"): if name.startswith("pytest-"):
name = name[7:] name = name[7:]

View File

@ -1,12 +1,12 @@
import threading import threading
import traceback import traceback
import warnings
from types import TracebackType from types import TracebackType
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Generator from typing import Generator
from typing import Optional from typing import Optional
from typing import Type from typing import Type
import warnings
import pytest import pytest

View File

@ -10,4 +10,5 @@ from time import perf_counter
from time import sleep from time import sleep
from time import time from time import time
__all__ = ["perf_counter", "sleep", "time"] __all__ = ["perf_counter", "sleep", "time"]

View File

@ -2,10 +2,10 @@
"""Support for providing temporary directories to test functions.""" """Support for providing temporary directories to test functions."""
import dataclasses import dataclasses
import os import os
import re
import tempfile
from pathlib import Path from pathlib import Path
import re
from shutil import rmtree from shutil import rmtree
import tempfile
from typing import Any from typing import Any
from typing import Dict from typing import Dict
from typing import final from typing import final
@ -32,6 +32,7 @@ from _pytest.nodes import Item
from _pytest.reports import TestReport from _pytest.reports import TestReport
from _pytest.stash import StashKey from _pytest.stash import StashKey
tmppath_result_key = StashKey[Dict[str, bool]]() tmppath_result_key = StashKey[Dict[str, bool]]()
RetentionType = Literal["all", "failed", "none"] RetentionType = Literal["all", "failed", "none"]
@ -268,7 +269,6 @@ def tmp_path(
The returned object is a :class:`pathlib.Path` object. The returned object is a :class:`pathlib.Path` object.
""" """
path = _mk_tmp(request, tmp_path_factory) path = _mk_tmp(request, tmp_path_factory)
yield path yield path

View File

@ -15,7 +15,6 @@ from typing import TYPE_CHECKING
from typing import Union from typing import Union
import _pytest._code import _pytest._code
import pytest
from _pytest.compat import getimfunc from _pytest.compat import getimfunc
from _pytest.compat import is_async_function from _pytest.compat import is_async_function
from _pytest.config import hookimpl from _pytest.config import hookimpl
@ -30,6 +29,8 @@ from _pytest.python import Class
from _pytest.python import Function from _pytest.python import Function
from _pytest.python import Module from _pytest.python import Module
from _pytest.runner import CallInfo from _pytest.runner import CallInfo
import pytest
if TYPE_CHECKING: if TYPE_CHECKING:
import unittest import unittest
@ -203,7 +204,9 @@ class TestCaseFunction(Function):
# Unwrap potential exception info (see twisted trial support below). # Unwrap potential exception info (see twisted trial support below).
rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo) rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo)
try: 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 # Invoke the attributes to trigger storing the traceback
# trial causes some issue there. # trial causes some issue there.
excinfo.value excinfo.value
@ -223,7 +226,7 @@ class TestCaseFunction(Function):
except BaseException: except BaseException:
fail( fail(
"ERROR: Unknown Incompatible Exception " "ERROR: Unknown Incompatible Exception "
"representation:\n%r" % (rawexcinfo,), f"representation:\n{rawexcinfo!r}",
pytrace=False, pytrace=False,
) )
except KeyboardInterrupt: except KeyboardInterrupt:
@ -348,9 +351,7 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None:
# handled internally, and doesn't reach here. # handled internally, and doesn't reach here.
unittest = sys.modules.get("unittest") unittest = sys.modules.get("unittest")
if ( if (
unittest unittest and call.excinfo and isinstance(call.excinfo.value, unittest.SkipTest) # type: ignore[attr-defined]
and call.excinfo
and isinstance(call.excinfo.value, unittest.SkipTest) # type: ignore[attr-defined]
): ):
excinfo = call.excinfo excinfo = call.excinfo
call2 = CallInfo[None].from_call( call2 = CallInfo[None].from_call(

View File

@ -1,12 +1,12 @@
import sys import sys
import traceback import traceback
import warnings
from types import TracebackType from types import TracebackType
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Generator from typing import Generator
from typing import Optional from typing import Optional
from typing import Type from typing import Type
import warnings
import pytest import pytest

View File

@ -1,12 +1,12 @@
import dataclasses import dataclasses
import inspect import inspect
import warnings
from types import FunctionType from types import FunctionType
from typing import Any from typing import Any
from typing import final from typing import final
from typing import Generic from typing import Generic
from typing import Type from typing import Type
from typing import TypeVar from typing import TypeVar
import warnings
class PytestWarning(UserWarning): class PytestWarning(UserWarning):
@ -73,11 +73,7 @@ class PytestExperimentalApiWarning(PytestWarning, FutureWarning):
@classmethod @classmethod
def simple(cls, apiname: str) -> "PytestExperimentalApiWarning": def simple(cls, apiname: str) -> "PytestExperimentalApiWarning":
return cls( return cls(f"{apiname} is an experimental api that may change over time")
"{apiname} is an experimental api that may change over time".format(
apiname=apiname
)
)
@final @final

View File

@ -1,18 +1,18 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import sys
import warnings
from contextlib import contextmanager from contextlib import contextmanager
import sys
from typing import Generator from typing import Generator
from typing import Literal from typing import Literal
from typing import Optional from typing import Optional
import warnings
import pytest
from _pytest.config import apply_warning_filters from _pytest.config import apply_warning_filters
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import parse_warning_filter from _pytest.config import parse_warning_filter
from _pytest.main import Session from _pytest.main import Session
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
import pytest
def pytest_configure(config: Config) -> None: def pytest_configure(config: Config) -> None:

View File

@ -6,6 +6,7 @@ import sys
import _pytest._py.error as error import _pytest._py.error as error
import _pytest._py.path as path import _pytest._py.path as path
sys.modules["py.error"] = error sys.modules["py.error"] = error
sys.modules["py.path"] = path sys.modules["py.path"] = path

View File

@ -81,6 +81,7 @@ from _pytest.warning_types import PytestUnknownMarkWarning
from _pytest.warning_types import PytestUnraisableExceptionWarning from _pytest.warning_types import PytestUnraisableExceptionWarning
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
set_trace = __pytestPDB.set_trace set_trace = __pytestPDB.set_trace

View File

@ -2,5 +2,6 @@
import pytest import pytest
if __name__ == "__main__": if __name__ == "__main__":
raise SystemExit(pytest.console_main()) raise SystemExit(pytest.console_main())

View File

@ -4,8 +4,8 @@ import multiprocessing
import os import os
import sys import sys
import time import time
import warnings
from unittest import mock from unittest import mock
import warnings
from py import error from py import error
from py.path import local from py.path import local
@ -183,7 +183,7 @@ class CommonFSTests:
def test_listdir_filter(self, path1): def test_listdir_filter(self, path1):
p = path1.listdir(lambda x: x.check(dir=1)) p = path1.listdir(lambda x: x.check(dir=1))
assert path1.join("sampledir") in p 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): def test_listdir_sorted(self, path1):
p = path1.listdir(lambda x: x.check(basestarts="sample"), sort=True) p = path1.listdir(lambda x: x.check(basestarts="sample"), sort=True)
@ -203,7 +203,7 @@ class CommonFSTests:
for i in path1.visit(None, lambda x: x.basename != "sampledir"): for i in path1.visit(None, lambda x: x.basename != "sampledir"):
lst.append(i.relto(path1)) lst.append(i.relto(path1))
assert "sampledir" in lst 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( @pytest.mark.parametrize(
"fil", "fil",

View File

@ -6,10 +6,10 @@ import subprocess
import sys import sys
import types import types
import pytest
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.pathlib import symlink_or_skip from _pytest.pathlib import symlink_or_skip
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
import pytest
def prepend_pythonpath(*dirs) -> str: def prepend_pythonpath(*dirs) -> str:

View File

@ -4,13 +4,13 @@ import sys
from types import FrameType from types import FrameType
from unittest import mock from unittest import mock
import pytest
from _pytest._code import Code from _pytest._code import Code
from _pytest._code import ExceptionInfo from _pytest._code import ExceptionInfo
from _pytest._code import Frame from _pytest._code import Frame
from _pytest._code import Source from _pytest._code import Source
from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ReprFuncArgs from _pytest._code.code import ReprFuncArgs
import pytest
def test_ne() -> None: def test_ne() -> None:

View File

@ -4,16 +4,15 @@ from __future__ import annotations
import importlib import importlib
import io import io
import operator import operator
from pathlib import Path
import queue import queue
import re import re
import sys import sys
import textwrap import textwrap
from pathlib import Path
from typing import Any from typing import Any
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _pytest._code import _pytest._code
import pytest
from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionInfo
from _pytest._code.code import FormattedExcinfo from _pytest._code.code import FormattedExcinfo
@ -23,6 +22,8 @@ from _pytest.pathlib import bestrelpath
from _pytest.pathlib import import_path from _pytest.pathlib import import_path
from _pytest.pytester import LineMatcher from _pytest.pytester import LineMatcher
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
import pytest
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest._code.code import _TracebackStyle from _pytest._code.code import _TracebackStyle
@ -1173,9 +1174,7 @@ raise ValueError()
"funcargs": funcargs, "funcargs": funcargs,
"tbfilter": tbfilter, "tbfilter": tbfilter,
}, },
id="style={},showlocals={},funcargs={},tbfilter={}".format( id=f"style={style},showlocals={showlocals},funcargs={funcargs},tbfilter={tbfilter}",
style, showlocals, funcargs, tbfilter
),
) )
for style in ["long", "short", "line", "no", "native", "value", "auto"] for style in ["long", "short", "line", "no", "native", "value", "auto"]
for showlocals in (True, False) for showlocals in (True, False)
@ -1339,7 +1338,7 @@ raise ValueError()
""" """
raise_suffix = " from None" if mode == "from_none" else "" raise_suffix = " from None" if mode == "from_none" else ""
mod = importasmod( mod = importasmod(
""" f"""
def f(): def f():
try: try:
g() g()
@ -1347,9 +1346,7 @@ raise ValueError()
raise AttributeError(){raise_suffix} raise AttributeError(){raise_suffix}
def g(): def g():
raise ValueError() raise ValueError()
""".format( """
raise_suffix=raise_suffix
)
) )
excinfo = pytest.raises(AttributeError, mod.f) excinfo = pytest.raises(AttributeError, mod.f)
r = excinfo.getrepr(style="long", chain=mode != "explicit_suppress") r = excinfo.getrepr(style="long", chain=mode != "explicit_suppress")
@ -1361,9 +1358,7 @@ raise ValueError()
assert tw_mock.lines[2] == " try:" assert tw_mock.lines[2] == " try:"
assert tw_mock.lines[3] == " g()" assert tw_mock.lines[3] == " g()"
assert tw_mock.lines[4] == " except Exception:" assert tw_mock.lines[4] == " except Exception:"
assert tw_mock.lines[5] == "> raise AttributeError(){}".format( assert tw_mock.lines[5] == f"> raise AttributeError(){raise_suffix}"
raise_suffix
)
assert tw_mock.lines[6] == "E AttributeError" assert tw_mock.lines[6] == "E AttributeError"
assert tw_mock.lines[7] == "" assert tw_mock.lines[7] == ""
line = tw_mock.get_write_msg(8) line = tw_mock.get_write_msg(8)
@ -1394,7 +1389,7 @@ raise ValueError()
""" """
exc_handling_code = " from e" if reason == "cause" else "" exc_handling_code = " from e" if reason == "cause" else ""
mod = importasmod( mod = importasmod(
""" f"""
def f(): def f():
try: try:
g() g()
@ -1402,9 +1397,7 @@ raise ValueError()
raise RuntimeError('runtime problem'){exc_handling_code} raise RuntimeError('runtime problem'){exc_handling_code}
def g(): def g():
raise ValueError('invalid value') raise ValueError('invalid value')
""".format( """
exc_handling_code=exc_handling_code
)
) )
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:

View File

@ -5,9 +5,10 @@ import sys
from typing import Generator from typing import Generator
from typing import List from typing import List
import pytest
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
import pytest
if sys.gettrace(): if sys.gettrace():

View File

@ -1,7 +1,7 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import pytest
from _pytest import deprecated from _pytest import deprecated
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
import pytest
from pytest import PytestDeprecationWarning from pytest import PytestDeprecationWarning

View File

@ -4,6 +4,7 @@ from unittest import mock
import pytest import pytest
config = {"mykey": "ORIGINAL"} config = {"mykey": "ORIGINAL"}

View File

@ -2,6 +2,7 @@
import argparse import argparse
import pathlib import pathlib
HERE = pathlib.Path(__file__).parent HERE = pathlib.Path(__file__).parent
TEST_CONTENT = (HERE / "template_test.py").read_bytes() TEST_CONTENT = (HERE / "template_test.py").read_bytes()

View File

@ -2,6 +2,7 @@
from typing import List from typing import List
from unittest import IsolatedAsyncioTestCase from unittest import IsolatedAsyncioTestCase
teardowns: List[None] = [] teardowns: List[None] = []

View File

@ -5,6 +5,7 @@ from typing import List
import asynctest import asynctest
teardowns: List[None] = [] teardowns: List[None] = []

View File

@ -1,16 +1,16 @@
import textwrap
from collections import ChainMap from collections import ChainMap
from collections import Counter from collections import Counter
from collections import defaultdict from collections import defaultdict
from collections import deque from collections import deque
from collections import OrderedDict from collections import OrderedDict
from dataclasses import dataclass from dataclasses import dataclass
import textwrap
from types import MappingProxyType from types import MappingProxyType
from types import SimpleNamespace from types import SimpleNamespace
from typing import Any from typing import Any
import pytest
from _pytest._io.pprint import PrettyPrinter from _pytest._io.pprint import PrettyPrinter
import pytest
@dataclass @dataclass

View File

@ -1,8 +1,8 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import pytest
from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE
from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr
from _pytest._io.saferepr import saferepr_unlimited from _pytest._io.saferepr import saferepr_unlimited
import pytest
def test_simple_repr(): def test_simple_repr():
@ -59,9 +59,7 @@ def test_exceptions() -> None:
obj = BrokenRepr(BrokenReprException("omg even worse")) obj = BrokenRepr(BrokenReprException("omg even worse"))
s2 = saferepr(obj) s2 = saferepr(obj)
assert s2 == ( assert s2 == (
"<[unpresentable exception ({!s}) raised in repr()] BrokenRepr object at 0x{:x}>".format( f"<[unpresentable exception ({exp_exc!s}) raised in repr()] BrokenRepr object at 0x{id(obj):x}>"
exp_exc, id(obj)
)
) )
@ -99,14 +97,12 @@ def test_baseexception():
baseexc_str = BaseException("__str__") baseexc_str = BaseException("__str__")
obj = BrokenObj(RaisingOnStrRepr([BaseException])) obj = BrokenObj(RaisingOnStrRepr([BaseException]))
assert saferepr(obj) == ( assert saferepr(obj) == (
"<[unpresentable exception ({!r}) " f"<[unpresentable exception ({baseexc_str!r}) "
"raised in repr()] BrokenObj object at 0x{:x}>".format(baseexc_str, id(obj)) f"raised in repr()] BrokenObj object at 0x{id(obj):x}>"
) )
obj = BrokenObj(RaisingOnStrRepr([RaisingOnStrRepr([BaseException])])) obj = BrokenObj(RaisingOnStrRepr([RaisingOnStrRepr([BaseException])]))
assert saferepr(obj) == ( assert saferepr(obj) == (
"<[{!r} raised in repr()] BrokenObj object at 0x{:x}>".format( f"<[{baseexc_str!r} raised in repr()] BrokenObj object at 0x{id(obj):x}>"
baseexc_str, id(obj)
)
) )
with pytest.raises(KeyboardInterrupt): with pytest.raises(KeyboardInterrupt):

View File

@ -1,17 +1,18 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import io import io
import os import os
from pathlib import Path
import re import re
import shutil import shutil
import sys import sys
from pathlib import Path
from typing import Generator from typing import Generator
from typing import Optional from typing import Optional
from unittest import mock from unittest import mock
import pytest
from _pytest._io import terminalwriter from _pytest._io import terminalwriter
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
import pytest
# These tests were initially copied from py 1.8.1. # These tests were initially copied from py 1.8.1.

View File

@ -1,6 +1,6 @@
import pytest
from _pytest._io.wcwidth import wcswidth from _pytest._io.wcwidth import wcswidth
from _pytest._io.wcwidth import wcwidth from _pytest._io.wcwidth import wcwidth
import pytest
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -3,9 +3,10 @@
import logging import logging
from typing import Iterator from typing import Iterator
import pytest
from _pytest.logging import caplog_records_key from _pytest.logging import caplog_records_key
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
import pytest
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
sublogger = logging.getLogger(__name__ + ".baz") sublogger = logging.getLogger(__name__ + ".baz")

View File

@ -4,12 +4,12 @@ import os
import re import re
from typing import cast from typing import cast
import pytest
from _pytest.capture import CaptureManager from _pytest.capture import CaptureManager
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
import pytest
def test_nothing_logged(pytester: Pytester) -> None: def test_nothing_logged(pytester: Pytester) -> None:
@ -177,13 +177,11 @@ def test_teardown_logging(pytester: Pytester) -> None:
def test_log_cli_enabled_disabled(pytester: Pytester, enabled: bool) -> None: def test_log_cli_enabled_disabled(pytester: Pytester, enabled: bool) -> None:
msg = "critical message logged by test" msg = "critical message logged by test"
pytester.makepyfile( pytester.makepyfile(
""" f"""
import logging import logging
def test_log_cli(): def test_log_cli():
logging.critical("{}") logging.critical("{msg}")
""".format( """
msg
)
) )
if enabled: if enabled:
pytester.makeini( pytester.makeini(
@ -710,13 +708,11 @@ def test_log_file_ini(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log")) log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makeini( pytester.makeini(
""" f"""
[pytest] [pytest]
log_file={} log_file={log_file}
log_file_level=WARNING log_file_level=WARNING
""".format( """
log_file
)
) )
pytester.makepyfile( pytester.makepyfile(
""" """
@ -749,13 +745,11 @@ def test_log_file_ini_level(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log")) log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makeini( pytester.makeini(
""" f"""
[pytest] [pytest]
log_file={} log_file={log_file}
log_file_level = INFO log_file_level = INFO
""".format( """
log_file
)
) )
pytester.makepyfile( pytester.makepyfile(
""" """
@ -788,13 +782,11 @@ def test_log_file_unicode(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log")) log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makeini( pytester.makeini(
""" f"""
[pytest] [pytest]
log_file={} log_file={log_file}
log_file_level = INFO log_file_level = INFO
""".format( """
log_file
)
) )
pytester.makepyfile( pytester.makepyfile(
"""\ """\
@ -832,8 +824,8 @@ def test_live_logging_suspends_capture(
is installed. is installed.
""" """
import contextlib import contextlib
import logging
from functools import partial from functools import partial
import logging
from _pytest.logging import _LiveLoggingStreamHandler from _pytest.logging import _LiveLoggingStreamHandler
@ -924,13 +916,11 @@ def test_collection_logging_to_file(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log")) log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makeini( pytester.makeini(
""" f"""
[pytest] [pytest]
log_file={} log_file={log_file}
log_file_level = INFO log_file_level = INFO
""".format( """
log_file
)
) )
pytester.makepyfile( pytester.makepyfile(
@ -962,14 +952,12 @@ def test_log_in_hooks(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log")) log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makeini( pytester.makeini(
""" f"""
[pytest] [pytest]
log_file={} log_file={log_file}
log_file_level = INFO log_file_level = INFO
log_cli=true log_cli=true
""".format( """
log_file
)
) )
pytester.makeconftest( pytester.makeconftest(
""" """
@ -998,14 +986,12 @@ def test_log_in_runtest_logreport(pytester: Pytester) -> None:
log_file = str(pytester.path.joinpath("pytest.log")) log_file = str(pytester.path.joinpath("pytest.log"))
pytester.makeini( pytester.makeini(
""" f"""
[pytest] [pytest]
log_file={} log_file={log_file}
log_file_level = INFO log_file_level = INFO
log_cli=true log_cli=true
""".format( """
log_file
)
) )
pytester.makeconftest( pytester.makeconftest(
""" """
@ -1039,19 +1025,17 @@ def test_log_set_path(pytester: Pytester) -> None:
""" """
) )
pytester.makeconftest( pytester.makeconftest(
""" f"""
import os import os
import pytest import pytest
@pytest.hookimpl(wrapper=True, tryfirst=True) @pytest.hookimpl(wrapper=True, tryfirst=True)
def pytest_runtest_setup(item): def pytest_runtest_setup(item):
config = item.config config = item.config
logging_plugin = config.pluginmanager.get_plugin("logging-plugin") 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) logging_plugin.set_log_path(report_file)
return (yield) return (yield)
""".format( """
repr(report_dir_base)
)
) )
pytester.makepyfile( pytester.makepyfile(
""" """

View File

@ -1,18 +1,19 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import operator
from contextlib import contextmanager from contextlib import contextmanager
from decimal import Decimal from decimal import Decimal
from fractions import Fraction from fractions import Fraction
from math import sqrt from math import sqrt
import operator
from operator import eq from operator import eq
from operator import ne from operator import ne
from typing import Optional from typing import Optional
import pytest
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
from _pytest.python_api import _recursive_sequence_map from _pytest.python_api import _recursive_sequence_map
import pytest
from pytest import approx from pytest import approx
inf, nan = float("inf"), float("nan") inf, nan = float("inf"), float("nan")
@ -38,9 +39,7 @@ def mocked_doctest_runner(monkeypatch):
class MyDocTestRunner(doctest.DocTestRunner): class MyDocTestRunner(doctest.DocTestRunner):
def report_failure(self, out, test, example, got): def report_failure(self, out, test, example, got):
raise AssertionError( raise AssertionError(
"'{}' evaluates to '{}', not '{}'".format( f"'{example.source.strip()}' evaluates to '{got.strip()}', not '{example.want.strip()}'"
example.source.strip(), got.strip(), example.want.strip()
)
) )
return MyDocTestRunner() return MyDocTestRunner()

View File

@ -6,7 +6,6 @@ from typing import Any
from typing import Dict from typing import Dict
import _pytest._code import _pytest._code
import pytest
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.main import Session from _pytest.main import Session
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
@ -14,6 +13,7 @@ from _pytest.nodes import Collector
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
from _pytest.python import Class from _pytest.python import Class
from _pytest.python import Function from _pytest.python import Function
import pytest
class TestModule: class TestModule:
@ -54,13 +54,11 @@ class TestModule:
monkeypatch.syspath_prepend(str(root1)) monkeypatch.syspath_prepend(str(root1))
p.write_text( p.write_text(
textwrap.dedent( textwrap.dedent(
"""\ f"""\
import x456 import x456
def test(): def test():
assert x456.__file__.startswith({!r}) assert x456.__file__.startswith({str(root2)!r})
""".format( """
str(root2)
)
), ),
encoding="utf-8", encoding="utf-8",
) )

View File

@ -1,10 +1,9 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import os import os
from pathlib import Path
import sys import sys
import textwrap import textwrap
from pathlib import Path
import pytest
from _pytest.compat import getfuncargnames from _pytest.compat import getfuncargnames
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.fixtures import deduplicate_names from _pytest.fixtures import deduplicate_names
@ -13,6 +12,7 @@ from _pytest.monkeypatch import MonkeyPatch
from _pytest.pytester import get_public_names from _pytest.pytester import get_public_names
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
from _pytest.python import Function from _pytest.python import Function
import pytest
def test_getfuncargnames_functions(): def test_getfuncargnames_functions():
@ -1288,7 +1288,7 @@ class TestFixtureUsages:
@pytest.mark.parametrize("scope", ["function", "session"]) @pytest.mark.parametrize("scope", ["function", "session"])
def test_parameters_without_eq_semantics(self, scope, pytester: Pytester) -> None: def test_parameters_without_eq_semantics(self, scope, pytester: Pytester) -> None:
pytester.makepyfile( pytester.makepyfile(
""" f"""
class NoEq1: # fails on `a == b` statement class NoEq1: # fails on `a == b` statement
def __eq__(self, _): def __eq__(self, _):
raise RuntimeError raise RuntimeError
@ -1310,9 +1310,7 @@ class TestFixtureUsages:
def test2(no_eq): def test2(no_eq):
pass pass
""".format( """
scope=scope
)
) )
result = pytester.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["*4 passed*"]) result.stdout.fnmatch_lines(["*4 passed*"])
@ -2199,7 +2197,7 @@ class TestAutouseManagement:
pass pass
def test_check(): def test_check():
assert values == ["new1", "new2", "fin2", "fin1"] assert values == ["new1", "new2", "fin2", "fin1"]
""" """ # noqa: UP031 (python syntax issues)
% locals() % locals()
) )
reprec = pytester.inline_run("-s") reprec = pytester.inline_run("-s")
@ -3087,8 +3085,8 @@ class TestFixtureMarker:
pass pass
def test_other(): def test_other():
pass pass
""" """ # noqa: UP031 (python syntax issues)
% {"scope": scope} % {"scope": scope} # noqa: UP031 (python syntax issues)
) )
reprec = pytester.inline_run("-lvs") reprec = pytester.inline_run("-lvs")
reprec.assertoutcome(passed=3) reprec.assertoutcome(passed=3)
@ -3287,7 +3285,7 @@ class TestRequestScopeAccess:
assert request.config assert request.config
def test_func(): def test_func():
pass pass
""" """ # noqa: UP031 (python syntax issues)
% (scope, ok.split(), error.split()) % (scope, ok.split(), error.split())
) )
reprec = pytester.inline_run("-l") reprec = pytester.inline_run("-l")
@ -3308,7 +3306,7 @@ class TestRequestScopeAccess:
assert request.config assert request.config
def test_func(arg): def test_func(arg):
pass pass
""" """ # noqa: UP031 (python syntax issues)
% (scope, ok.split(), error.split()) % (scope, ok.split(), error.split())
) )
reprec = pytester.inline_run() reprec = pytester.inline_run()

Some files were not shown because too many files have changed in this diff Show More