WIP: experiment with allow_escape for getlocation

This commit is contained in:
Ronny Pfannschmidt 2020-11-22 20:09:45 +01:00
parent a99885f344
commit dfde2c6c34
3 changed files with 23 additions and 11 deletions

View File

@ -100,15 +100,18 @@ class CodeLocation(NamedTuple):
lineno: int lineno: int
# TODO: integrate after pytest 3.6.0 has been dropped
def CodeLocation__str__(self: CodeLocation) -> str: def CodeLocation__str__(self: CodeLocation) -> str:
"""Python 3.6 hack for NamedTuple __str__""" """Python 3.6.0 hack for NamedTuple __str__"""
return f"{self.path}:{self.lineno}" return f"{self.path}:{self.lineno}"
setattr(CodeLocation, "__str__", CodeLocation__str__) setattr(CodeLocation, "__str__", CodeLocation__str__)
def getlocation(function, curdir: Path | None) -> CodeLocation: def getlocation(
function, *, relative_to: Path | None, allow_escape: bool
) -> CodeLocation:
function = get_real_func(function) function = get_real_func(function)
fn = Path(inspect.getfile(function)) fn = Path(inspect.getfile(function))
lineno = function.__code__.co_firstlineno lineno = function.__code__.co_firstlineno
@ -116,9 +119,12 @@ def getlocation(function, curdir: Path | None) -> CodeLocation:
# TODO: this cycle indicates a larger issue # TODO: this cycle indicates a larger issue
from .pathlib import bestrelpath from .pathlib import bestrelpath
if curdir is not None: if relative_to is not None:
try: try:
relfn = Path(bestrelpath(curdir, fn)) if allow_escape:
relfn = Path(bestrelpath(relative_to, fn))
else:
relfn = relative_to.relative_to(relative_to)
except ValueError: except ValueError:
pass pass
else: else:

View File

@ -660,7 +660,11 @@ class FixtureRequest:
"\n\nRequested here:\n{}:{}".format( "\n\nRequested here:\n{}:{}".format(
funcitem.nodeid, funcitem.nodeid,
fixturedef.argname, fixturedef.argname,
getlocation(fixturedef.func, funcitem.config.rootpath), getlocation(
fixturedef.func,
relative_to=funcitem.config.rootpath,
allow_escape=True,
),
source_path_str, source_path_str,
source_lineno, source_lineno,
) )
@ -1210,7 +1214,7 @@ class FixtureFunctionMarker:
name = self.name or function.__name__ name = self.name or function.__name__
if name == "request": if name == "request":
location = getlocation(function, None) location = getlocation(function, relative_to=None, allow_escape=True)
fail( fail(
"'request' is a reserved word for fixtures, use another name:\n {}".format( "'request' is a reserved word for fixtures, use another name:\n {}".format(
location location

View File

@ -1576,9 +1576,8 @@ def _show_fixtures_per_test(config: Config, session: Session) -> None:
tw = _pytest.config.create_terminal_writer(config) tw = _pytest.config.create_terminal_writer(config)
verbose = config.getvalue("verbose") verbose = config.getvalue("verbose")
def get_best_relpath(func) -> str: def get_best_relpath(func):
loc = getlocation(func, str(curdir)) return getlocation(func, curdir)
return bestrelpath(curdir, Path(loc))
def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None: def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:
argname = fixture_def.argname argname = fixture_def.argname
@ -1599,9 +1598,12 @@ def _show_fixtures_per_test(config: Config, session: Session) -> None:
def write_item(item: nodes.Item) -> None: def write_item(item: nodes.Item) -> None:
# Not all items have _fixtureinfo attribute. # Not all items have _fixtureinfo attribute.
info: Optional[FuncFixtureInfo] = getattr(item, "_fixtureinfo", None) info: Optional[FuncFixtureInfo] = getattr(item, "_fixtureinfo", None)
function: Optional[Callable[..., Any]] = getattr(item, "function", None)
if info is None or not info.name2fixturedefs: if info is None or not info.name2fixturedefs:
# This test item does not use any fixtures. # This test item does not use any fixtures.
return return
if function is None:
return
tw.line() tw.line()
tw.sep("-", f"fixtures used by {item.name}") tw.sep("-", f"fixtures used by {item.name}")
# TODO: Fix this type ignore. # TODO: Fix this type ignore.
@ -1642,7 +1644,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
if not fixturedefs: if not fixturedefs:
continue continue
for fixturedef in fixturedefs: for fixturedef in fixturedefs:
loc = getlocation(fixturedef.func, curdir) loc = getlocation(fixturedef.func, relative_to=curdir, allow_escape=True)
if (fixturedef.argname, loc) in seen: if (fixturedef.argname, loc) in seen:
continue continue
seen.add((fixturedef.argname, loc)) seen.add((fixturedef.argname, loc))
@ -1668,7 +1670,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
continue continue
tw.write(f"{argname}", green=True) tw.write(f"{argname}", green=True)
if fixturedef.scope != "function": if fixturedef.scope != "function":
tw.write(" [%s scope]" % fixturedef.scope, cyan=True) tw.write(f" [{fixturedef.scope} scope]", cyan=True)
tw.write(f" -- {prettypath}", yellow=True) tw.write(f" -- {prettypath}", yellow=True)
tw.write("\n") tw.write("\n")
doc = inspect.getdoc(fixturedef.func) doc = inspect.getdoc(fixturedef.func)