Add denotation, users now can use annotation to denote a test

This commit is contained in:
Songpeng Liu 2023-10-27 13:58:22 +11:00
parent c1728948ac
commit 64151d44d5
9 changed files with 95 additions and 4 deletions

View File

@ -354,6 +354,7 @@ Simon Gomizelj
Simon Holesch Simon Holesch
Simon Kerr Simon Kerr
Skylar Downes Skylar Downes
Songpeng Liu
Srinivas Reddy Thatiparthy Srinivas Reddy Thatiparthy
Stefaan Lippens Stefaan Lippens
Stefan Farmbauer Stefan Farmbauer

View File

@ -0,0 +1,4 @@
Add denotation, users now can use annotation to denote a test:
@pytest.mark.test
def hello():
assert 5 == 5

View File

@ -69,6 +69,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader)
try: try:
self.fnpats = config.getini("python_files") self.fnpats = config.getini("python_files")
except ValueError: except ValueError:
print("debug in 75")
self.fnpats = ["test_*.py", "*_test.py"] self.fnpats = ["test_*.py", "*_test.py"]
self.session: Optional[Session] = None self.session: Optional[Session] = None
self._rewritten_names: Dict[str, Path] = {} self._rewritten_names: Dict[str, Path] = {}

0
src/_pytest/cacheprovider.py Executable file → Normal file
View File

View File

@ -661,9 +661,8 @@ class Session(nodes.FSCollector):
self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = [] self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
self._initial_parts: List[Tuple[Path, List[str]]] = [] self._initial_parts: List[Tuple[Path, List[str]]] = []
self.items: List[nodes.Item] = [] self.items: List[nodes.Item] = []
#import pdb; pdb.set_trace()
hook = self.config.hook hook = self.config.hook
items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
try: try:
initialpaths: List[Path] = [] initialpaths: List[Path] = []
@ -705,6 +704,12 @@ class Session(nodes.FSCollector):
hook.pytest_collection_finish(session=self) hook.pytest_collection_finish(session=self)
self.testscollected = len(items) self.testscollected = len(items)
# print("[lizhicheng]")
# print(len(items))
# print(type(items))
# print(items)
# # import pdb;pdb.set_trace()
return items return items
def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]: def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:

View File

@ -625,3 +625,70 @@ class NodeKeywords(MutableMapping[str, Any]):
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<NodeKeywords for node {self.node}>" return f"<NodeKeywords for node {self.node}>"
@final
@dataclasses.dataclass(frozen=True)
class Test:
"""A pytest test."""
#: Name of the test.
name: str
#: Positional arguments of the mark decorator.
args: Tuple[Any, ...]
#: Keyword arguments of the mark decorator.
kwargs: Mapping[str, Any]
_param_ids_from: Optional["Test"] = dataclasses.field(default=None, repr=False)
#: Resolved/generated ids with parametrize Marks.
_param_ids_generated: Optional[Sequence[str]] = dataclasses.field(
default=None, repr=False
)
def __init__(
self,
name: str,
args: Tuple[Any, ...],
kwargs: Mapping[str, Any],
param_ids_from: Optional["Mark"] = None,
param_ids_generated: Optional[Sequence[str]] = None,
*,
_ispytest: bool = False,
) -> None:
""":meta private:"""
check_ispytest(_ispytest)
# Weirdness to bypass frozen=True.
object.__setattr__(self, "name", name)
object.__setattr__(self, "args", args)
object.__setattr__(self, "kwargs", kwargs)
object.__setattr__(self, "_param_ids_from", param_ids_from)
object.__setattr__(self, "_param_ids_generated", param_ids_generated)
def _has_param_ids(self) -> bool:
return "ids" in self.kwargs or len(self.args) >= 4
def combined_with(self, other: "Test") -> "Test":
"""Return a new Test which is a combination of this
Test and another Test.
Combines by appending args and merging kwargs.
"""
assert self.name == other.name
# Remember source of ids with parametrize Marks.
param_ids_from: Optional[Mark] = None
if self.name == "parametrize":
if other._has_param_ids():
param_ids_from = other
elif self._has_param_ids():
param_ids_from = self
return Test(
self.name,
self.args + other.args,
dict(self.kwargs, **other.kwargs),
param_ids_from=param_ids_from,
_ispytest=True,
)

View File

@ -1034,6 +1034,7 @@ class Pytester:
return result return result
def runitem(self, source: str) -> Any: def runitem(self, source: str) -> Any:
print(str)
"""Run the "test_func" Item. """Run the "test_func" Item.
The calling test instance (class containing the test method) must The calling test instance (class containing the test method) must

View File

@ -110,7 +110,7 @@ def pytest_addoption(parser: Parser) -> None:
"python_files", "python_files",
type="args", type="args",
# NOTE: default is also used in AssertionRewritingHook. # NOTE: default is also used in AssertionRewritingHook.
default=["test_*.py", "*_test.py"], default=["test_*.py", "*_test.py", "myselftest_*.py"],
help="Glob-style file patterns for Python test module discovery", help="Glob-style file patterns for Python test module discovery",
) )
parser.addini( parser.addini(
@ -122,7 +122,7 @@ def pytest_addoption(parser: Parser) -> None:
parser.addini( parser.addini(
"python_functions", "python_functions",
type="args", type="args",
default=["test"], default=["test", "my", "*"],
help="Prefixes or glob names for Python test function and method discovery", help="Prefixes or glob names for Python test function and method discovery",
) )
parser.addini( parser.addini(

View File

@ -0,0 +1,12 @@
# content of test_sample.py
import pytest
@pytest.mark.test
def mul():
assert 24 == (4 * 6)
def my_test():
print("test_answer")
assert 5 == 5