Merge pull request #9184 from bluetech/reportinfo-pathlike
[7.0] Change `Node.reportinfo()` return value from `py.path` to `str|os.PathLike[str]`
This commit is contained in:
commit
da3b3012b1
|
@ -0,0 +1,8 @@
|
||||||
|
The :ref:`Node.reportinfo() <non-python tests>` function first return value type has been expanded from `py.path.local | str` to `os.PathLike[str] | str`.
|
||||||
|
|
||||||
|
Most plugins which refer to `reportinfo()` only define it as part of a custom :class:`pytest.Item` implementation.
|
||||||
|
Since `py.path.local` is a `os.PathLike[str]`, these plugins are unaffacted.
|
||||||
|
|
||||||
|
Plugins and users which call `reportinfo()`, use the first return value and interact with it as a `py.path.local`, would need to adjust by calling `py.path.local(fspath)`.
|
||||||
|
Although preferably, avoid the legacy `py.path.local` and use `pathlib.Path`, or use `item.location` or `item.path`, instead.
|
||||||
|
Note: pytest was not able to provide a deprecation period for this change.
|
|
@ -40,7 +40,7 @@ class YamlItem(pytest.Item):
|
||||||
)
|
)
|
||||||
|
|
||||||
def reportinfo(self):
|
def reportinfo(self):
|
||||||
return self.fspath, 0, f"usecase: {self.name}"
|
return self.path, 0, f"usecase: {self.name}"
|
||||||
|
|
||||||
|
|
||||||
class YamlException(Exception):
|
class YamlException(Exception):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Discover and run doctests in modules and test files."""
|
"""Discover and run doctests in modules and test files."""
|
||||||
import bdb
|
import bdb
|
||||||
import inspect
|
import inspect
|
||||||
|
import os
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -28,7 +29,6 @@ from _pytest._code.code import ExceptionInfo
|
||||||
from _pytest._code.code import ReprFileLocation
|
from _pytest._code.code import ReprFileLocation
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest.compat import legacy_path
|
|
||||||
from _pytest.compat import safe_getattr
|
from _pytest.compat import safe_getattr
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
|
@ -371,9 +371,9 @@ class DoctestItem(pytest.Item):
|
||||||
reprlocation_lines.append((reprlocation, lines))
|
reprlocation_lines.append((reprlocation, lines))
|
||||||
return ReprFailDoctest(reprlocation_lines)
|
return ReprFailDoctest(reprlocation_lines)
|
||||||
|
|
||||||
def reportinfo(self):
|
def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
|
||||||
assert self.dtest is not None
|
assert self.dtest is not None
|
||||||
return legacy_path(self.path), self.dtest.lineno, "[doctest] %s" % self.name
|
return self.path, self.dtest.lineno, "[doctest] %s" % self.name
|
||||||
|
|
||||||
|
|
||||||
def _get_flag_lookup() -> Dict[str, int]:
|
def _get_flag_lookup() -> Dict[str, int]:
|
||||||
|
|
|
@ -718,15 +718,13 @@ class Item(Node):
|
||||||
if content:
|
if content:
|
||||||
self._report_sections.append((when, key, content))
|
self._report_sections.append((when, key, content))
|
||||||
|
|
||||||
def reportinfo(self) -> Tuple[Union[LEGACY_PATH, str], Optional[int], str]:
|
def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
|
||||||
|
return self.path, None, ""
|
||||||
# TODO: enable Path objects in reportinfo
|
|
||||||
return legacy_path(self.path), None, ""
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def location(self) -> Tuple[str, Optional[int], str]:
|
def location(self) -> Tuple[str, Optional[int], str]:
|
||||||
location = self.reportinfo()
|
location = self.reportinfo()
|
||||||
fspath = absolutepath(str(location[0]))
|
path = absolutepath(os.fspath(location[0]))
|
||||||
relfspath = self.session._node_location_to_relpath(fspath)
|
relfspath = self.session._node_location_to_relpath(path)
|
||||||
assert type(location[2]) is str
|
assert type(location[2]) is str
|
||||||
return (relfspath, location[1], location[2])
|
return (relfspath, location[1], location[2])
|
||||||
|
|
|
@ -48,7 +48,6 @@ from _pytest.compat import getlocation
|
||||||
from _pytest.compat import is_async_function
|
from _pytest.compat import is_async_function
|
||||||
from _pytest.compat import is_generator
|
from _pytest.compat import is_generator
|
||||||
from _pytest.compat import LEGACY_PATH
|
from _pytest.compat import LEGACY_PATH
|
||||||
from _pytest.compat import legacy_path
|
|
||||||
from _pytest.compat import NOTSET
|
from _pytest.compat import NOTSET
|
||||||
from _pytest.compat import safe_getattr
|
from _pytest.compat import safe_getattr
|
||||||
from _pytest.compat import safe_isclass
|
from _pytest.compat import safe_isclass
|
||||||
|
@ -321,7 +320,7 @@ class PyobjMixin(nodes.Node):
|
||||||
parts.reverse()
|
parts.reverse()
|
||||||
return ".".join(parts)
|
return ".".join(parts)
|
||||||
|
|
||||||
def reportinfo(self) -> Tuple[Union[LEGACY_PATH, str], int, str]:
|
def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
|
||||||
# XXX caching?
|
# XXX caching?
|
||||||
obj = self.obj
|
obj = self.obj
|
||||||
compat_co_firstlineno = getattr(obj, "compat_co_firstlineno", None)
|
compat_co_firstlineno = getattr(obj, "compat_co_firstlineno", None)
|
||||||
|
@ -330,17 +329,13 @@ class PyobjMixin(nodes.Node):
|
||||||
file_path = sys.modules[obj.__module__].__file__
|
file_path = sys.modules[obj.__module__].__file__
|
||||||
if file_path.endswith(".pyc"):
|
if file_path.endswith(".pyc"):
|
||||||
file_path = file_path[:-1]
|
file_path = file_path[:-1]
|
||||||
fspath: Union[LEGACY_PATH, str] = file_path
|
path: Union["os.PathLike[str]", str] = file_path
|
||||||
lineno = compat_co_firstlineno
|
lineno = compat_co_firstlineno
|
||||||
else:
|
else:
|
||||||
path, lineno = getfslineno(obj)
|
path, lineno = getfslineno(obj)
|
||||||
if isinstance(path, Path):
|
|
||||||
fspath = legacy_path(path)
|
|
||||||
else:
|
|
||||||
fspath = path
|
|
||||||
modpath = self.getmodpath()
|
modpath = self.getmodpath()
|
||||||
assert isinstance(lineno, int)
|
assert isinstance(lineno, int)
|
||||||
return fspath, lineno, modpath
|
return path, lineno, modpath
|
||||||
|
|
||||||
|
|
||||||
# As an optimization, these builtin attribute names are pre-ignored when
|
# As an optimization, these builtin attribute names are pre-ignored when
|
||||||
|
|
|
@ -324,9 +324,9 @@ class TestReport(BaseReport):
|
||||||
outcome = "skipped"
|
outcome = "skipped"
|
||||||
r = excinfo._getreprcrash()
|
r = excinfo._getreprcrash()
|
||||||
if excinfo.value._use_item_location:
|
if excinfo.value._use_item_location:
|
||||||
filename, line = item.reportinfo()[:2]
|
path, line = item.reportinfo()[:2]
|
||||||
assert line is not None
|
assert line is not None
|
||||||
longrepr = str(filename), line + 1, r.message
|
longrepr = os.fspath(path), line + 1, r.message
|
||||||
else:
|
else:
|
||||||
longrepr = (str(r.path), r.lineno, r.message)
|
longrepr = (str(r.path), r.lineno, r.message)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1154,8 +1154,8 @@ class TestReportInfo:
|
||||||
|
|
||||||
def test_func_reportinfo(self, pytester: Pytester) -> None:
|
def test_func_reportinfo(self, pytester: Pytester) -> None:
|
||||||
item = pytester.getitem("def test_func(): pass")
|
item = pytester.getitem("def test_func(): pass")
|
||||||
fspath, lineno, modpath = item.reportinfo()
|
path, lineno, modpath = item.reportinfo()
|
||||||
assert str(fspath) == str(item.path)
|
assert os.fspath(path) == str(item.path)
|
||||||
assert lineno == 0
|
assert lineno == 0
|
||||||
assert modpath == "test_func"
|
assert modpath == "test_func"
|
||||||
|
|
||||||
|
@ -1169,8 +1169,8 @@ class TestReportInfo:
|
||||||
)
|
)
|
||||||
classcol = pytester.collect_by_name(modcol, "TestClass")
|
classcol = pytester.collect_by_name(modcol, "TestClass")
|
||||||
assert isinstance(classcol, Class)
|
assert isinstance(classcol, Class)
|
||||||
fspath, lineno, msg = classcol.reportinfo()
|
path, lineno, msg = classcol.reportinfo()
|
||||||
assert str(fspath) == str(modcol.path)
|
assert os.fspath(path) == str(modcol.path)
|
||||||
assert lineno == 1
|
assert lineno == 1
|
||||||
assert msg == "TestClass"
|
assert msg == "TestClass"
|
||||||
|
|
||||||
|
@ -1194,7 +1194,7 @@ class TestReportInfo:
|
||||||
assert isinstance(classcol, Class)
|
assert isinstance(classcol, Class)
|
||||||
instance = list(classcol.collect())[0]
|
instance = list(classcol.collect())[0]
|
||||||
assert isinstance(instance, Instance)
|
assert isinstance(instance, Instance)
|
||||||
fspath, lineno, msg = instance.reportinfo()
|
path, lineno, msg = instance.reportinfo()
|
||||||
|
|
||||||
|
|
||||||
def test_customized_python_discovery(pytester: Pytester) -> None:
|
def test_customized_python_discovery(pytester: Pytester) -> None:
|
||||||
|
|
|
@ -19,7 +19,7 @@ class TestOEJSKITSpecials:
|
||||||
return MyCollector.from_parent(collector, name=name)
|
return MyCollector.from_parent(collector, name=name)
|
||||||
class MyCollector(pytest.Collector):
|
class MyCollector(pytest.Collector):
|
||||||
def reportinfo(self):
|
def reportinfo(self):
|
||||||
return self.fspath, 3, "xyz"
|
return self.path, 3, "xyz"
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
modcol = pytester.getmodulecol(
|
modcol = pytester.getmodulecol(
|
||||||
|
@ -52,7 +52,7 @@ class TestOEJSKITSpecials:
|
||||||
return MyCollector.from_parent(collector, name=name)
|
return MyCollector.from_parent(collector, name=name)
|
||||||
class MyCollector(pytest.Collector):
|
class MyCollector(pytest.Collector):
|
||||||
def reportinfo(self):
|
def reportinfo(self):
|
||||||
return self.fspath, 3, "xyz"
|
return self.path, 3, "xyz"
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
modcol = pytester.getmodulecol(
|
modcol = pytester.getmodulecol(
|
||||||
|
|
Loading…
Reference in New Issue