Skip to content

Commit c9267af

Browse files
authored
Merge pull request #9166 from bluetech/optimize-imply-path
nodes: micro-optimize _imply_path
2 parents 14b79a6 + 076ac90 commit c9267af

File tree

3 files changed

+34
-11
lines changed

3 files changed

+34
-11
lines changed

src/_pytest/nodes.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,26 +93,40 @@ def iterparentnodeids(nodeid: str) -> Iterator[str]:
9393
yield nodeid
9494

9595

96+
def _check_path(path: Path, fspath: LEGACY_PATH) -> None:
97+
if Path(fspath) != path:
98+
raise ValueError(
99+
f"Path({fspath!r}) != {path!r}\n"
100+
"if both path and fspath are given they need to be equal"
101+
)
102+
103+
96104
def _imply_path(
97105
path: Optional[Path], fspath: Optional[LEGACY_PATH]
98106
) -> Tuple[Path, LEGACY_PATH]:
99107
if path is not None:
100108
if fspath is not None:
101-
if Path(fspath) != path:
102-
raise ValueError(
103-
f"Path({fspath!r}) != {path!r}\n"
104-
"if both path and fspath are given they need to be equal"
105-
)
106-
assert Path(fspath) == path, f"{fspath} != {path}"
109+
_check_path(path, fspath)
107110
else:
108111
fspath = legacy_path(path)
109112
return path, fspath
110-
111113
else:
112114
assert fspath is not None
113115
return Path(fspath), fspath
114116

115117

118+
# Optimization: use _imply_path_only over _imply_path when only need Path.
119+
# This is to avoid `legacy_path(path)` which is surprisingly heavy.
120+
def _imply_path_only(path: Optional[Path], fspath: Optional[LEGACY_PATH]) -> Path:
121+
if path is not None:
122+
if fspath is not None:
123+
_check_path(path, fspath)
124+
return path
125+
else:
126+
assert fspath is not None
127+
return Path(fspath)
128+
129+
116130
_NodeType = TypeVar("_NodeType", bound="Node")
117131

118132

@@ -196,7 +210,9 @@ def __init__(
196210
self.session = parent.session
197211

198212
#: Filesystem path where this node was collected from (can be None).
199-
self.path = _imply_path(path or getattr(parent, "path", None), fspath=fspath)[0]
213+
self.path = _imply_path_only(
214+
path or getattr(parent, "path", None), fspath=fspath
215+
)
200216

201217
# The explicit annotation is to avoid publicly exposing NodeKeywords.
202218
#: Keywords/markers collected from all scopes.
@@ -573,7 +589,7 @@ def __init__(
573589
assert path is None
574590
path = path_or_parent
575591

576-
path, fspath = _imply_path(path, fspath=fspath)
592+
path = _imply_path_only(path, fspath=fspath)
577593
if name is None:
578594
name = path.name
579595
if parent is not None and parent.path != path:

src/_pytest/python.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,6 @@ def __init__(
639639
) -> None:
640640
# NOTE: Could be just the following, but kept as-is for compat.
641641
# nodes.FSCollector.__init__(self, fspath, parent=parent)
642-
path, fspath = nodes._imply_path(path, fspath=fspath)
643642
session = parent.session
644643
nodes.FSCollector.__init__(
645644
self,
@@ -650,7 +649,7 @@ def __init__(
650649
session=session,
651650
nodeid=nodeid,
652651
)
653-
self.name = path.parent.name
652+
self.name = self.path.parent.name
654653

655654
def setup(self) -> None:
656655
# Not using fixtures to call setup_module here because autouse fixtures

testing/deprecated_test.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import re
22
import sys
33
import warnings
4+
from pathlib import Path
45
from unittest import mock
56

67
import pytest
@@ -179,6 +180,13 @@ def test_hookproxy_warnings_for_fspath(tmp_path, hooktype, request):
179180

180181
hooks.pytest_ignore_collect(config=request.config, fspath=tmp_path)
181182

183+
# Passing entirely *different* paths is an outright error.
184+
with pytest.raises(ValueError, match=r"path.*fspath.*need to be equal"):
185+
with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r:
186+
hooks.pytest_ignore_collect(
187+
config=request.config, path=path, fspath=Path("/bla/bla")
188+
)
189+
182190

183191
def test_warns_none_is_deprecated():
184192
with pytest.warns(

0 commit comments

Comments
 (0)