Skip to content

Commit 356cbba

Browse files
WIP: experiment with allow_escape for getlocation
1 parent 6cb425a commit 356cbba

File tree

3 files changed

+30
-18
lines changed

3 files changed

+30
-18
lines changed

src/_pytest/compat.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,31 @@ class CodeLocation(NamedTuple):
8282
lineno: int
8383

8484

85+
# TODO: integrate after pytest 3.6.0 has been dropped
8586
def CodeLocation__str__(self: CodeLocation) -> str:
86-
"""Python 3.6 hack for NamedTuple __str__"""
87+
"""Python 3.6.0 hack for NamedTuple __str__"""
8788
return f"{self.path}:{self.lineno}"
8889

8990

9091
setattr(CodeLocation, "__str__", CodeLocation__str__)
9192

9293

93-
def getlocation(function, curdir: Optional[Path]) -> CodeLocation:
94+
def getlocation(
95+
function, *, relative_to: Optional[Path], allow_escape: bool
96+
) -> CodeLocation:
9497
function = get_real_func(function)
9598
fn = Path(inspect.getfile(function))
9699
lineno = function.__code__.co_firstlineno
97100

98101
# TODO: this cycle indicates a larger issue
99102
from .pathlib import bestrelpath
100103

101-
if curdir is not None:
104+
if relative_to is not None:
102105
try:
103-
relfn = Path(bestrelpath(curdir, fn))
106+
if allow_escape:
107+
relfn = Path(bestrelpath(relative_to, fn))
108+
else:
109+
relfn = relative_to.relative_to(relative_to)
104110
except ValueError:
105111
pass
106112
else:

src/_pytest/fixtures.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,11 @@ def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None:
660660
"\n\nRequested here:\n{}:{}".format(
661661
funcitem.nodeid,
662662
fixturedef.argname,
663-
getlocation(fixturedef.func, funcitem.config.rootpath),
663+
getlocation(
664+
fixturedef.func,
665+
relative_to=funcitem.config.rootpath,
666+
allow_escape=True,
667+
),
664668
source_path_str,
665669
source_lineno,
666670
)
@@ -1202,7 +1206,7 @@ def __call__(self, function: _FixtureFunction) -> _FixtureFunction:
12021206

12031207
name = self.name or function.__name__
12041208
if name == "request":
1205-
location = getlocation(function, None)
1209+
location = getlocation(function, relative_to=None, allow_escape=True)
12061210
fail(
12071211
"'request' is a reserved word for fixtures, use another name:\n {}".format(
12081212
location

src/_pytest/python.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import inspect
55
import itertools
66
import os
7-
import pathlib
87
import sys
98
import types
109
import warnings
@@ -1408,19 +1407,18 @@ def _show_fixtures_per_test(config: Config, session: Session) -> None:
14081407
import _pytest.config
14091408

14101409
session.perform_collect()
1411-
curdir = pathlib.Path.cwd()
1410+
curdir = Path.cwd()
14121411
tw = _pytest.config.create_terminal_writer(config)
14131412
verbose = config.getvalue("verbose")
14141413

1415-
def get_best_relpath(func):
1416-
return getlocation(func, curdir)
1417-
14181414
def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:
14191415
argname = fixture_def.argname
14201416
if verbose <= 0 and argname.startswith("_"):
14211417
return
14221418
if verbose > 0:
1423-
bestrel = get_best_relpath(fixture_def.func)
1419+
bestrel = getlocation(
1420+
fixture_def.func, relative_to=curdir, allow_escape=True
1421+
)
14241422
funcargspec = f"{argname} -- {bestrel}"
14251423
else:
14261424
funcargspec = argname
@@ -1434,13 +1432,17 @@ def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:
14341432
def write_item(item: nodes.Item) -> None:
14351433
# Not all items have _fixtureinfo attribute.
14361434
info: Optional[FuncFixtureInfo] = getattr(item, "_fixtureinfo", None)
1435+
function: Optional[Callable[..., Any]] = getattr(item, "function", None)
14371436
if info is None or not info.name2fixturedefs:
14381437
# This test item does not use any fixtures.
14391438
return
1439+
if function is None:
1440+
return
14401441
tw.line()
14411442
tw.sep("-", f"fixtures used by {item.name}")
1442-
# TODO: Fix this type ignore.
1443-
tw.sep("-", "({})".format(get_best_relpath(item.function))) # type: ignore[attr-defined]
1443+
1444+
loc = getlocation(function, relative_to=curdir, allow_escape=True)
1445+
tw.sep("-", f"({loc})")
14441446
# dict key not used in loop but needed for sorting.
14451447
for _, fixturedefs in sorted(info.name2fixturedefs.items()):
14461448
assert fixturedefs is not None
@@ -1477,7 +1479,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
14771479
if not fixturedefs:
14781480
continue
14791481
for fixturedef in fixturedefs:
1480-
loc = getlocation(fixturedef.func, curdir)
1482+
loc = getlocation(fixturedef.func, relative_to=curdir, allow_escape=True)
14811483
if (fixturedef.argname, loc) in seen:
14821484
continue
14831485
seen.add((fixturedef.argname, loc))
@@ -1503,11 +1505,11 @@ def _showfixtures_main(config: Config, session: Session) -> None:
15031505
continue
15041506
tw.write(argname, green=True)
15051507
if fixturedef.scope != "function":
1506-
tw.write(" [%s scope]" % fixturedef.scope, cyan=True)
1508+
tw.write(f" [{fixturedef.scope} scope]", cyan=True)
15071509
if verbose > 0:
1508-
tw.write(" -- %s" % str(bestrel), yellow=True)
1510+
tw.write(f" -- {bestrel}", yellow=True)
15091511
tw.write("\n")
1510-
loc = getlocation(fixturedef.func, curdir)
1512+
loc = getlocation(fixturedef.func, relative_to=curdir, allow_escape=True)
15111513
doc = inspect.getdoc(fixturedef.func)
15121514
if doc:
15131515
write_docstring(tw, doc)

0 commit comments

Comments
 (0)