Merge 02ad46a5a4
into 81cfb3fc87
This commit is contained in:
commit
c73a1004b2
|
@ -13,6 +13,7 @@ from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
|
from typing import NamedTuple
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
@ -93,18 +94,36 @@ def is_async_function(func: object) -> bool:
|
||||||
return iscoroutinefunction(func) or inspect.isasyncgenfunction(func)
|
return iscoroutinefunction(func) or inspect.isasyncgenfunction(func)
|
||||||
|
|
||||||
|
|
||||||
def getlocation(function, curdir: str | None = None) -> str:
|
class CodeLocation(NamedTuple):
|
||||||
|
path: Path
|
||||||
|
lineno: int
|
||||||
|
|
||||||
|
def __str__(self: CodeLocation) -> str:
|
||||||
|
"""Python 3.6.0 hack for NamedTuple __str__"""
|
||||||
|
return f"{self.path}:{self.lineno}"
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
if curdir is not None:
|
|
||||||
|
# TODO: this cycle indicates a larger issue
|
||||||
|
from .pathlib import bestrelpath
|
||||||
|
|
||||||
|
if relative_to is not None:
|
||||||
try:
|
try:
|
||||||
relfn = fn.relative_to(curdir)
|
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:
|
||||||
return "%s:%d" % (relfn, lineno + 1)
|
return CodeLocation(relfn, lineno + 1)
|
||||||
return "%s:%d" % (fn, lineno + 1)
|
return CodeLocation(fn, lineno + 1)
|
||||||
|
|
||||||
|
|
||||||
def num_mock_patch_args(function) -> int:
|
def num_mock_patch_args(function) -> int:
|
||||||
|
|
|
@ -676,7 +676,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,
|
||||||
)
|
)
|
||||||
|
@ -1207,7 +1211,7 @@ class FixtureFunctionMarker:
|
||||||
|
|
||||||
name = self.name or function.__name__
|
name = self.name or function.__name__
|
||||||
if name == "request":
|
if name == "request":
|
||||||
location = getlocation(function)
|
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
|
||||||
|
|
|
@ -40,6 +40,7 @@ from _pytest._io import TerminalWriter
|
||||||
from _pytest._io.saferepr import saferepr
|
from _pytest._io.saferepr import saferepr
|
||||||
from _pytest.compat import ascii_escaped
|
from _pytest.compat import ascii_escaped
|
||||||
from _pytest.compat import assert_never
|
from _pytest.compat import assert_never
|
||||||
|
from _pytest.compat import CodeLocation
|
||||||
from _pytest.compat import final
|
from _pytest.compat import final
|
||||||
from _pytest.compat import get_default_arg_names
|
from _pytest.compat import get_default_arg_names
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
|
@ -1544,7 +1545,7 @@ def _ascii_escaped_by_config(val: Union[str, bytes], config: Optional[Config]) -
|
||||||
|
|
||||||
def _pretty_fixture_path(func) -> str:
|
def _pretty_fixture_path(func) -> str:
|
||||||
cwd = Path.cwd()
|
cwd = Path.cwd()
|
||||||
loc = Path(getlocation(func, str(cwd)))
|
loc = Path(str(getlocation(func, relative_to=cwd, allow_escape=False)))
|
||||||
prefix = Path("...", "_pytest")
|
prefix = Path("...", "_pytest")
|
||||||
try:
|
try:
|
||||||
return str(prefix / loc.relative_to(_PYTEST_DIR))
|
return str(prefix / loc.relative_to(_PYTEST_DIR))
|
||||||
|
@ -1566,9 +1567,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, relative_to=curdir, allow_escape=False)
|
||||||
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
|
||||||
|
@ -1589,9 +1589,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.
|
||||||
|
@ -1625,14 +1628,14 @@ def _showfixtures_main(config: Config, session: Session) -> None:
|
||||||
fm = session._fixturemanager
|
fm = session._fixturemanager
|
||||||
|
|
||||||
available = []
|
available = []
|
||||||
seen: Set[Tuple[str, str]] = set()
|
seen: Set[Tuple[str, CodeLocation]] = set()
|
||||||
|
|
||||||
for argname, fixturedefs in fm._arg2fixturedefs.items():
|
for argname, fixturedefs in fm._arg2fixturedefs.items():
|
||||||
assert fixturedefs is not None
|
assert fixturedefs is not None
|
||||||
if not fixturedefs:
|
if not fixturedefs:
|
||||||
continue
|
continue
|
||||||
for fixturedef in fixturedefs:
|
for fixturedef in fixturedefs:
|
||||||
loc = getlocation(fixturedef.func, str(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))
|
||||||
|
@ -1658,7 +1661,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)
|
||||||
|
|
Loading…
Reference in New Issue