diff options
author | arcadia-devtools <arcadia-devtools@yandex-team.ru> | 2022-02-14 00:49:36 +0300 |
---|---|---|
committer | arcadia-devtools <arcadia-devtools@yandex-team.ru> | 2022-02-14 00:49:36 +0300 |
commit | 82cfd1b7cab2d843cdf5467d9737f72597a493bd (patch) | |
tree | 1dfdcfe81a1a6b193ceacc2a828c521b657a339b /contrib/python/pytest/py3/_pytest/_code | |
parent | 3df7211d3e3691f8e33b0a1fb1764fe810d59302 (diff) | |
download | ydb-82cfd1b7cab2d843cdf5467d9737f72597a493bd.tar.gz |
intermediate changes
ref:68b1302de4b5da30b6bdf02193f7a2604d8b5cf8
Diffstat (limited to 'contrib/python/pytest/py3/_pytest/_code')
-rw-r--r-- | contrib/python/pytest/py3/_pytest/_code/code.py | 241 | ||||
-rw-r--r-- | contrib/python/pytest/py3/_pytest/_code/source.py | 5 |
2 files changed, 133 insertions, 113 deletions
diff --git a/contrib/python/pytest/py3/_pytest/_code/code.py b/contrib/python/pytest/py3/_pytest/_code/code.py index 423069330a..5b758a8848 100644 --- a/contrib/python/pytest/py3/_pytest/_code/code.py +++ b/contrib/python/pytest/py3/_pytest/_code/code.py @@ -1,4 +1,6 @@ +import ast import inspect +import os import re import sys import traceback @@ -12,6 +14,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 @@ -31,7 +34,6 @@ from weakref import ref import attr import pluggy -import py import _pytest from _pytest._code.source import findsource @@ -43,9 +45,13 @@ from _pytest._io.saferepr import safeformat from _pytest._io.saferepr import saferepr from _pytest.compat import final from _pytest.compat import get_real_func +from _pytest.deprecated import check_ispytest +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath if TYPE_CHECKING: from typing_extensions import Literal + from typing_extensions import SupportsIndex from weakref import ReferenceType _TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"] @@ -78,16 +84,16 @@ class Code: return self.raw.co_name @property - def path(self) -> Union[py.path.local, str]: + def path(self) -> Union[Path, str]: """Return a path object pointing to source code, or an ``str`` in case of ``OSError`` / non-existing file.""" if not self.raw.co_filename: return "" try: - p = py.path.local(self.raw.co_filename) + p = absolutepath(self.raw.co_filename) # maybe don't try this checking - if not p.check(): - raise OSError("py.path check failed.") + if not p.exists(): + raise OSError("path check failed.") return p except OSError: # XXX maybe try harder like the weird logic @@ -223,7 +229,7 @@ class TracebackEntry: return source.getstatement(self.lineno) @property - def path(self) -> Union[py.path.local, str]: + def path(self) -> Union[Path, str]: """Path to the source code.""" return self.frame.code.path @@ -235,7 +241,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 @@ -255,7 +263,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] @@ -270,9 +278,9 @@ class TracebackEntry: Mostly for internal use. """ - tbh: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]] = ( - False - ) + tbh: Union[ + bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool] + ] = False for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals): # in normal cases, f_locals and f_globals are dictionaries # however via `exec(...)` / `eval(...)` they can be other types @@ -336,10 +344,10 @@ class Traceback(List[TracebackEntry]): def cut( self, - path=None, + path: Optional[Union["os.PathLike[str]", str]] = None, lineno: Optional[int] = None, firstlineno: Optional[int] = None, - excludepath: Optional[py.path.local] = None, + excludepath: Optional["os.PathLike[str]"] = None, ) -> "Traceback": """Return a Traceback instance wrapping part of this Traceback. @@ -350,31 +358,37 @@ class Traceback(List[TracebackEntry]): for formatting reasons (removing some uninteresting bits that deal with handling of the exception/traceback). """ + path_ = None if path is None else os.fspath(path) + excludepath_ = None if excludepath is None else os.fspath(excludepath) for x in self: code = x.frame.code codepath = code.path + if path is not None and str(codepath) != path_: + continue if ( - (path is None or codepath == path) - and ( - excludepath is None - or not isinstance(codepath, py.path.local) - or not codepath.relto(excludepath) - ) - and (lineno is None or x.lineno == lineno) - and (firstlineno is None or x.frame.code.firstlineno == firstlineno) + excludepath is not None + and isinstance(codepath, Path) + and excludepath_ in (str(p) for p in codepath.parents) # type: ignore[operator] ): - return Traceback(x._rawentry, self._excinfo) + continue + if lineno is not None and x.lineno != lineno: + continue + if firstlineno is not None and x.frame.code.firstlineno != firstlineno: + continue + return Traceback(x._rawentry, self._excinfo) return self @overload - def __getitem__(self, key: int) -> TracebackEntry: + def __getitem__(self, key: "SupportsIndex") -> TracebackEntry: ... @overload def __getitem__(self, key: slice) -> "Traceback": ... - def __getitem__(self, key: Union[int, slice]) -> Union[TracebackEntry, "Traceback"]: + def __getitem__( + self, key: Union["SupportsIndex", slice] + ) -> Union[TracebackEntry, "Traceback"]: if isinstance(key, slice): return self.__class__(super().__getitem__(key)) else: @@ -418,41 +432,45 @@ class Traceback(List[TracebackEntry]): f = entry.frame loc = f.f_locals for otherloc in values: - if f.eval( - co_equal, - __recursioncache_locals_1=loc, - __recursioncache_locals_2=otherloc, - ): + if otherloc == loc: return i values.append(entry.frame.f_locals) return None -co_equal = compile( - "__recursioncache_locals_1 == __recursioncache_locals_2", "?", "eval" -) - - -_E = TypeVar("_E", bound=BaseException, covariant=True) +E = TypeVar("E", bound=BaseException, covariant=True) @final -@attr.s(repr=False) -class ExceptionInfo(Generic[_E]): +@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: Optional[Tuple[Type["E"], "E", TracebackType]] + _striptext: str + _traceback: Optional[Traceback] - _excinfo = attr.ib(type=Optional[Tuple[Type["_E"], "_E", TracebackType]]) - _striptext = attr.ib(type=str, default="") - _traceback = attr.ib(type=Optional[Traceback], default=None) + def __init__( + self, + excinfo: Optional[Tuple[Type["E"], "E", TracebackType]], + striptext: str = "", + traceback: Optional[Traceback] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._excinfo = excinfo + self._striptext = striptext + self._traceback = traceback @classmethod def from_exc_info( cls, - exc_info: Tuple[Type[_E], _E, TracebackType], + exc_info: Tuple[Type[E], E, TracebackType], exprinfo: Optional[str] = None, - ) -> "ExceptionInfo[_E]": + ) -> "ExceptionInfo[E]": """Return an ExceptionInfo for an existing exc_info tuple. .. warning:: @@ -472,7 +490,7 @@ class ExceptionInfo(Generic[_E]): if exprinfo and exprinfo.startswith(cls._assert_start_repr): _striptext = "AssertionError: " - return cls(exc_info, _striptext) + return cls(exc_info, _striptext, _ispytest=True) @classmethod def from_current( @@ -497,17 +515,17 @@ class ExceptionInfo(Generic[_E]): return ExceptionInfo.from_exc_info(exc_info, exprinfo) @classmethod - def for_later(cls) -> "ExceptionInfo[_E]": + def for_later(cls) -> "ExceptionInfo[E]": """Return an unfilled ExceptionInfo.""" - return cls(None) + return cls(None, _ispytest=True) - def fill_unfilled(self, exc_info: Tuple[Type[_E], _E, TracebackType]) -> None: + def fill_unfilled(self, exc_info: Tuple[Type[E], E, TracebackType]) -> None: """Fill an unfilled ExceptionInfo created with ``for_later()``.""" assert self._excinfo is None, "ExceptionInfo was already filled" self._excinfo = exc_info @property - def type(self) -> Type[_E]: + def type(self) -> Type[E]: """The exception class.""" assert ( self._excinfo is not None @@ -515,7 +533,7 @@ class ExceptionInfo(Generic[_E]): return self._excinfo[0] @property - def value(self) -> _E: + def value(self) -> E: """The exception value.""" assert ( self._excinfo is not None @@ -559,10 +577,10 @@ class ExceptionInfo(Generic[_E]): def exconly(self, tryshort: bool = False) -> str: """Return the exception as a string. - When 'tryshort' resolves to True, and the exception is a - _pytest._code._AssertionError, only the actual exception part of - the exception representation is returned (so 'AssertionError: ' is - removed from the beginning). + When 'tryshort' resolves to True, and the exception is an + AssertionError, only the actual exception part of the exception + representation is returned (so 'AssertionError: ' is removed from + the beginning). """ lines = format_exception_only(self.type, self.value) text = "".join(lines) @@ -662,22 +680,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" - - 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) + flow_marker: ClassVar = ">" + fail_marker: ClassVar = "E" + + 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. @@ -801,7 +821,8 @@ class FormattedExcinfo: message = "in %s" % (entry.name) else: message = excinfo and excinfo.typename or "" - path = self._makepath(entry.path) + entry_path = entry.path + path = self._makepath(entry_path) reprfileloc = ReprFileLocation(path, entry.lineno + 1, message) localsrepr = self.repr_locals(entry.locals) return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style) @@ -814,15 +835,15 @@ class FormattedExcinfo: lines.extend(self.get_exconly(excinfo, indent=4)) return ReprEntry(lines, None, None, None, style) - def _makepath(self, path): - if not self.abspath: + def _makepath(self, path: Union[Path, str]) -> str: + if not self.abspath and isinstance(path, Path): try: - np = py.path.local().bestrelpath(path) + np = bestrelpath(Path.cwd(), path) except OSError: - return path + return str(path) if len(np) < len(str(path)): - path = np - return path + return np + return str(path) def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback": traceback = excinfo.traceback @@ -877,7 +898,7 @@ class FormattedExcinfo: max_frames=max_frames, total=len(traceback), ) - # Type ignored because adding two instaces of a List subtype + # Type ignored because adding two instances of a List subtype # currently incorrectly has type List instead of the subtype. traceback = traceback[:max_frames] + traceback[-max_frames:] # type: ignore else: @@ -918,7 +939,7 @@ class FormattedExcinfo: if e.__cause__ is not None and self.chain: e = e.__cause__ excinfo_ = ( - ExceptionInfo((type(e), e, e.__traceback__)) + ExceptionInfo.from_exc_info((type(e), e, e.__traceback__)) if e.__traceback__ else None ) @@ -928,7 +949,7 @@ class FormattedExcinfo: ): e = e.__context__ excinfo_ = ( - ExceptionInfo((type(e), e, e.__traceback__)) + ExceptionInfo.from_exc_info((type(e), e, e.__traceback__)) if e.__traceback__ else None ) @@ -939,7 +960,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 @@ -950,7 +971,7 @@ class TerminalRepr: return io.getvalue().strip() def __repr__(self) -> str: - return "<{} instance at {:0x}>".format(self.__class__, id(self)) + return f"<{self.__class__} instance at {id(self):0x}>" def toterminal(self, tw: TerminalWriter) -> None: raise NotImplementedError() @@ -975,13 +996,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__() @@ -999,23 +1016,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. @@ -1043,22 +1060,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. @@ -1132,11 +1150,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 @@ -1149,18 +1167,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: @@ -1181,7 +1199,7 @@ class ReprFuncArgs(TerminalRepr): tw.line("") -def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]: +def getfslineno(obj: object) -> Tuple[Union[str, Path], int]: """Return source location (path, lineno) for the given object. If the source cannot be determined return ("", -1). @@ -1203,7 +1221,7 @@ def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]: except TypeError: return "", -1 - fspath = fn and py.path.local(fn) or "" + fspath = fn and absolutepath(fn) or "" lineno = -1 if fspath: try: @@ -1225,7 +1243,6 @@ _PLUGGY_DIR = Path(pluggy.__file__.rstrip("oc")) if _PLUGGY_DIR.name == "__init__.py": _PLUGGY_DIR = _PLUGGY_DIR.parent _PYTEST_DIR = Path(_pytest.__file__).parent -_PY_DIR = Path(py.__file__).parent def filter_traceback(entry: TracebackEntry) -> bool: @@ -1253,7 +1270,5 @@ def filter_traceback(entry: TracebackEntry) -> bool: return False if _PYTEST_DIR in parents: return False - if _PY_DIR in parents: - return False return True diff --git a/contrib/python/pytest/py3/_pytest/_code/source.py b/contrib/python/pytest/py3/_pytest/_code/source.py index 6f54057c0a..208cfb8003 100644 --- a/contrib/python/pytest/py3/_pytest/_code/source.py +++ b/contrib/python/pytest/py3/_pytest/_code/source.py @@ -149,6 +149,11 @@ def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[i values: List[int] = [] for x in ast.walk(node): if isinstance(x, (ast.stmt, ast.ExceptHandler)): + # Before Python 3.8, the lineno of a decorated class or function pointed at the decorator. + # Since Python 3.8, the lineno points to the class/def, so need to include the decorators. + if isinstance(x, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)): + for d in x.decorator_list: + values.append(d.lineno - 1) values.append(x.lineno - 1) for name in ("finalbody", "orelse"): val: Optional[List[ast.stmt]] = getattr(x, name, None) |