aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pytest/py3/_pytest/nodes.py
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-02-10 16:44:39 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:39 +0300
commite9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch)
tree64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/pytest/py3/_pytest/nodes.py
parent2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff)
downloadydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/pytest/py3/_pytest/nodes.py')
-rw-r--r--contrib/python/pytest/py3/_pytest/nodes.py752
1 files changed, 376 insertions, 376 deletions
diff --git a/contrib/python/pytest/py3/_pytest/nodes.py b/contrib/python/pytest/py3/_pytest/nodes.py
index 4ac60823d5..27434fb6a6 100644
--- a/contrib/python/pytest/py3/_pytest/nodes.py
+++ b/contrib/python/pytest/py3/_pytest/nodes.py
@@ -1,369 +1,369 @@
import os
import warnings
-from pathlib import Path
-from typing import Callable
-from typing import Iterable
-from typing import Iterator
-from typing import List
-from typing import Optional
-from typing import overload
-from typing import Set
-from typing import Tuple
-from typing import Type
-from typing import TYPE_CHECKING
-from typing import TypeVar
-from typing import Union
+from pathlib import Path
+from typing import Callable
+from typing import Iterable
+from typing import Iterator
+from typing import List
+from typing import Optional
+from typing import overload
+from typing import Set
+from typing import Tuple
+from typing import Type
+from typing import TYPE_CHECKING
+from typing import TypeVar
+from typing import Union
import py
import _pytest._code
-from _pytest._code import getfslineno
-from _pytest._code.code import ExceptionInfo
-from _pytest._code.code import TerminalRepr
-from _pytest.compat import cached_property
-from _pytest.config import Config
-from _pytest.config import ConftestImportFailure
-from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
-from _pytest.mark.structures import Mark
-from _pytest.mark.structures import MarkDecorator
+from _pytest._code import getfslineno
+from _pytest._code.code import ExceptionInfo
+from _pytest._code.code import TerminalRepr
+from _pytest.compat import cached_property
+from _pytest.config import Config
+from _pytest.config import ConftestImportFailure
+from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
+from _pytest.mark.structures import Mark
+from _pytest.mark.structures import MarkDecorator
from _pytest.mark.structures import NodeKeywords
from _pytest.outcomes import fail
-from _pytest.pathlib import absolutepath
-from _pytest.store import Store
-
-if TYPE_CHECKING:
- # Imported here due to circular import.
- from _pytest.main import Session
- from _pytest._code.code import _TracebackStyle
-
-
+from _pytest.pathlib import absolutepath
+from _pytest.store import Store
+
+if TYPE_CHECKING:
+ # Imported here due to circular import.
+ from _pytest.main import Session
+ from _pytest._code.code import _TracebackStyle
+
+
SEP = "/"
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
-def iterparentnodeids(nodeid: str) -> Iterator[str]:
- """Return the parent node IDs of a given node ID, inclusive.
+def iterparentnodeids(nodeid: str) -> Iterator[str]:
+ """Return the parent node IDs of a given node ID, inclusive.
+
+ For the node ID
+
+ "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source"
+
+ the result would be
+
+ ""
+ "testing"
+ "testing/code"
+ "testing/code/test_excinfo.py"
+ "testing/code/test_excinfo.py::TestFormattedExcinfo"
+ "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source"
+
+ Note that :: parts are only considered at the last / component.
+ """
+ pos = 0
+ sep = SEP
+ yield ""
+ while True:
+ at = nodeid.find(sep, pos)
+ if at == -1 and sep == SEP:
+ sep = "::"
+ elif at == -1:
+ if nodeid:
+ yield nodeid
+ break
+ else:
+ if at:
+ yield nodeid[:at]
+ pos = at + len(sep)
+
+
+_NodeType = TypeVar("_NodeType", bound="Node")
+
- For the node ID
+class NodeMeta(type):
+ def __call__(self, *k, **kw):
+ msg = (
+ "Direct construction of {name} has been deprecated, please use {name}.from_parent.\n"
+ "See "
+ "https://docs.pytest.org/en/stable/deprecations.html#node-construction-changed-to-node-from-parent"
+ " for more details."
+ ).format(name=self.__name__)
+ fail(msg, pytrace=False)
- "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source"
+ def _create(self, *k, **kw):
+ return super().__call__(*k, **kw)
- the result would be
- ""
- "testing"
- "testing/code"
- "testing/code/test_excinfo.py"
- "testing/code/test_excinfo.py::TestFormattedExcinfo"
- "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source"
+class Node(metaclass=NodeMeta):
+ """Base class for Collector and Item, the components of the test
+ collection tree.
- Note that :: parts are only considered at the last / component.
+ Collector subclasses have children; Items are leaf nodes.
"""
- pos = 0
- sep = SEP
- yield ""
- while True:
- at = nodeid.find(sep, pos)
- if at == -1 and sep == SEP:
- sep = "::"
- elif at == -1:
- if nodeid:
- yield nodeid
- break
- else:
- if at:
- yield nodeid[:at]
- pos = at + len(sep)
-
-
-_NodeType = TypeVar("_NodeType", bound="Node")
-
-
-class NodeMeta(type):
- def __call__(self, *k, **kw):
- msg = (
- "Direct construction of {name} has been deprecated, please use {name}.from_parent.\n"
- "See "
- "https://docs.pytest.org/en/stable/deprecations.html#node-construction-changed-to-node-from-parent"
- " for more details."
- ).format(name=self.__name__)
- fail(msg, pytrace=False)
-
- def _create(self, *k, **kw):
- return super().__call__(*k, **kw)
-
-
-class Node(metaclass=NodeMeta):
- """Base class for Collector and Item, the components of the test
- collection tree.
-
- Collector subclasses have children; Items are leaf nodes.
- """
-
- # Use __slots__ to make attribute access faster.
- # Note that __dict__ is still available.
- __slots__ = (
- "name",
- "parent",
- "config",
- "session",
- "fspath",
- "_nodeid",
- "_store",
- "__dict__",
- )
-
+
+ # Use __slots__ to make attribute access faster.
+ # Note that __dict__ is still available.
+ __slots__ = (
+ "name",
+ "parent",
+ "config",
+ "session",
+ "fspath",
+ "_nodeid",
+ "_store",
+ "__dict__",
+ )
+
def __init__(
- self,
- name: str,
- parent: "Optional[Node]" = None,
- config: Optional[Config] = None,
- session: "Optional[Session]" = None,
- fspath: Optional[py.path.local] = None,
- nodeid: Optional[str] = None,
- ) -> None:
- #: A unique name within the scope of the parent node.
+ self,
+ name: str,
+ parent: "Optional[Node]" = None,
+ config: Optional[Config] = None,
+ session: "Optional[Session]" = None,
+ fspath: Optional[py.path.local] = None,
+ nodeid: Optional[str] = None,
+ ) -> None:
+ #: A unique name within the scope of the parent node.
self.name = name
- #: The parent collector node.
+ #: The parent collector node.
self.parent = parent
- #: The pytest config object.
- if config:
- self.config: Config = config
- else:
- if not parent:
- raise TypeError("config or parent must be provided")
- self.config = parent.config
-
- #: The pytest session this node is part of.
- if session:
- self.session = session
- else:
- if not parent:
- raise TypeError("session or parent must be provided")
- self.session = parent.session
-
- #: Filesystem path where this node was collected from (can be None).
+ #: The pytest config object.
+ if config:
+ self.config: Config = config
+ else:
+ if not parent:
+ raise TypeError("config or parent must be provided")
+ self.config = parent.config
+
+ #: The pytest session this node is part of.
+ if session:
+ self.session = session
+ else:
+ if not parent:
+ raise TypeError("session or parent must be provided")
+ self.session = parent.session
+
+ #: Filesystem path where this node was collected from (can be None).
self.fspath = fspath or getattr(parent, "fspath", None)
- #: Keywords/markers collected from all scopes.
+ #: Keywords/markers collected from all scopes.
self.keywords = NodeKeywords(self)
- #: The marker objects belonging to this node.
- self.own_markers: List[Mark] = []
+ #: The marker objects belonging to this node.
+ self.own_markers: List[Mark] = []
- #: Allow adding of extra keywords to use for matching.
- self.extra_keyword_matches: Set[str] = set()
+ #: Allow adding of extra keywords to use for matching.
+ self.extra_keyword_matches: Set[str] = set()
if nodeid is not None:
assert "::()" not in nodeid
self._nodeid = nodeid
else:
- if not self.parent:
- raise TypeError("nodeid or parent must be provided")
+ if not self.parent:
+ raise TypeError("nodeid or parent must be provided")
self._nodeid = self.parent.nodeid
if self.name != "()":
self._nodeid += "::" + self.name
- # A place where plugins can store information on the node for their
- # own use. Currently only intended for internal plugins.
- self._store = Store()
-
- @classmethod
- def from_parent(cls, parent: "Node", **kw):
- """Public constructor for Nodes.
-
- This indirection got introduced in order to enable removing
- the fragile logic from the node constructors.
-
- Subclasses can use ``super().from_parent(...)`` when overriding the
- construction.
-
- :param parent: The parent node of this Node.
- """
- if "config" in kw:
- raise TypeError("config is not a valid argument for from_parent")
- if "session" in kw:
- raise TypeError("session is not a valid argument for from_parent")
- return cls._create(parent=parent, **kw)
-
+ # A place where plugins can store information on the node for their
+ # own use. Currently only intended for internal plugins.
+ self._store = Store()
+
+ @classmethod
+ def from_parent(cls, parent: "Node", **kw):
+ """Public constructor for Nodes.
+
+ This indirection got introduced in order to enable removing
+ the fragile logic from the node constructors.
+
+ Subclasses can use ``super().from_parent(...)`` when overriding the
+ construction.
+
+ :param parent: The parent node of this Node.
+ """
+ if "config" in kw:
+ raise TypeError("config is not a valid argument for from_parent")
+ if "session" in kw:
+ raise TypeError("session is not a valid argument for from_parent")
+ return cls._create(parent=parent, **kw)
+
@property
def ihook(self):
- """fspath-sensitive hook proxy used to call pytest hooks."""
+ """fspath-sensitive hook proxy used to call pytest hooks."""
return self.session.gethookproxy(self.fspath)
- def __repr__(self) -> str:
- return "<{} {}>".format(self.__class__.__name__, getattr(self, "name", None))
+ def __repr__(self) -> str:
+ return "<{} {}>".format(self.__class__.__name__, getattr(self, "name", None))
- def warn(self, warning: Warning) -> None:
- """Issue a warning for this Node.
+ def warn(self, warning: Warning) -> None:
+ """Issue a warning for this Node.
- Warnings will be displayed after the test session, unless explicitly suppressed.
+ Warnings will be displayed after the test session, unless explicitly suppressed.
- :param Warning warning:
- The warning instance to issue.
+ :param Warning warning:
+ The warning instance to issue.
- :raises ValueError: If ``warning`` instance is not a subclass of Warning.
+ :raises ValueError: If ``warning`` instance is not a subclass of Warning.
- Example usage:
+ Example usage:
.. code-block:: python
node.warn(PytestWarning("some message"))
- node.warn(UserWarning("some message"))
+ node.warn(UserWarning("some message"))
- .. versionchanged:: 6.2
- Any subclass of :class:`Warning` is now accepted, rather than only
- :class:`PytestWarning <pytest.PytestWarning>` subclasses.
+ .. versionchanged:: 6.2
+ Any subclass of :class:`Warning` is now accepted, rather than only
+ :class:`PytestWarning <pytest.PytestWarning>` subclasses.
"""
- # enforce type checks here to avoid getting a generic type error later otherwise.
- if not isinstance(warning, Warning):
+ # enforce type checks here to avoid getting a generic type error later otherwise.
+ if not isinstance(warning, Warning):
raise ValueError(
- "warning must be an instance of Warning or subclass, got {!r}".format(
+ "warning must be an instance of Warning or subclass, got {!r}".format(
warning
)
)
path, lineno = get_fslocation_from_item(self)
- assert lineno is not None
+ assert lineno is not None
warnings.warn_explicit(
- warning, category=None, filename=str(path), lineno=lineno + 1,
+ warning, category=None, filename=str(path), lineno=lineno + 1,
)
- # Methods for ordering nodes.
-
+ # Methods for ordering nodes.
+
@property
- def nodeid(self) -> str:
- """A ::-separated string denoting its collection tree address."""
+ def nodeid(self) -> str:
+ """A ::-separated string denoting its collection tree address."""
return self._nodeid
- def __hash__(self) -> int:
- return hash(self._nodeid)
+ def __hash__(self) -> int:
+ return hash(self._nodeid)
- def setup(self) -> None:
+ def setup(self) -> None:
pass
- def teardown(self) -> None:
+ def teardown(self) -> None:
pass
- def listchain(self) -> List["Node"]:
- """Return list of all parent collectors up to self, starting from
- the root of collection tree."""
+ def listchain(self) -> List["Node"]:
+ """Return list of all parent collectors up to self, starting from
+ the root of collection tree."""
chain = []
- item: Optional[Node] = self
+ item: Optional[Node] = self
while item is not None:
chain.append(item)
item = item.parent
chain.reverse()
return chain
- def add_marker(
- self, marker: Union[str, MarkDecorator], append: bool = True
- ) -> None:
- """Dynamically add a marker object to the node.
+ def add_marker(
+ self, marker: Union[str, MarkDecorator], append: bool = True
+ ) -> None:
+ """Dynamically add a marker object to the node.
- :param append:
- Whether to append the marker, or prepend it.
+ :param append:
+ Whether to append the marker, or prepend it.
"""
- from _pytest.mark import MARK_GEN
+ from _pytest.mark import MARK_GEN
- if isinstance(marker, MarkDecorator):
- marker_ = marker
- elif isinstance(marker, str):
- marker_ = getattr(MARK_GEN, marker)
- else:
+ if isinstance(marker, MarkDecorator):
+ marker_ = marker
+ elif isinstance(marker, str):
+ marker_ = getattr(MARK_GEN, marker)
+ else:
raise ValueError("is not a string or pytest.mark.* Marker")
- self.keywords[marker_.name] = marker_
+ self.keywords[marker_.name] = marker_
if append:
- self.own_markers.append(marker_.mark)
+ self.own_markers.append(marker_.mark)
else:
- self.own_markers.insert(0, marker_.mark)
+ self.own_markers.insert(0, marker_.mark)
- def iter_markers(self, name: Optional[str] = None) -> Iterator[Mark]:
- """Iterate over all markers of the node.
+ def iter_markers(self, name: Optional[str] = None) -> Iterator[Mark]:
+ """Iterate over all markers of the node.
- :param name: If given, filter the results by the name attribute.
+ :param name: If given, filter the results by the name attribute.
"""
return (x[1] for x in self.iter_markers_with_node(name=name))
- def iter_markers_with_node(
- self, name: Optional[str] = None
- ) -> Iterator[Tuple["Node", Mark]]:
- """Iterate over all markers of the node.
+ def iter_markers_with_node(
+ self, name: Optional[str] = None
+ ) -> Iterator[Tuple["Node", Mark]]:
+ """Iterate over all markers of the node.
- :param name: If given, filter the results by the name attribute.
- :returns: An iterator of (node, mark) tuples.
+ :param name: If given, filter the results by the name attribute.
+ :returns: An iterator of (node, mark) tuples.
"""
for node in reversed(self.listchain()):
for mark in node.own_markers:
if name is None or getattr(mark, "name", None) == name:
yield node, mark
- @overload
- def get_closest_marker(self, name: str) -> Optional[Mark]:
- ...
-
- @overload
- def get_closest_marker(self, name: str, default: Mark) -> Mark:
- ...
-
- def get_closest_marker(
- self, name: str, default: Optional[Mark] = None
- ) -> Optional[Mark]:
- """Return the first marker matching the name, from closest (for
- example function) to farther level (for example module level).
-
- :param default: Fallback return value if no marker was found.
- :param name: Name to filter by.
+ @overload
+ def get_closest_marker(self, name: str) -> Optional[Mark]:
+ ...
+
+ @overload
+ def get_closest_marker(self, name: str, default: Mark) -> Mark:
+ ...
+
+ def get_closest_marker(
+ self, name: str, default: Optional[Mark] = None
+ ) -> Optional[Mark]:
+ """Return the first marker matching the name, from closest (for
+ example function) to farther level (for example module level).
+
+ :param default: Fallback return value if no marker was found.
+ :param name: Name to filter by.
"""
return next(self.iter_markers(name=name), default)
- def listextrakeywords(self) -> Set[str]:
- """Return a set of all extra keywords in self and any parents."""
- extra_keywords: Set[str] = set()
+ def listextrakeywords(self) -> Set[str]:
+ """Return a set of all extra keywords in self and any parents."""
+ extra_keywords: Set[str] = set()
for item in self.listchain():
extra_keywords.update(item.extra_keyword_matches)
return extra_keywords
- def listnames(self) -> List[str]:
+ def listnames(self) -> List[str]:
return [x.name for x in self.listchain()]
- def addfinalizer(self, fin: Callable[[], object]) -> None:
- """Register a function to be called when this node is finalized.
+ def addfinalizer(self, fin: Callable[[], object]) -> None:
+ """Register a function to be called when this node is finalized.
This method can only be called when this node is active
in a setup chain, for example during self.setup().
"""
self.session._setupstate.addfinalizer(fin, self)
- def getparent(self, cls: Type[_NodeType]) -> Optional[_NodeType]:
- """Get the next parent node (including self) which is an instance of
- the given class."""
- current: Optional[Node] = self
+ def getparent(self, cls: Type[_NodeType]) -> Optional[_NodeType]:
+ """Get the next parent node (including self) which is an instance of
+ the given class."""
+ current: Optional[Node] = self
while current and not isinstance(current, cls):
current = current.parent
- assert current is None or isinstance(current, cls)
+ assert current is None or isinstance(current, cls)
return current
- def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
+ def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
pass
- def _repr_failure_py(
- self,
- excinfo: ExceptionInfo[BaseException],
- style: "Optional[_TracebackStyle]" = None,
- ) -> TerminalRepr:
- from _pytest.fixtures import FixtureLookupError
-
- if isinstance(excinfo.value, ConftestImportFailure):
- excinfo = ExceptionInfo(excinfo.value.excinfo)
- if isinstance(excinfo.value, fail.Exception):
+ def _repr_failure_py(
+ self,
+ excinfo: ExceptionInfo[BaseException],
+ style: "Optional[_TracebackStyle]" = None,
+ ) -> TerminalRepr:
+ from _pytest.fixtures import FixtureLookupError
+
+ if isinstance(excinfo.value, ConftestImportFailure):
+ excinfo = ExceptionInfo(excinfo.value.excinfo)
+ if isinstance(excinfo.value, fail.Exception):
if not excinfo.value.pytrace:
- style = "value"
- if isinstance(excinfo.value, FixtureLookupError):
+ style = "value"
+ if isinstance(excinfo.value, FixtureLookupError):
return excinfo.value.formatrepr()
- if self.config.getoption("fulltrace", False):
+ if self.config.getoption("fulltrace", False):
style = "long"
else:
tb = _pytest._code.Traceback([excinfo.traceback[-1]])
@@ -374,104 +374,104 @@ class Node(metaclass=NodeMeta):
style = "long"
# XXX should excinfo.getrepr record all data and toterminal() process it?
if style is None:
- if self.config.getoption("tbstyle", "auto") == "short":
+ if self.config.getoption("tbstyle", "auto") == "short":
style = "short"
else:
style = "long"
- if self.config.getoption("verbose", 0) > 1:
+ if self.config.getoption("verbose", 0) > 1:
truncate_locals = False
else:
truncate_locals = True
- # excinfo.getrepr() formats paths relative to the CWD if `abspath` is False.
- # It is possible for a fixture/test to change the CWD while this code runs, which
- # would then result in the user seeing confusing paths in the failure message.
- # To fix this, if the CWD changed, always display the full absolute path.
- # It will be better to just always display paths relative to invocation_dir, but
- # this requires a lot of plumbing (#6428).
+ # excinfo.getrepr() formats paths relative to the CWD if `abspath` is False.
+ # It is possible for a fixture/test to change the CWD while this code runs, which
+ # would then result in the user seeing confusing paths in the failure message.
+ # To fix this, if the CWD changed, always display the full absolute path.
+ # It will be better to just always display paths relative to invocation_dir, but
+ # this requires a lot of plumbing (#6428).
try:
- abspath = Path(os.getcwd()) != self.config.invocation_params.dir
+ abspath = Path(os.getcwd()) != self.config.invocation_params.dir
except OSError:
abspath = True
return excinfo.getrepr(
funcargs=True,
abspath=abspath,
- showlocals=self.config.getoption("showlocals", False),
+ showlocals=self.config.getoption("showlocals", False),
style=style,
- tbfilter=False, # pruned already, or in --fulltrace mode.
+ tbfilter=False, # pruned already, or in --fulltrace mode.
truncate_locals=truncate_locals,
)
- def repr_failure(
- self,
- excinfo: ExceptionInfo[BaseException],
- style: "Optional[_TracebackStyle]" = None,
- ) -> Union[str, TerminalRepr]:
- """Return a representation of a collection or test failure.
-
- :param excinfo: Exception information for the failure.
- """
- return self._repr_failure_py(excinfo, style)
-
-
-def get_fslocation_from_item(
- node: "Node",
-) -> Tuple[Union[str, py.path.local], Optional[int]]:
- """Try to extract the actual location from a node, depending on available attributes:
-
- * "location": a pair (path, lineno)
- * "obj": a Python object that the node wraps.
+ def repr_failure(
+ self,
+ excinfo: ExceptionInfo[BaseException],
+ style: "Optional[_TracebackStyle]" = None,
+ ) -> Union[str, TerminalRepr]:
+ """Return a representation of a collection or test failure.
+
+ :param excinfo: Exception information for the failure.
+ """
+ return self._repr_failure_py(excinfo, style)
+
+
+def get_fslocation_from_item(
+ node: "Node",
+) -> Tuple[Union[str, py.path.local], Optional[int]]:
+ """Try to extract the actual location from a node, depending on available attributes:
+
+ * "location": a pair (path, lineno)
+ * "obj": a Python object that the node wraps.
* "fspath": just a path
- :rtype: A tuple of (str|py.path.local, int) with filename and line number.
+ :rtype: A tuple of (str|py.path.local, int) with filename and line number.
"""
- # See Item.location.
- location: Optional[Tuple[str, Optional[int], str]] = getattr(node, "location", None)
- if location is not None:
- return location[:2]
- obj = getattr(node, "obj", None)
+ # See Item.location.
+ location: Optional[Tuple[str, Optional[int], str]] = getattr(node, "location", None)
+ if location is not None:
+ return location[:2]
+ obj = getattr(node, "obj", None)
if obj is not None:
return getfslineno(obj)
- return getattr(node, "fspath", "unknown location"), -1
+ return getattr(node, "fspath", "unknown location"), -1
class Collector(Node):
- """Collector instances create children through collect() and thus
- iteratively build a tree."""
+ """Collector instances create children through collect() and thus
+ iteratively build a tree."""
class CollectError(Exception):
- """An error during collection, contains a custom message."""
+ """An error during collection, contains a custom message."""
- def collect(self) -> Iterable[Union["Item", "Collector"]]:
- """Return a list of children (items and collectors) for this
- collection node."""
+ def collect(self) -> Iterable[Union["Item", "Collector"]]:
+ """Return a list of children (items and collectors) for this
+ collection node."""
raise NotImplementedError("abstract")
- # TODO: This omits the style= parameter which breaks Liskov Substitution.
- def repr_failure( # type: ignore[override]
- self, excinfo: ExceptionInfo[BaseException]
- ) -> Union[str, TerminalRepr]:
- """Return a representation of a collection failure.
-
- :param excinfo: Exception information for the failure.
- """
- if isinstance(excinfo.value, self.CollectError) and not self.config.getoption(
- "fulltrace", False
- ):
+ # TODO: This omits the style= parameter which breaks Liskov Substitution.
+ def repr_failure( # type: ignore[override]
+ self, excinfo: ExceptionInfo[BaseException]
+ ) -> Union[str, TerminalRepr]:
+ """Return a representation of a collection failure.
+
+ :param excinfo: Exception information for the failure.
+ """
+ if isinstance(excinfo.value, self.CollectError) and not self.config.getoption(
+ "fulltrace", False
+ ):
exc = excinfo.value
return str(exc.args[0])
- # Respect explicit tbstyle option, but default to "short"
- # (_repr_failure_py uses "long" with "fulltrace" option always).
- tbstyle = self.config.getoption("tbstyle", "auto")
- if tbstyle == "auto":
- tbstyle = "short"
-
- return self._repr_failure_py(excinfo, style=tbstyle)
-
- def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
+ # Respect explicit tbstyle option, but default to "short"
+ # (_repr_failure_py uses "long" with "fulltrace" option always).
+ tbstyle = self.config.getoption("tbstyle", "auto")
+ if tbstyle == "auto":
+ tbstyle = "short"
+
+ return self._repr_failure_py(excinfo, style=tbstyle)
+
+ def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None:
if hasattr(self, "fspath"):
traceback = excinfo.traceback
ntraceback = traceback.cut(path=self.fspath)
@@ -487,14 +487,14 @@ def _check_initialpaths_for_relpath(session, fspath):
class FSCollector(Collector):
- def __init__(
- self,
- fspath: py.path.local,
- parent=None,
- config: Optional[Config] = None,
- session: Optional["Session"] = None,
- nodeid: Optional[str] = None,
- ) -> None:
+ def __init__(
+ self,
+ fspath: py.path.local,
+ parent=None,
+ config: Optional[Config] = None,
+ session: Optional["Session"] = None,
+ nodeid: Optional[str] = None,
+ ) -> None:
name = fspath.basename
if parent is not None:
rel = fspath.relto(parent.fspath)
@@ -513,58 +513,58 @@ class FSCollector(Collector):
if nodeid and os.sep != SEP:
nodeid = nodeid.replace(os.sep, SEP)
- super().__init__(name, parent, config, session, nodeid=nodeid, fspath=fspath)
-
- @classmethod
- def from_parent(cls, parent, *, fspath, **kw):
- """The public constructor."""
- return super().from_parent(parent=parent, fspath=fspath, **kw)
-
- def gethookproxy(self, fspath: py.path.local):
- warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
- return self.session.gethookproxy(fspath)
-
- def isinitpath(self, path: py.path.local) -> bool:
- warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
- return self.session.isinitpath(path)
-
-
-class File(FSCollector):
- """Base class for collecting tests from a file.
-
- :ref:`non-python tests`.
- """
-
-
-class Item(Node):
- """A basic test invocation item.
-
- Note that for a single function there might be multiple test invocation items.
+ super().__init__(name, parent, config, session, nodeid=nodeid, fspath=fspath)
+
+ @classmethod
+ def from_parent(cls, parent, *, fspath, **kw):
+ """The public constructor."""
+ return super().from_parent(parent=parent, fspath=fspath, **kw)
+
+ def gethookproxy(self, fspath: py.path.local):
+ warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
+ return self.session.gethookproxy(fspath)
+
+ def isinitpath(self, path: py.path.local) -> bool:
+ warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)
+ return self.session.isinitpath(path)
+
+
+class File(FSCollector):
+ """Base class for collecting tests from a file.
+
+ :ref:`non-python tests`.
+ """
+
+
+class Item(Node):
+ """A basic test invocation item.
+
+ Note that for a single function there might be multiple test invocation items.
"""
nextitem = None
- def __init__(
- self,
- name,
- parent=None,
- config: Optional[Config] = None,
- session: Optional["Session"] = None,
- nodeid: Optional[str] = None,
- ) -> None:
- super().__init__(name, parent, config, session, nodeid=nodeid)
- self._report_sections: List[Tuple[str, str, str]] = []
-
- #: A list of tuples (name, value) that holds user defined properties
- #: for this test.
- self.user_properties: List[Tuple[str, object]] = []
-
- def runtest(self) -> None:
- raise NotImplementedError("runtest must be implemented by Item subclass")
-
- def add_report_section(self, when: str, key: str, content: str) -> None:
- """Add a new report section, similar to what's done internally to add
- stdout and stderr captured output::
+ def __init__(
+ self,
+ name,
+ parent=None,
+ config: Optional[Config] = None,
+ session: Optional["Session"] = None,
+ nodeid: Optional[str] = None,
+ ) -> None:
+ super().__init__(name, parent, config, session, nodeid=nodeid)
+ self._report_sections: List[Tuple[str, str, str]] = []
+
+ #: A list of tuples (name, value) that holds user defined properties
+ #: for this test.
+ self.user_properties: List[Tuple[str, object]] = []
+
+ def runtest(self) -> None:
+ raise NotImplementedError("runtest must be implemented by Item subclass")
+
+ def add_report_section(self, when: str, key: str, content: str) -> None:
+ """Add a new report section, similar to what's done internally to add
+ stdout and stderr captured output::
item.add_report_section("call", "stdout", "report section contents")
@@ -579,13 +579,13 @@ class Item(Node):
if content:
self._report_sections.append((when, key, content))
- def reportinfo(self) -> Tuple[Union[py.path.local, str], Optional[int], str]:
+ def reportinfo(self) -> Tuple[Union[py.path.local, str], Optional[int], str]:
return self.fspath, None, ""
- @cached_property
- def location(self) -> Tuple[str, Optional[int], str]:
- location = self.reportinfo()
- fspath = absolutepath(str(location[0]))
- relfspath = self.session._node_location_to_relpath(fspath)
- assert type(location[2]) is str
- return (relfspath, location[1], location[2])
+ @cached_property
+ def location(self) -> Tuple[str, Optional[int], str]:
+ location = self.reportinfo()
+ fspath = absolutepath(str(location[0]))
+ relfspath = self.session._node_location_to_relpath(fspath)
+ assert type(location[2]) is str
+ return (relfspath, location[1], location[2])