Use attr.s(auto_attribs=True) in more places

It's nicer to read without the attr.ib noise.
This commit is contained in:
Ran Benita 2021-10-04 18:32:05 +03:00
parent dced00e60f
commit e5468681b0
13 changed files with 103 additions and 109 deletions

View File

@ -1,3 +1,4 @@
import ast
import inspect
import re
import sys
@ -12,6 +13,7 @@ from types import FrameType
from types import TracebackType
from typing import Any
from typing import Callable
from typing import ClassVar
from typing import Dict
from typing import Generic
from typing import Iterable
@ -238,7 +240,9 @@ class TracebackEntry:
def getfirstlinesource(self) -> int:
return self.frame.code.firstlineno
def getsource(self, astcache=None) -> Optional["Source"]:
def getsource(
self, astcache: Optional[Dict[Union[str, Path], ast.AST]] = None
) -> Optional["Source"]:
"""Return failing source code."""
# we use the passed in astcache to not reparse asttrees
# within exception info printing
@ -258,7 +262,7 @@ class TracebackEntry:
except SyntaxError:
end = self.lineno + 1
else:
if key is not None:
if key is not None and astcache is not None:
astcache[key] = astnode
return source[start:end]
@ -435,15 +439,15 @@ E = TypeVar("E", bound=BaseException, covariant=True)
@final
@attr.s(repr=False, init=False)
@attr.s(repr=False, init=False, auto_attribs=True)
class ExceptionInfo(Generic[E]):
"""Wraps sys.exc_info() objects and offers help for navigating the traceback."""
_assert_start_repr = "AssertionError('assert "
_assert_start_repr: ClassVar = "AssertionError('assert "
_excinfo = attr.ib(type=Optional[Tuple[Type["E"], "E", TracebackType]])
_striptext = attr.ib(type=str)
_traceback = attr.ib(type=Optional[Traceback])
_excinfo: Optional[Tuple[Type["E"], "E", TracebackType]]
_striptext: str
_traceback: Optional[Traceback]
def __init__(
self,
@ -673,22 +677,24 @@ class ExceptionInfo(Generic[E]):
return True
@attr.s
@attr.s(auto_attribs=True)
class FormattedExcinfo:
"""Presenting information about failing Functions and Generators."""
# for traceback entries
flow_marker = ">"
fail_marker = "E"
flow_marker: ClassVar = ">"
fail_marker: ClassVar = "E"
showlocals = attr.ib(type=bool, default=False)
style = attr.ib(type="_TracebackStyle", default="long")
abspath = attr.ib(type=bool, default=True)
tbfilter = attr.ib(type=bool, default=True)
funcargs = attr.ib(type=bool, default=False)
truncate_locals = attr.ib(type=bool, default=True)
chain = attr.ib(type=bool, default=True)
astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False)
showlocals: bool = False
style: "_TracebackStyle" = "long"
abspath: bool = True
tbfilter: bool = True
funcargs: bool = False
truncate_locals: bool = True
chain: bool = True
astcache: Dict[Union[str, Path], ast.AST] = attr.ib(
factory=dict, init=False, repr=False
)
def _getindent(self, source: "Source") -> int:
# Figure out indent for the given source.
@ -951,7 +957,7 @@ class FormattedExcinfo:
return ExceptionChainRepr(repr_chain)
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class TerminalRepr:
def __str__(self) -> str:
# FYI this is called from pytest-xdist's serialization of exception
@ -987,13 +993,9 @@ class ExceptionRepr(TerminalRepr):
tw.line(content)
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ExceptionChainRepr(ExceptionRepr):
chain = attr.ib(
type=Sequence[
Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]
]
)
chain: Sequence[Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]]
def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
@ -1011,23 +1013,23 @@ class ExceptionChainRepr(ExceptionRepr):
super().toterminal(tw)
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ReprExceptionInfo(ExceptionRepr):
reprtraceback = attr.ib(type="ReprTraceback")
reprcrash = attr.ib(type="ReprFileLocation")
reprtraceback: "ReprTraceback"
reprcrash: "ReprFileLocation"
def toterminal(self, tw: TerminalWriter) -> None:
self.reprtraceback.toterminal(tw)
super().toterminal(tw)
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ReprTraceback(TerminalRepr):
reprentries = attr.ib(type=Sequence[Union["ReprEntry", "ReprEntryNative"]])
extraline = attr.ib(type=Optional[str])
style = attr.ib(type="_TracebackStyle")
reprentries: Sequence[Union["ReprEntry", "ReprEntryNative"]]
extraline: Optional[str]
style: "_TracebackStyle"
entrysep = "_ "
entrysep: ClassVar = "_ "
def toterminal(self, tw: TerminalWriter) -> None:
# The entries might have different styles.
@ -1055,22 +1057,23 @@ class ReprTracebackNative(ReprTraceback):
self.extraline = None
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ReprEntryNative(TerminalRepr):
lines = attr.ib(type=Sequence[str])
style: "_TracebackStyle" = "native"
lines: Sequence[str]
style: ClassVar["_TracebackStyle"] = "native"
def toterminal(self, tw: TerminalWriter) -> None:
tw.write("".join(self.lines))
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ReprEntry(TerminalRepr):
lines = attr.ib(type=Sequence[str])
reprfuncargs = attr.ib(type=Optional["ReprFuncArgs"])
reprlocals = attr.ib(type=Optional["ReprLocals"])
reprfileloc = attr.ib(type=Optional["ReprFileLocation"])
style = attr.ib(type="_TracebackStyle")
lines: Sequence[str]
reprfuncargs: Optional["ReprFuncArgs"]
reprlocals: Optional["ReprLocals"]
reprfileloc: Optional["ReprFileLocation"]
style: "_TracebackStyle"
def _write_entry_lines(self, tw: TerminalWriter) -> None:
"""Write the source code portions of a list of traceback entries with syntax highlighting.
@ -1144,11 +1147,11 @@ class ReprEntry(TerminalRepr):
)
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ReprFileLocation(TerminalRepr):
path = attr.ib(type=str, converter=str)
lineno = attr.ib(type=int)
message = attr.ib(type=str)
path: str = attr.ib(converter=str)
lineno: int
message: str
def toterminal(self, tw: TerminalWriter) -> None:
# Filename and lineno output for each entry, using an output format
@ -1161,18 +1164,18 @@ class ReprFileLocation(TerminalRepr):
tw.line(f":{self.lineno}: {msg}")
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ReprLocals(TerminalRepr):
lines = attr.ib(type=Sequence[str])
lines: Sequence[str]
def toterminal(self, tw: TerminalWriter, indent="") -> None:
for line in self.lines:
tw.line(indent + line)
@attr.s(eq=False)
@attr.s(eq=False, auto_attribs=True)
class ReprFuncArgs(TerminalRepr):
args = attr.ib(type=Sequence[Tuple[str, object]])
args: Sequence[Tuple[str, object]]
def toterminal(self, tw: TerminalWriter) -> None:
if self.args:

View File

@ -55,10 +55,10 @@ Signature: 8a477f597d28d172789f06886806bc55
@final
@attr.s(init=False)
@attr.s(init=False, auto_attribs=True)
class Cache:
_cachedir = attr.ib(type=Path, repr=False)
_config = attr.ib(type=Config, repr=False)
_cachedir: Path = attr.ib(repr=False)
_config: Config = attr.ib(repr=False)
# Sub-directory under cache-dir for directories created by `mkdir()`.
_CACHE_PREFIX_DIRS = "d"

View File

@ -858,7 +858,7 @@ class Config:
"""
@final
@attr.s(frozen=True)
@attr.s(frozen=True, auto_attribs=True)
class InvocationParams:
"""Holds parameters passed during :func:`pytest.main`.
@ -874,21 +874,12 @@ class Config:
Plugins accessing ``InvocationParams`` must be aware of that.
"""
args = attr.ib(type=Tuple[str, ...], converter=_args_converter)
"""The command-line arguments as passed to :func:`pytest.main`.
:type: Tuple[str, ...]
"""
plugins = attr.ib(type=Optional[Sequence[Union[str, _PluggyPlugin]]])
"""Extra plugins, might be `None`.
:type: Optional[Sequence[Union[str, plugin]]]
"""
dir = attr.ib(type=Path)
"""The directory from which :func:`pytest.main` was invoked.
:type: pathlib.Path
"""
args: Tuple[str, ...] = attr.ib(converter=_args_converter)
"""The command-line arguments as passed to :func:`pytest.main`."""
plugins: Optional[Sequence[Union[str, _PluggyPlugin]]]
"""Extra plugins, might be `None`."""
dir: Path
"""The directory from which :func:`pytest.main` was invoked."""
def __init__(
self,

View File

@ -393,16 +393,16 @@ def get_direct_param_fixture_func(request):
return request.param
@attr.s(slots=True)
@attr.s(slots=True, auto_attribs=True)
class FuncFixtureInfo:
# Original function argument names.
argnames = attr.ib(type=Tuple[str, ...])
argnames: Tuple[str, ...]
# Argnames that function immediately requires. These include argnames +
# fixture names specified via usefixtures and via autouse=True in fixture
# definitions.
initialnames = attr.ib(type=Tuple[str, ...])
names_closure = attr.ib(type=List[str])
name2fixturedefs = attr.ib(type=Dict[str, Sequence["FixtureDef[Any]"]])
initialnames: Tuple[str, ...]
names_closure: List[str]
name2fixturedefs: Dict[str, Sequence["FixtureDef[Any]"]]
def prune_dependency_tree(self) -> None:
"""Recompute names_closure from initialnames and name2fixturedefs.
@ -1187,11 +1187,11 @@ def wrap_function_to_error_out_if_called_directly(
@final
@attr.s(frozen=True)
@attr.s(frozen=True, auto_attribs=True)
class FixtureFunctionMarker:
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = attr.ib()
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]"
params: Optional[Tuple[object, ...]] = attr.ib(converter=_params_converter)
autouse: bool = attr.ib(default=False)
autouse: bool = False
ids: Union[
Tuple[Union[None, str, float, int, bool], ...],
Callable[[Any], Optional[object]],
@ -1199,7 +1199,7 @@ class FixtureFunctionMarker:
default=None,
converter=_ensure_immutable_ids,
)
name: Optional[str] = attr.ib(default=None)
name: Optional[str] = None
def __call__(self, function: FixtureFunction) -> FixtureFunction:
if inspect.isclass(function):

View File

@ -442,9 +442,9 @@ class Failed(Exception):
"""Signals a stop as failed test run."""
@attr.s
@attr.s(slots=True, auto_attribs=True)
class _bestrelpath_cache(Dict[Path, str]):
path = attr.ib(type=Path)
path: Path
def __missing__(self, path: Path) -> str:
r = bestrelpath(self.path, path)

View File

@ -133,7 +133,7 @@ def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]:
return None
@attr.s(slots=True)
@attr.s(slots=True, auto_attribs=True)
class KeywordMatcher:
"""A matcher for keywords.
@ -148,7 +148,7 @@ class KeywordMatcher:
any item, as well as names directly assigned to test functions.
"""
_names = attr.ib(type=AbstractSet[str])
_names: AbstractSet[str]
@classmethod
def from_item(cls, item: "Item") -> "KeywordMatcher":
@ -217,17 +217,17 @@ def deselect_by_keyword(items: "List[Item]", config: Config) -> None:
items[:] = remaining
@attr.s(slots=True)
@attr.s(slots=True, auto_attribs=True)
class MarkMatcher:
"""A matcher for markers which are present.
Tries to match on any marker names, attached to the given colitem.
"""
own_mark_names = attr.ib()
own_mark_names: AbstractSet[str]
@classmethod
def from_item(cls, item) -> "MarkMatcher":
def from_item(cls, item: "Item") -> "MarkMatcher":
mark_names = {mark.name for mark in item.iter_markers()}
return cls(mark_names)

View File

@ -47,11 +47,11 @@ class TokenType(enum.Enum):
EOF = "end of input"
@attr.s(frozen=True, slots=True)
@attr.s(frozen=True, slots=True, auto_attribs=True)
class Token:
type = attr.ib(type=TokenType)
value = attr.ib(type=str)
pos = attr.ib(type=int)
type: TokenType
value: str
pos: int
class ParseError(Exception):

View File

@ -33,7 +33,6 @@ from typing import TYPE_CHECKING
from typing import Union
from weakref import WeakKeyDictionary
import attr
from iniconfig import IniConfig
from iniconfig import SectionWrapper
@ -1518,7 +1517,6 @@ class LineComp:
@final
@attr.s(repr=False, str=False, init=False)
class Testdir:
"""
Similar to :class:`Pytester`, but this class works with legacy legacy_path objects instead.

View File

@ -157,11 +157,11 @@ def evaluate_condition(item: Item, mark: Mark, condition: object) -> Tuple[bool,
return result, reason
@attr.s(slots=True, frozen=True)
@attr.s(slots=True, frozen=True, auto_attribs=True)
class Skip:
"""The result of evaluate_skip_marks()."""
reason = attr.ib(type=str, default="unconditional skip")
reason: str = "unconditional skip"
def evaluate_skip_marks(item: Item) -> Optional[Skip]:
@ -192,14 +192,14 @@ def evaluate_skip_marks(item: Item) -> Optional[Skip]:
return None
@attr.s(slots=True, frozen=True)
@attr.s(slots=True, frozen=True, auto_attribs=True)
class Xfail:
"""The result of evaluate_xfail_marks()."""
reason = attr.ib(type=str)
run = attr.ib(type=bool)
strict = attr.ib(type=bool)
raises = attr.ib(type=Optional[Tuple[Type[BaseException], ...]])
reason: str
run: bool
strict: bool
raises: Optional[Tuple[Type[BaseException], ...]]
def evaluate_xfail_marks(item: Item) -> Optional[Xfail]:

View File

@ -14,6 +14,7 @@ from pathlib import Path
from typing import Any
from typing import Callable
from typing import cast
from typing import ClassVar
from typing import Dict
from typing import Generator
from typing import List
@ -279,7 +280,7 @@ def pytest_report_teststatus(report: BaseReport) -> Tuple[str, str, str]:
return outcome, letter, outcome.upper()
@attr.s
@attr.s(auto_attribs=True)
class WarningReport:
"""Simple structure to hold warnings information captured by ``pytest_warning_recorded``.
@ -291,10 +292,11 @@ class WarningReport:
File system location of the source of the warning (see ``get_location``).
"""
message = attr.ib(type=str)
nodeid = attr.ib(type=Optional[str], default=None)
fslocation = attr.ib(type=Optional[Tuple[str, int]], default=None)
count_towards_summary = True
message: str
nodeid: Optional[str] = None
fslocation: Optional[Tuple[str, int]] = None
count_towards_summary: ClassVar = True
def get_location(self, config: Config) -> Optional[str]:
"""Return the more user-friendly information about the location of a warning, or None."""

View File

@ -158,12 +158,12 @@ class TempPathFactory:
@final
@attr.s(init=False)
@attr.s(init=False, auto_attribs=True)
class TempdirFactory:
"""Backward compatibility wrapper that implements :class:``_pytest.compat.LEGACY_PATH``
for :class:``TempPathFactory``."""
_tmppath_factory = attr.ib(type=TempPathFactory)
_tmppath_factory: TempPathFactory
def __init__(
self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False

View File

@ -116,7 +116,7 @@ _W = TypeVar("_W", bound=PytestWarning)
@final
@attr.s
@attr.s(auto_attribs=True)
class UnformattedWarning(Generic[_W]):
"""A warning meant to be formatted during runtime.
@ -124,8 +124,8 @@ class UnformattedWarning(Generic[_W]):
as opposed to a direct message.
"""
category = attr.ib(type=Type["_W"])
template = attr.ib(type=str)
category: Type["_W"]
template: str
def format(self, **kwargs: Any) -> _W:
"""Return an instance of the warning category, formatted with given kwargs."""

View File

@ -455,7 +455,7 @@ class TestFormattedExcinfo:
pass
"""
).strip()
pr.flow_marker = "|"
pr.flow_marker = "|" # type: ignore[misc]
lines = pr.get_source(source, 0)
assert len(lines) == 2
assert lines[0] == "| def f(x):"