Merge pull request #9166 from bluetech/optimize-imply-path

nodes: micro-optimize _imply_path
This commit is contained in:
Ran Benita 2021-10-06 10:50:10 +03:00 committed by GitHub
commit c9267af3bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 11 deletions

View File

@ -93,26 +93,40 @@ def iterparentnodeids(nodeid: str) -> Iterator[str]:
yield nodeid
def _check_path(path: Path, fspath: LEGACY_PATH) -> None:
if Path(fspath) != path:
raise ValueError(
f"Path({fspath!r}) != {path!r}\n"
"if both path and fspath are given they need to be equal"
)
def _imply_path(
path: Optional[Path], fspath: Optional[LEGACY_PATH]
) -> Tuple[Path, LEGACY_PATH]:
if path is not None:
if fspath is not None:
if Path(fspath) != path:
raise ValueError(
f"Path({fspath!r}) != {path!r}\n"
"if both path and fspath are given they need to be equal"
)
assert Path(fspath) == path, f"{fspath} != {path}"
_check_path(path, fspath)
else:
fspath = legacy_path(path)
return path, fspath
else:
assert fspath is not None
return Path(fspath), fspath
# Optimization: use _imply_path_only over _imply_path when only need Path.
# This is to avoid `legacy_path(path)` which is surprisingly heavy.
def _imply_path_only(path: Optional[Path], fspath: Optional[LEGACY_PATH]) -> Path:
if path is not None:
if fspath is not None:
_check_path(path, fspath)
return path
else:
assert fspath is not None
return Path(fspath)
_NodeType = TypeVar("_NodeType", bound="Node")
@ -196,7 +210,9 @@ class Node(metaclass=NodeMeta):
self.session = parent.session
#: Filesystem path where this node was collected from (can be None).
self.path = _imply_path(path or getattr(parent, "path", None), fspath=fspath)[0]
self.path = _imply_path_only(
path or getattr(parent, "path", None), fspath=fspath
)
# The explicit annotation is to avoid publicly exposing NodeKeywords.
#: Keywords/markers collected from all scopes.
@ -573,7 +589,7 @@ class FSCollector(Collector):
assert path is None
path = path_or_parent
path, fspath = _imply_path(path, fspath=fspath)
path = _imply_path_only(path, fspath=fspath)
if name is None:
name = path.name
if parent is not None and parent.path != path:

View File

@ -639,7 +639,6 @@ class Package(Module):
) -> None:
# NOTE: Could be just the following, but kept as-is for compat.
# nodes.FSCollector.__init__(self, fspath, parent=parent)
path, fspath = nodes._imply_path(path, fspath=fspath)
session = parent.session
nodes.FSCollector.__init__(
self,
@ -650,7 +649,7 @@ class Package(Module):
session=session,
nodeid=nodeid,
)
self.name = path.parent.name
self.name = self.path.parent.name
def setup(self) -> None:
# Not using fixtures to call setup_module here because autouse fixtures

View File

@ -1,6 +1,7 @@
import re
import sys
import warnings
from pathlib import Path
from unittest import mock
import pytest
@ -179,6 +180,13 @@ def test_hookproxy_warnings_for_fspath(tmp_path, hooktype, request):
hooks.pytest_ignore_collect(config=request.config, fspath=tmp_path)
# Passing entirely *different* paths is an outright error.
with pytest.raises(ValueError, match=r"path.*fspath.*need to be equal"):
with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r:
hooks.pytest_ignore_collect(
config=request.config, path=path, fspath=Path("/bla/bla")
)
def test_warns_none_is_deprecated():
with pytest.warns(