aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pytest/py3/_pytest/_code
diff options
context:
space:
mode:
authorarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-02-14 00:49:36 +0300
committerarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-02-14 00:49:36 +0300
commit82cfd1b7cab2d843cdf5467d9737f72597a493bd (patch)
tree1dfdcfe81a1a6b193ceacc2a828c521b657a339b /contrib/python/pytest/py3/_pytest/_code
parent3df7211d3e3691f8e33b0a1fb1764fe810d59302 (diff)
downloadydb-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.py241
-rw-r--r--contrib/python/pytest/py3/_pytest/_code/source.py5
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)