diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index 446f580ee..143ec190c 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -505,7 +505,9 @@ def pytest_runtest_logstart( See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. :param nodeid: Full node ID of the item. - :param location: A tuple of ``(filename, lineno, testname)``. + :param location: A tuple of ``(filename, lineno, testname)`` + where ``filename`` is a file path relative to ``config.rootpath`` + and ``lineno`` is 0-based. """ @@ -517,7 +519,9 @@ def pytest_runtest_logfinish( See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. :param nodeid: Full node ID of the item. - :param location: A tuple of ``(filename, lineno, testname)``. + :param location: A tuple of ``(filename, lineno, testname)`` + where ``filename`` is a file path relative to ``config.rootpath`` + and ``lineno`` is 0-based. """ diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index cfb9b5a36..c74740dbc 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -511,7 +511,7 @@ def get_fslocation_from_item(node: "Node") -> Tuple[Union[str, Path], Optional[i * "obj": a Python object that the node wraps. * "fspath": just a path - :rtype: A tuple of (str|Path, int) with filename and line number. + :rtype: A tuple of (str|Path, int) with filename and 0-based line number. """ # See Item.location. location: Optional[Tuple[str, Optional[int], str]] = getattr(node, "location", None) @@ -755,7 +755,7 @@ class Item(Node): Returns a tuple with three elements: - The path of the test (default ``self.path``) - - The line number of the test (default ``None``) + - The 0-based line number of the test (default ``None``) - A name of the test to be shown (default ``""``) .. seealso:: :ref:`non-python tests` @@ -764,6 +764,11 @@ class Item(Node): @cached_property def location(self) -> Tuple[str, Optional[int], str]: + """ + Returns a tuple of ``(relfspath, lineno, testname)`` for this item + where ``relfspath`` is file path relative to ``config.rootpath`` + and lineno is a 0-based line number. + """ location = self.reportinfo() path = absolutepath(os.fspath(location[0])) relfspath = self.session._node_location_to_relpath(path) diff --git a/src/_pytest/reports.py b/src/_pytest/reports.py index a8fa61787..2e36514ea 100644 --- a/src/_pytest/reports.py +++ b/src/_pytest/reports.py @@ -273,6 +273,8 @@ class TestReport(BaseReport): #: A (filesystempath, lineno, domaininfo) tuple indicating the #: actual location of a test item - it might be different from the #: collected one e.g. if a method is inherited from a different module. + #: The filesystempath may be relative to ``config.rootdir``. + #: The line number is 0-based. self.location: Tuple[str, Optional[int], str] = location #: A name -> value dictionary containing all keywords and @@ -417,7 +419,9 @@ class CollectReport(BaseReport): self.__dict__.update(extra) @property - def location(self): + def location( # type:ignore[override] + self, + ) -> Optional[Tuple[str, Optional[int], str]]: return (self.fspath, None, self.fspath) def __repr__(self) -> str: diff --git a/testing/test_runner.py b/testing/test_runner.py index c6d5b8aaf..de3e18184 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -473,6 +473,7 @@ class TestSessionReports: assert not rep.skipped assert rep.passed locinfo = rep.location + assert locinfo is not None assert locinfo[0] == col.path.name assert not locinfo[1] assert locinfo[2] == col.path.name